Compare commits

...

26 Commits

Author SHA1 Message Date
wuzihao051119
4677ceb03c drift(mobile): drift auth user sync 2025-07-25 12:28:02 +08:00
shenlong
ad65e9011a chore: bump line length to 120 (#20191) 2025-07-25 02:37:22 +00:00
Zack Pollard
977c9b96ba fix: geodata_places pkey migration failing for certain upgrade paths (#20177) 2025-07-24 22:50:36 +01:00
John Stef
aa2828ab33 fix(mobile): hide video thumbnail when video is ready (#19328) 2025-07-24 22:38:08 +01:00
Daimolean
a36840d7cc fix(web): multi-select in ascending asset order (#19461) 2025-07-24 22:37:44 +01:00
Pablo Lluch
e34f46fa0d fix: send correct includeArchived parameter to API when showing markers in map (#20117)
Co-authored-by: Pablo Lluch <pablo.lluch@gmail.com>
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2025-07-24 22:34:06 +02:00
Alex
6170a3843c chore: remove build flavor Android (#20161) 2025-07-24 14:55:49 -05:00
shenlong
563e2ab503 fix: update trash action i18n keys (#20164)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-24 14:55:35 -05:00
shenlong
79157e1043 fix: fallback auto grouping to day grouping (#20156)
fallback auto grouping to day grouping

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-24 19:28:40 +00:00
shenlong
02688a2a03 fix: override SSL options inside isolates (#20142)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-24 14:26:00 -05:00
Brandon Wees
3b9bfceef0 fix: album deleted toast message (#20121)
* fix: album deleted toast message

* Update mobile/lib/presentation/pages/drift_remote_album.page.dart

Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>

* Fix lint

---------

Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>
2025-07-24 14:09:17 -05:00
github-actions
089085fcdb chore: version v1.136.0 2025-07-24 14:24:38 +00:00
Jason Rasmussen
fc68cf4f32 chore: remove migration (#20129) 2025-07-24 14:11:53 +00:00
Alex
0051a9bba5 fix(web): Revert prevent flashing white background in dark mode on page load/reload (#19934) (#20122)
Revert "fix(web): prevent flashing white background in dark mode on page load/reload (#19934)"

This reverts commit 32f23b8d38.
2025-07-24 09:45:38 +02:00
Daniel Dietzler
f27bdf7523 chore: migrate to UI modal manager (#20116) 2025-07-23 17:27:09 -04:00
Daniel Dietzler
c1c9f30ea4 chore: migrate to immich/ui confirm modal (#20114) 2025-07-23 22:56:56 +02:00
Jason Rasmussen
bc8cb9b671 fix: default route permission (#20113) 2025-07-23 16:56:38 -04:00
Jason Rasmussen
a675922172 fix: unset prewarn param (#20109) 2025-07-23 16:52:59 -04:00
Jason Rasmussen
2bead445bd docs: remove outdated note (#20110) 2025-07-23 16:00:19 -04:00
Daniel Dietzler
0e1c8c2b80 fix: ML recognition distance UI form validation (#20107) 2025-07-23 19:12:06 +02:00
Alex
0174de19dd feat: export database option (#20098) 2025-07-23 14:40:16 +00:00
Alex
1a35a01149 feat: drift manual upload (#20101) 2025-07-23 09:20:52 -05:00
shenlong
08122d6871 fix: show only local assets from albums selected for backup (#20050)
* show only local assets from albums selected for backup

# Conflicts:
#	mobile/lib/infrastructure/repositories/db.repository.drift.dart

* ignore backup selection

* fix: backup album ownerId

* fix: backup album ownerId

* only show local only assets that are selected for backup

* add index on visibility and backup selection

* fix: video not playing in search view

* remove safe area from bottom bar

* refactor stack count with a CTE and local asset with a SELECT

* fix lint

* remove redundant COALESCE

* remove stack count from main timeline query

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-23 09:13:15 -05:00
Jason Rasmussen
92384c28de feat: sync auth user (#20067) 2025-07-23 09:59:33 -04:00
Jason Rasmussen
ab597155fa fix: immich-dev live reload (#20104) 2025-07-23 09:59:21 -04:00
Weblate (bot)
1d9cc4ca5f chore(web): update translations (#20082)
Co-authored-by: Alberto Serluca <alberto.ser11@gmail.com>
Co-authored-by: DevServs <bonov@mail.ru>
Co-authored-by: Florian Ostertag <florian.kuepper@gmail.com>
Co-authored-by: Gilbert <thengilbert@gmail.com>
Co-authored-by: Indrek Haav <indrek.haav@hotmail.com>
Co-authored-by: Jozef Gaal <preklady@mayday.sk>
Co-authored-by: KecskeTech <teonyitas@gmail.com>
Co-authored-by: Kuno Claes <kuno@icodes.dev>
Co-authored-by: MSDNicrosoft <wang3311835119@hotmail.com>
Co-authored-by: Matjaž T <matjaz@moj-svet.si>
Co-authored-by: Mārtiņš Bruņenieks <martinsb@gmail.com>
Co-authored-by: Vegard Fladby <vegard@fladby.org>
Co-authored-by: adri1m64 <adrien.melle@laposte.net>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
2025-07-23 14:38:29 +01:00
673 changed files with 14918 additions and 11286 deletions

View File

@@ -122,17 +122,17 @@ jobs:
IS_MAIN: ${{ github.ref == 'refs/heads/main' }} IS_MAIN: ${{ github.ref == 'refs/heads/main' }}
run: | run: |
if [[ $IS_MAIN == 'true' ]]; then if [[ $IS_MAIN == 'true' ]]; then
flutter build apk --release --flavor production flutter build apk --release
flutter build apk --release --flavor production --split-per-abi --target-platform android-arm,android-arm64,android-x64 flutter build apk --release --split-per-abi --target-platform android-arm,android-arm64,android-x64
else else
flutter build apk --debug --flavor production --split-per-abi --target-platform android-arm64 flutter build apk --debug --split-per-abi --target-platform android-arm64
fi fi
- name: Publish Android Artifact - name: Publish Android Artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: release-apk-signed name: release-apk-signed
path: mobile/build/app/outputs/flutter-apk/**/*.apk path: mobile/build/app/outputs/flutter-apk/*.apk
- name: Save Gradle Cache - name: Save Gradle Cache
id: cache-gradle-save id: cache-gradle-save

View File

@@ -98,7 +98,8 @@ jobs:
run: dart analyze --fatal-infos run: dart analyze --fatal-infos
- name: Run dart format - name: Run dart format
run: dart format lib/ --set-exit-if-changed # Ignore generated files manually until https://github.com/dart-lang/dart_style/issues/864 is resolved
run: dart format --set-exit-if-changed $(find lib -name '*.dart' -not \( -name 'generated_plugin_registrant.dart' -o -name '*.g.dart' -o -name '*.drift.dart' \))
- name: Run dart custom_lint - name: Run dart custom_lint
run: dart run custom_lint run: dart run custom_lint

19
.vscode/launch.json vendored
View File

@@ -18,25 +18,6 @@
"name": "Immich Workers", "name": "Immich Workers",
"remoteRoot": "/usr/src/app", "remoteRoot": "/usr/src/app",
"localRoot": "${workspaceFolder}/server" "localRoot": "${workspaceFolder}/server"
},
{
"name": "Flavor - Production",
"request": "launch",
"type": "dart",
"codeLens": {
"for": [
"run-test",
"run-test-file",
"run-file",
"debug-test",
"debug-test-file",
"debug-file",
],
"title": "${debugType}",
},
"args": [
"--flavor", "production"
],
} }
] ]
} }

6
cli/package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "@immich/cli", "name": "@immich/cli",
"version": "2.2.72", "version": "2.2.73",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@immich/cli", "name": "@immich/cli",
"version": "2.2.72", "version": "2.2.73",
"license": "GNU Affero General Public License version 3", "license": "GNU Affero General Public License version 3",
"dependencies": { "dependencies": {
"chokidar": "^4.0.3", "chokidar": "^4.0.3",
@@ -54,7 +54,7 @@
}, },
"../open-api/typescript-sdk": { "../open-api/typescript-sdk": {
"name": "@immich/sdk", "name": "@immich/sdk",
"version": "1.135.3", "version": "1.136.0",
"dev": true, "dev": true,
"license": "GNU Affero General Public License version 3", "license": "GNU Affero General Public License version 3",
"dependencies": { "dependencies": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "@immich/cli", "name": "@immich/cli",
"version": "2.2.72", "version": "2.2.73",
"description": "Command Line Interface (CLI) for Immich", "description": "Command Line Interface (CLI) for Immich",
"type": "module", "type": "module",
"exports": "./dist/index.js", "exports": "./dist/index.js",

View File

@@ -29,29 +29,26 @@ These environment variables are used by the `docker-compose.yml` file and do **N
## General ## General
| Variable | Description | Default | Containers | Workers | | Variable | Description | Default | Containers | Workers |
| :---------------------------------- | :---------------------------------------------------------------------------------------- | :---------------------------------: | :----------------------- | :----------------- | | :---------------------------------- | :---------------------------------------------------------------------------------------- | :--------------------------: | :----------------------- | :----------------- |
| `TZ` | Timezone | <sup>\*1</sup> | server | microservices | | `TZ` | Timezone | <sup>\*1</sup> | server | microservices |
| `IMMICH_ENV` | Environment (production, development) | `production` | server, machine learning | api, microservices | | `IMMICH_ENV` | Environment (production, development) | `production` | server, machine learning | api, microservices |
| `IMMICH_LOG_LEVEL` | Log level (verbose, debug, log, warn, error) | `log` | server, machine learning | api, microservices | | `IMMICH_LOG_LEVEL` | Log level (verbose, debug, log, warn, error) | `log` | server, machine learning | api, microservices |
| `IMMICH_MEDIA_LOCATION` | Media location inside the container ⚠️**You probably shouldn't set this**<sup>\*2</sup>⚠️ | `/usr/src/app/upload`<sup>\*3</sup> | server | api, microservices | | `IMMICH_MEDIA_LOCATION` | Media location inside the container ⚠️**You probably shouldn't set this**<sup>\*2</sup>⚠️ | `/usr/src/app/upload` | server | api, microservices |
| `IMMICH_CONFIG_FILE` | Path to config file | | server | api, microservices | | `IMMICH_CONFIG_FILE` | Path to config file | | server | api, microservices |
| `NO_COLOR` | Set to `true` to disable color-coded log output | `false` | server, machine learning | | | `NO_COLOR` | Set to `true` to disable color-coded log output | `false` | server, machine learning | |
| `CPU_CORES` | Number of cores available to the Immich server | auto-detected CPU core count | server | | | `CPU_CORES` | Number of cores available to the Immich server | auto-detected CPU core count | server | |
| `IMMICH_API_METRICS_PORT` | Port for the OTEL metrics | `8081` | server | api | | `IMMICH_API_METRICS_PORT` | Port for the OTEL metrics | `8081` | server | api |
| `IMMICH_MICROSERVICES_METRICS_PORT` | Port for the OTEL metrics | `8082` | server | microservices | | `IMMICH_MICROSERVICES_METRICS_PORT` | Port for the OTEL metrics | `8082` | server | microservices |
| `IMMICH_PROCESS_INVALID_IMAGES` | When `true`, generate thumbnails for invalid images | | server | microservices | | `IMMICH_PROCESS_INVALID_IMAGES` | When `true`, generate thumbnails for invalid images | | server | microservices |
| `IMMICH_TRUSTED_PROXIES` | List of comma-separated IPs set as trusted proxies | | server | api | | `IMMICH_TRUSTED_PROXIES` | List of comma-separated IPs set as trusted proxies | | server | api |
| `IMMICH_IGNORE_MOUNT_CHECK_ERRORS` | See [System Integrity](/docs/administration/system-integrity) | | server | api, microservices | | `IMMICH_IGNORE_MOUNT_CHECK_ERRORS` | See [System Integrity](/docs/administration/system-integrity) | | server | api, microservices |
\*1: `TZ` should be set to a `TZ identifier` from [this list][tz-list]. For example, `TZ="Etc/UTC"`. \*1: `TZ` should be set to a `TZ identifier` from [this list][tz-list]. For example, `TZ="Etc/UTC"`.
`TZ` is used by `exiftool` as a fallback in case the timezone cannot be determined from the image metadata. It is also used for logfile timestamps and cron job execution. `TZ` is used by `exiftool` as a fallback in case the timezone cannot be determined from the image metadata. It is also used for logfile timestamps and cron job execution.
\*2: This path is where the Immich code looks for the files, which is internal to the docker container. Setting it to a path on your host will certainly break things, you should use the `UPLOAD_LOCATION` variable instead. \*2: This path is where the Immich code looks for the files, which is internal to the docker container. Setting it to a path on your host will certainly break things, you should use the `UPLOAD_LOCATION` variable instead.
\*3: With the default `WORKDIR` of `/usr/src/app`, this path will resolve to `/usr/src/app/upload`.
It only needs to be set if the Immich deployment method is changing.
## Workers ## Workers
| Variable | Description | Default | Containers | | Variable | Description | Default | Containers |

View File

@@ -1,4 +1,8 @@
[ [
{
"label": "v1.136.0",
"url": "https://v1.136.0.archive.immich.app"
},
{ {
"label": "v1.135.3", "label": "v1.135.3",
"url": "https://v1.135.3.archive.immich.app" "url": "https://v1.135.3.archive.immich.app"

8
e2e/package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "immich-e2e", "name": "immich-e2e",
"version": "1.135.3", "version": "1.136.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "immich-e2e", "name": "immich-e2e",
"version": "1.135.3", "version": "1.136.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/eslintrc": "^3.1.0",
@@ -46,7 +46,7 @@
}, },
"../cli": { "../cli": {
"name": "@immich/cli", "name": "@immich/cli",
"version": "2.2.72", "version": "2.2.73",
"dev": true, "dev": true,
"license": "GNU Affero General Public License version 3", "license": "GNU Affero General Public License version 3",
"dependencies": { "dependencies": {
@@ -95,7 +95,7 @@
}, },
"../open-api/typescript-sdk": { "../open-api/typescript-sdk": {
"name": "@immich/sdk", "name": "@immich/sdk",
"version": "1.135.3", "version": "1.136.0",
"dev": true, "dev": true,
"license": "GNU Affero General Public License version 3", "license": "GNU Affero General Public License version 3",
"dependencies": { "dependencies": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "immich-e2e", "name": "immich-e2e",
"version": "1.135.3", "version": "1.136.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"type": "module", "type": "module",

View File

@@ -573,6 +573,8 @@
"backup_options_page_title": "Nastavení záloh", "backup_options_page_title": "Nastavení záloh",
"backup_setting_subtitle": "Správa nastavení zálohování na pozadí a na popředí", "backup_setting_subtitle": "Správa nastavení zálohování na pozadí a na popředí",
"backward": "Pozpátku", "backward": "Pozpátku",
"beta_sync": "Stav synchronizace beta verze",
"beta_sync_subtitle": "Správa nového systému synchronizace",
"biometric_auth_enabled": "Biometrické ověřování je povoleno", "biometric_auth_enabled": "Biometrické ověřování je povoleno",
"biometric_locked_out": "Jste vyloučeni z biometrického ověřování", "biometric_locked_out": "Jste vyloučeni z biometrického ověřování",
"biometric_no_options": "Biometrické možnosti nejsou k dispozici", "biometric_no_options": "Biometrické možnosti nejsou k dispozici",
@@ -590,7 +592,7 @@
"cache_settings_clear_cache_button": "Vymazat vyrovnávací paměť", "cache_settings_clear_cache_button": "Vymazat vyrovnávací paměť",
"cache_settings_clear_cache_button_title": "Vymaže vyrovnávací paměť aplikace. To výrazně ovlivní výkon aplikace, dokud se vyrovnávací paměť neobnoví.", "cache_settings_clear_cache_button_title": "Vymaže vyrovnávací paměť aplikace. To výrazně ovlivní výkon aplikace, dokud se vyrovnávací paměť neobnoví.",
"cache_settings_duplicated_assets_clear_button": "VYMAZAT", "cache_settings_duplicated_assets_clear_button": "VYMAZAT",
"cache_settings_duplicated_assets_subtitle": "Fotografie a videa, které aplikace zařadila na černou listinu", "cache_settings_duplicated_assets_subtitle": "Fotografie a videa, které aplikace ignoruje",
"cache_settings_duplicated_assets_title": "Duplicitní položky ({count})", "cache_settings_duplicated_assets_title": "Duplicitní položky ({count})",
"cache_settings_statistics_album": "Knihovna náhledů", "cache_settings_statistics_album": "Knihovna náhledů",
"cache_settings_statistics_full": "Kompletní fotografie", "cache_settings_statistics_full": "Kompletní fotografie",
@@ -1051,6 +1053,9 @@
"haptic_feedback_switch": "Povolit dotykovou zpětnou vazbu", "haptic_feedback_switch": "Povolit dotykovou zpětnou vazbu",
"haptic_feedback_title": "Dotyková zpětná vazba", "haptic_feedback_title": "Dotyková zpětná vazba",
"has_quota": "Má kvótu", "has_quota": "Má kvótu",
"hash_asset": "Hash položky",
"hashed_assets": "Hashované položky",
"hashing": "Hashování",
"header_settings_add_header_tip": "Přidat hlavičku", "header_settings_add_header_tip": "Přidat hlavičku",
"header_settings_field_validator_msg": "Hodnota nemůže být prázdná", "header_settings_field_validator_msg": "Hodnota nemůže být prázdná",
"header_settings_header_name_input": "Název hlavičky", "header_settings_header_name_input": "Název hlavičky",
@@ -1083,6 +1088,7 @@
"host": "Hostitel", "host": "Hostitel",
"hour": "Hodina", "hour": "Hodina",
"id": "ID", "id": "ID",
"idle": "Nečinnost",
"ignore_icloud_photos": "Ignorovat fotografie na iCloudu", "ignore_icloud_photos": "Ignorovat fotografie na iCloudu",
"ignore_icloud_photos_description": "Fotografie uložené na iCloudu se nebudou nahrávat na Immich server", "ignore_icloud_photos_description": "Fotografie uložené na iCloudu se nebudou nahrávat na Immich server",
"image": "Obrázek", "image": "Obrázek",
@@ -1165,7 +1171,9 @@
"list": "Seznam", "list": "Seznam",
"loading": "Načítání", "loading": "Načítání",
"loading_search_results_failed": "Načítání výsledků vyhledávání se nezdařilo", "loading_search_results_failed": "Načítání výsledků vyhledávání se nezdařilo",
"local": "Místní",
"local_asset_cast_failed": "Nelze odeslat položku, která není nahraná na serveru", "local_asset_cast_failed": "Nelze odeslat položku, která není nahraná na serveru",
"local_assets": "Místní položky",
"local_network": "Místní síť", "local_network": "Místní síť",
"local_network_sheet_info": "Aplikace se při použití zadané sítě Wi-Fi připojí k serveru prostřednictvím tohoto URL", "local_network_sheet_info": "Aplikace se při použití zadané sítě Wi-Fi připojí k serveru prostřednictvím tohoto URL",
"location_permission": "Oprávnění polohy", "location_permission": "Oprávnění polohy",
@@ -1322,6 +1330,7 @@
"no_results": "Žádné výsledky", "no_results": "Žádné výsledky",
"no_results_description": "Zkuste použít synonymum nebo obecnější klíčové slovo", "no_results_description": "Zkuste použít synonymum nebo obecnější klíčové slovo",
"no_shared_albums_message": "Vytvořte si album a sdílejte fotografie a videa s lidmi ve své síti", "no_shared_albums_message": "Vytvořte si album a sdílejte fotografie a videa s lidmi ve své síti",
"no_uploads_in_progress": "Neprobíhá žádné nahrávání",
"not_in_any_album": "Bez alba", "not_in_any_album": "Bez alba",
"not_selected": "Není vybráno", "not_selected": "Není vybráno",
"note_apply_storage_label_to_previously_uploaded assets": "Upozornění: Chcete-li použít štítek úložiště na dříve nahrané položky, spusťte příkaz", "note_apply_storage_label_to_previously_uploaded assets": "Upozornění: Chcete-li použít štítek úložiště na dříve nahrané položky, spusťte příkaz",
@@ -1359,6 +1368,7 @@
"original": "originál", "original": "originál",
"other": "Ostatní", "other": "Ostatní",
"other_devices": "Ostatní zařízení", "other_devices": "Ostatní zařízení",
"other_entities": "Ostatní entity",
"other_variables": "Další proměnné", "other_variables": "Další proměnné",
"owned": "Vlastní", "owned": "Vlastní",
"owner": "Vlastník", "owner": "Vlastník",
@@ -1519,6 +1529,8 @@
"refreshing_faces": "Obnovování obličejů", "refreshing_faces": "Obnovování obličejů",
"refreshing_metadata": "Obnovování metadat", "refreshing_metadata": "Obnovování metadat",
"regenerating_thumbnails": "Regenerace miniatur", "regenerating_thumbnails": "Regenerace miniatur",
"remote": "Vzdálený",
"remote_assets": "Vzdálené položky",
"remove": "Odstranit", "remove": "Odstranit",
"remove_assets_album_confirmation": "Opravdu chcete z alba odstranit {count, plural, one {# položku} few {# položky} other {# položek}}?", "remove_assets_album_confirmation": "Opravdu chcete z alba odstranit {count, plural, one {# položku} few {# položky} other {# položek}}?",
"remove_assets_shared_link_confirmation": "Opravdu chcete ze sdíleného odkazu odstranit {count, plural, one {# položku} few {# položky} other {# položek}}?", "remove_assets_shared_link_confirmation": "Opravdu chcete ze sdíleného odkazu odstranit {count, plural, one {# položku} few {# položky} other {# položek}}?",
@@ -1556,11 +1568,15 @@
"reset_password": "Obnovit heslo", "reset_password": "Obnovit heslo",
"reset_people_visibility": "Obnovit viditelnost lidí", "reset_people_visibility": "Obnovit viditelnost lidí",
"reset_pin_code": "Resetovat PIN kód", "reset_pin_code": "Resetovat PIN kód",
"reset_sqlite": "Obnovit SQLite databázi",
"reset_sqlite_confirmation": "Jste si jisti, že chcete obnovit SQLite databázi? Pro opětovnou synchronizaci dat se budete muset odhlásit a znovu přihlásit",
"reset_sqlite_success": "Obnovení SQLite databáze proběhlo úspěšně",
"reset_to_default": "Obnovit výchozí nastavení", "reset_to_default": "Obnovit výchozí nastavení",
"resolve_duplicates": "Vyřešit duplicity", "resolve_duplicates": "Vyřešit duplicity",
"resolved_all_duplicates": "Vyřešeny všechny duplicity", "resolved_all_duplicates": "Vyřešeny všechny duplicity",
"restore": "Obnovit", "restore": "Obnovit",
"restore_all": "Obnovit vše", "restore_all": "Obnovit vše",
"restore_trash_action_prompt": "{count} obnoveno z koše",
"restore_user": "Obnovit uživatele", "restore_user": "Obnovit uživatele",
"restored_asset": "Položka obnovena", "restored_asset": "Položka obnovena",
"resume": "Pokračovat", "resume": "Pokračovat",
@@ -1569,6 +1585,7 @@
"role": "Role", "role": "Role",
"role_editor": "Editor", "role_editor": "Editor",
"role_viewer": "Divák", "role_viewer": "Divák",
"running": "Probíhá",
"save": "Uložit", "save": "Uložit",
"save_to_gallery": "Uložit do galerie", "save_to_gallery": "Uložit do galerie",
"saved_api_key": "API klíč uložen", "saved_api_key": "API klíč uložen",
@@ -1822,6 +1839,7 @@
"storage_quota": "Kvóta úložiště", "storage_quota": "Kvóta úložiště",
"storage_usage": "Využito {used} z {available}", "storage_usage": "Využito {used} z {available}",
"submit": "Odeslat", "submit": "Odeslat",
"success": "Úspěch",
"suggestions": "Návrhy", "suggestions": "Návrhy",
"sunrise_on_the_beach": "Východ slunce na pláži", "sunrise_on_the_beach": "Východ slunce na pláži",
"support": "Podpora", "support": "Podpora",
@@ -1831,6 +1849,8 @@
"sync": "Synchronizovat", "sync": "Synchronizovat",
"sync_albums": "Synchronizovat alba", "sync_albums": "Synchronizovat alba",
"sync_albums_manual_subtitle": "Synchronizovat všechna nahraná videa a fotografie do vybraných záložních alb", "sync_albums_manual_subtitle": "Synchronizovat všechna nahraná videa a fotografie do vybraných záložních alb",
"sync_local": "Synchronizovat místní",
"sync_remote": "Synchronizovat vzdálené",
"sync_upload_album_setting_subtitle": "Vytvořit a nahrát fotografie a videa do vybraných alb na Immich", "sync_upload_album_setting_subtitle": "Vytvořit a nahrát fotografie a videa do vybraných alb na Immich",
"tag": "Značka", "tag": "Značka",
"tag_assets": "Přiřadit značku", "tag_assets": "Přiřadit značku",
@@ -1841,6 +1861,7 @@
"tag_updated": "Aktualizována značka: {tag}", "tag_updated": "Aktualizována značka: {tag}",
"tagged_assets": "Přiřazena značka {count, plural, one {# položce} other {# položkám}}", "tagged_assets": "Přiřazena značka {count, plural, one {# položce} other {# položkám}}",
"tags": "Značky", "tags": "Značky",
"tap_to_run_job": "Klepnutím na spustíte úlohu",
"template": "Šablona", "template": "Šablona",
"theme": "Motiv", "theme": "Motiv",
"theme_selection": "Výběr motivu", "theme_selection": "Výběr motivu",

View File

@@ -573,6 +573,8 @@
"backup_options_page_title": "Sicherungsoptionen", "backup_options_page_title": "Sicherungsoptionen",
"backup_setting_subtitle": "Verwaltung der Upload-Einstellungen im Hintergrund und im Vordergrund", "backup_setting_subtitle": "Verwaltung der Upload-Einstellungen im Hintergrund und im Vordergrund",
"backward": "Rückwärts", "backward": "Rückwärts",
"beta_sync": "Status des Beta Sync",
"beta_sync_subtitle": "Verwalte das neue Synchronisierungssystem",
"biometric_auth_enabled": "Biometrische Authentifizierung aktiviert", "biometric_auth_enabled": "Biometrische Authentifizierung aktiviert",
"biometric_locked_out": "Du bist von der biometrischen Authentifizierung ausgeschlossen", "biometric_locked_out": "Du bist von der biometrischen Authentifizierung ausgeschlossen",
"biometric_no_options": "Keine biometrischen Optionen verfügbar", "biometric_no_options": "Keine biometrischen Optionen verfügbar",
@@ -1051,6 +1053,9 @@
"haptic_feedback_switch": "Haptisches Feedback aktivieren", "haptic_feedback_switch": "Haptisches Feedback aktivieren",
"haptic_feedback_title": "Haptisches Feedback", "haptic_feedback_title": "Haptisches Feedback",
"has_quota": "Kontingent", "has_quota": "Kontingent",
"hash_asset": "Dateihash",
"hashed_assets": "Gehashte Dateien",
"hashing": "Hashen",
"header_settings_add_header_tip": "Header hinzufügen", "header_settings_add_header_tip": "Header hinzufügen",
"header_settings_field_validator_msg": "Der Wert darf nicht leer sein", "header_settings_field_validator_msg": "Der Wert darf nicht leer sein",
"header_settings_header_name_input": "Header-Name", "header_settings_header_name_input": "Header-Name",
@@ -1083,6 +1088,7 @@
"host": "Host", "host": "Host",
"hour": "Stunde", "hour": "Stunde",
"id": "ID", "id": "ID",
"idle": "Untätig",
"ignore_icloud_photos": "iCloud Fotos ignorieren", "ignore_icloud_photos": "iCloud Fotos ignorieren",
"ignore_icloud_photos_description": "Fotos, die in der iCloud gespeichert sind, werden nicht auf den immich Server hochgeladen", "ignore_icloud_photos_description": "Fotos, die in der iCloud gespeichert sind, werden nicht auf den immich Server hochgeladen",
"image": "Bild", "image": "Bild",
@@ -1165,7 +1171,9 @@
"list": "Liste", "list": "Liste",
"loading": "Laden", "loading": "Laden",
"loading_search_results_failed": "Laden von Suchergebnissen fehlgeschlagen", "loading_search_results_failed": "Laden von Suchergebnissen fehlgeschlagen",
"local": "Lokal",
"local_asset_cast_failed": "Eine Datei, die nicht auf den Server hochgeladen wurde, kann nicht gecastet werden", "local_asset_cast_failed": "Eine Datei, die nicht auf den Server hochgeladen wurde, kann nicht gecastet werden",
"local_assets": "Lokale Dateien",
"local_network": "Lokales Netzwerk", "local_network": "Lokales Netzwerk",
"local_network_sheet_info": "Die App stellt über diese URL eine Verbindung zum Server her, wenn sie das angegebene WLAN-Netzwerk verwendet", "local_network_sheet_info": "Die App stellt über diese URL eine Verbindung zum Server her, wenn sie das angegebene WLAN-Netzwerk verwendet",
"location_permission": "Standort Genehmigung", "location_permission": "Standort Genehmigung",
@@ -1322,6 +1330,7 @@
"no_results": "Keine Ergebnisse", "no_results": "Keine Ergebnisse",
"no_results_description": "Versuche es mit einem Synonym oder einem allgemeineren Stichwort", "no_results_description": "Versuche es mit einem Synonym oder einem allgemeineren Stichwort",
"no_shared_albums_message": "Erstelle ein Album, um Fotos und Videos mit Personen in deinem Netzwerk zu teilen", "no_shared_albums_message": "Erstelle ein Album, um Fotos und Videos mit Personen in deinem Netzwerk zu teilen",
"no_uploads_in_progress": "Kein Upload in Bearbeitung",
"not_in_any_album": "In keinem Album", "not_in_any_album": "In keinem Album",
"not_selected": "Nicht ausgewählt", "not_selected": "Nicht ausgewählt",
"note_apply_storage_label_to_previously_uploaded assets": "Hinweis: Um eine Speicherpfadbezeichnung anzuwenden, starte den", "note_apply_storage_label_to_previously_uploaded assets": "Hinweis: Um eine Speicherpfadbezeichnung anzuwenden, starte den",
@@ -1359,6 +1368,7 @@
"original": "Original", "original": "Original",
"other": "Sonstiges", "other": "Sonstiges",
"other_devices": "Andere Geräte", "other_devices": "Andere Geräte",
"other_entities": "Andere Entitäten",
"other_variables": "Sonstige Variablen", "other_variables": "Sonstige Variablen",
"owned": "Eigenes", "owned": "Eigenes",
"owner": "Besitzer", "owner": "Besitzer",
@@ -1519,6 +1529,8 @@
"refreshing_faces": "Gesichter werden aktualisiert", "refreshing_faces": "Gesichter werden aktualisiert",
"refreshing_metadata": "Metadaten werden aktualisiert", "refreshing_metadata": "Metadaten werden aktualisiert",
"regenerating_thumbnails": "Miniaturansichten werden neu erstellt", "regenerating_thumbnails": "Miniaturansichten werden neu erstellt",
"remote": "Entfernt",
"remote_assets": "Entfernte Dateien",
"remove": "Entfernen", "remove": "Entfernen",
"remove_assets_album_confirmation": "Bist du sicher, dass du {count, plural, one {# Datei} other {# Dateien}} aus dem Album entfernen willst?", "remove_assets_album_confirmation": "Bist du sicher, dass du {count, plural, one {# Datei} other {# Dateien}} aus dem Album entfernen willst?",
"remove_assets_shared_link_confirmation": "Bist du sicher, dass du {count, plural, one {# Datei} other {# Dateien}} von diesem geteilten Link entfernen willst?", "remove_assets_shared_link_confirmation": "Bist du sicher, dass du {count, plural, one {# Datei} other {# Dateien}} von diesem geteilten Link entfernen willst?",
@@ -1556,11 +1568,15 @@
"reset_password": "Passwort zurücksetzen", "reset_password": "Passwort zurücksetzen",
"reset_people_visibility": "Sichtbarkeit von Personen zurücksetzen", "reset_people_visibility": "Sichtbarkeit von Personen zurücksetzen",
"reset_pin_code": "PIN Code zurücksetzen", "reset_pin_code": "PIN Code zurücksetzen",
"reset_sqlite": "SQLite Datenbank zurücksetzen",
"reset_sqlite_confirmation": "Bist du sicher, dass du die SQLite-Datenbank zurücksetzen willst? Du musst dich ab- und wieder anmelden, um die Daten neu zu synchronisieren",
"reset_sqlite_success": "SQLite Datenbank erfolgreich zurückgesetzt",
"reset_to_default": "Auf Standard zurücksetzen", "reset_to_default": "Auf Standard zurücksetzen",
"resolve_duplicates": "Duplikate entfernen", "resolve_duplicates": "Duplikate entfernen",
"resolved_all_duplicates": "Alle Duplikate aufgelöst", "resolved_all_duplicates": "Alle Duplikate aufgelöst",
"restore": "Wiederherstellen", "restore": "Wiederherstellen",
"restore_all": "Alle wiederherstellen", "restore_all": "Alle wiederherstellen",
"restore_trash_action_prompt": "{count} aus dem Papierkorb wiederhergestellt",
"restore_user": "Nutzer wiederherstellen", "restore_user": "Nutzer wiederherstellen",
"restored_asset": "Datei wiederhergestellt", "restored_asset": "Datei wiederhergestellt",
"resume": "Fortsetzen", "resume": "Fortsetzen",
@@ -1569,6 +1585,7 @@
"role": "Rolle", "role": "Rolle",
"role_editor": "Bearbeiter", "role_editor": "Bearbeiter",
"role_viewer": "Betrachter", "role_viewer": "Betrachter",
"running": "Läuft",
"save": "Speichern", "save": "Speichern",
"save_to_gallery": "In Galerie speichern", "save_to_gallery": "In Galerie speichern",
"saved_api_key": "API-Schlüssel wurde gespeichert", "saved_api_key": "API-Schlüssel wurde gespeichert",
@@ -1822,6 +1839,7 @@
"storage_quota": "Speicherplatz-Kontingent", "storage_quota": "Speicherplatz-Kontingent",
"storage_usage": "{used} von {available} verwendet", "storage_usage": "{used} von {available} verwendet",
"submit": "Bestätigen", "submit": "Bestätigen",
"success": "Erfolgreich",
"suggestions": "Vorschläge", "suggestions": "Vorschläge",
"sunrise_on_the_beach": "Sonnenaufgang am Strand", "sunrise_on_the_beach": "Sonnenaufgang am Strand",
"support": "Unterstützung", "support": "Unterstützung",
@@ -1831,6 +1849,8 @@
"sync": "Synchronisieren", "sync": "Synchronisieren",
"sync_albums": "Alben synchronisieren", "sync_albums": "Alben synchronisieren",
"sync_albums_manual_subtitle": "Synchronisiere alle hochgeladenen Videos und Fotos in die ausgewählten Backup-Alben", "sync_albums_manual_subtitle": "Synchronisiere alle hochgeladenen Videos und Fotos in die ausgewählten Backup-Alben",
"sync_local": "Lokal synchronisieren",
"sync_remote": "Entfernt synchronisieren",
"sync_upload_album_setting_subtitle": "Erstelle deine ausgewählten Alben in Immich und lade die Fotos und Videos dort hoch", "sync_upload_album_setting_subtitle": "Erstelle deine ausgewählten Alben in Immich und lade die Fotos und Videos dort hoch",
"tag": "Tag", "tag": "Tag",
"tag_assets": "Dateien taggen", "tag_assets": "Dateien taggen",
@@ -1841,6 +1861,7 @@
"tag_updated": "Tag aktualisiert: {tag}", "tag_updated": "Tag aktualisiert: {tag}",
"tagged_assets": "{count, plural, one {# Datei} other {# Dateien}} getagged", "tagged_assets": "{count, plural, one {# Datei} other {# Dateien}} getagged",
"tags": "Tags", "tags": "Tags",
"tap_to_run_job": "Tippen um den Job zu starten",
"template": "Vorlage", "template": "Vorlage",
"theme": "Theme", "theme": "Theme",
"theme_selection": "Themenauswahl", "theme_selection": "Themenauswahl",

View File

@@ -397,6 +397,7 @@
"album_cover_updated": "Album cover updated", "album_cover_updated": "Album cover updated",
"album_delete_confirmation": "Are you sure you want to delete the album {album}?", "album_delete_confirmation": "Are you sure you want to delete the album {album}?",
"album_delete_confirmation_description": "If this album is shared, other users will not be able to access it anymore.", "album_delete_confirmation_description": "If this album is shared, other users will not be able to access it anymore.",
"album_deleted": "Album deleted",
"album_info_card_backup_album_excluded": "EXCLUDED", "album_info_card_backup_album_excluded": "EXCLUDED",
"album_info_card_backup_album_included": "INCLUDED", "album_info_card_backup_album_included": "INCLUDED",
"album_info_updated": "Album info updated", "album_info_updated": "Album info updated",
@@ -1002,6 +1003,8 @@
"explorer": "Explorer", "explorer": "Explorer",
"export": "Export", "export": "Export",
"export_as_json": "Export as JSON", "export_as_json": "Export as JSON",
"export_database": "Export Database",
"export_database_description": "Export the SQLite database",
"extension": "Extension", "extension": "Extension",
"external": "External", "external": "External",
"external_libraries": "External Libraries", "external_libraries": "External Libraries",
@@ -1941,11 +1944,13 @@
"updated_at": "Updated", "updated_at": "Updated",
"updated_password": "Updated password", "updated_password": "Updated password",
"upload": "Upload", "upload": "Upload",
"upload_action_prompt": "{count} queued for upload",
"upload_concurrency": "Upload concurrency", "upload_concurrency": "Upload concurrency",
"upload_details": "Upload Details", "upload_details": "Upload Details",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?", "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_title": "Upload Asset", "upload_dialog_title": "Upload Asset",
"upload_errors": "Upload completed with {count, plural, one {# error} other {# errors}}, refresh the page to see new upload assets.", "upload_errors": "Upload completed with {count, plural, one {# error} other {# errors}}, refresh the page to see new upload assets.",
"upload_finished": "Upload finished",
"upload_progress": "Remaining {remaining, number} - Processed {processed, number}/{total, number}", "upload_progress": "Remaining {remaining, number} - Processed {processed, number}/{total, number}",
"upload_skipped_duplicates": "Skipped {count, plural, one {# duplicate asset} other {# duplicate assets}}", "upload_skipped_duplicates": "Skipped {count, plural, one {# duplicate asset} other {# duplicate assets}}",
"upload_status_duplicates": "Duplicates", "upload_status_duplicates": "Duplicates",
@@ -1954,6 +1959,7 @@
"upload_success": "Upload success, refresh the page to see new upload assets.", "upload_success": "Upload success, refresh the page to see new upload assets.",
"upload_to_immich": "Upload to Immich ({count})", "upload_to_immich": "Upload to Immich ({count})",
"uploading": "Uploading", "uploading": "Uploading",
"uploading_media": "Uploading media",
"url": "URL", "url": "URL",
"usage": "Usage", "usage": "Usage",
"use_biometric": "Use biometric", "use_biometric": "Use biometric",

View File

@@ -573,6 +573,8 @@
"backup_options_page_title": "Varundamise valikud", "backup_options_page_title": "Varundamise valikud",
"backup_setting_subtitle": "Halda taustal ja esiplaanil üleslaadimise seadeid", "backup_setting_subtitle": "Halda taustal ja esiplaanil üleslaadimise seadeid",
"backward": "Tagasi", "backward": "Tagasi",
"beta_sync": "Beeta sünkroonimise staatus",
"beta_sync_subtitle": "Halda uut sünkroonimissüsteemi",
"biometric_auth_enabled": "Biomeetriline autentimine lubatud", "biometric_auth_enabled": "Biomeetriline autentimine lubatud",
"biometric_locked_out": "Biomeetriline autentimine on blokeeritud", "biometric_locked_out": "Biomeetriline autentimine on blokeeritud",
"biometric_no_options": "Biomeetrilisi valikuid ei ole", "biometric_no_options": "Biomeetrilisi valikuid ei ole",
@@ -590,7 +592,7 @@
"cache_settings_clear_cache_button": "Tühjenda puhver", "cache_settings_clear_cache_button": "Tühjenda puhver",
"cache_settings_clear_cache_button_title": "Tühjendab rakenduse puhvri. See mõjutab oluliselt rakenduse jõudlust, kuni puhver uuesti täidetakse.", "cache_settings_clear_cache_button_title": "Tühjendab rakenduse puhvri. See mõjutab oluliselt rakenduse jõudlust, kuni puhver uuesti täidetakse.",
"cache_settings_duplicated_assets_clear_button": "TÜHJENDA", "cache_settings_duplicated_assets_clear_button": "TÜHJENDA",
"cache_settings_duplicated_assets_subtitle": "Fotod ja videod, mis on rakenduse poolt mustfiltreeritud", "cache_settings_duplicated_assets_subtitle": "Fotod ja videod, mis on rakenduse poolt ignoreeritud",
"cache_settings_duplicated_assets_title": "Dubleeritud üksused ({count})", "cache_settings_duplicated_assets_title": "Dubleeritud üksused ({count})",
"cache_settings_statistics_album": "Kogu pisipildid", "cache_settings_statistics_album": "Kogu pisipildid",
"cache_settings_statistics_full": "Täismõõdus pildid", "cache_settings_statistics_full": "Täismõõdus pildid",
@@ -1051,6 +1053,9 @@
"haptic_feedback_switch": "Luba haptiline tagasiside", "haptic_feedback_switch": "Luba haptiline tagasiside",
"haptic_feedback_title": "Haptiline tagasiside", "haptic_feedback_title": "Haptiline tagasiside",
"has_quota": "On kvoot", "has_quota": "On kvoot",
"hash_asset": "Arvuta üksuse räsi",
"hashed_assets": "Räsiga üksused",
"hashing": "Räsi arvutamine",
"header_settings_add_header_tip": "Lisa päis", "header_settings_add_header_tip": "Lisa päis",
"header_settings_field_validator_msg": "Väärtus ei saa olla tühi", "header_settings_field_validator_msg": "Väärtus ei saa olla tühi",
"header_settings_header_name_input": "Päise nimi", "header_settings_header_name_input": "Päise nimi",
@@ -1083,6 +1088,7 @@
"host": "Host", "host": "Host",
"hour": "Tund", "hour": "Tund",
"id": "ID", "id": "ID",
"idle": "Jõude",
"ignore_icloud_photos": "Ignoreeri iCloud fotosid", "ignore_icloud_photos": "Ignoreeri iCloud fotosid",
"ignore_icloud_photos_description": "Fotosid, mis on iCloud'is, ei laadita üles Immich'i serverisse", "ignore_icloud_photos_description": "Fotosid, mis on iCloud'is, ei laadita üles Immich'i serverisse",
"image": "Pilt", "image": "Pilt",
@@ -1165,7 +1171,9 @@
"list": "Loend", "list": "Loend",
"loading": "Laadimine", "loading": "Laadimine",
"loading_search_results_failed": "Otsitulemuste laadimine ebaõnnestus", "loading_search_results_failed": "Otsitulemuste laadimine ebaõnnestus",
"local": "Lokaalne üksus",
"local_asset_cast_failed": "Ei saa edastada üksust, mis pole serverisse üles laaditud", "local_asset_cast_failed": "Ei saa edastada üksust, mis pole serverisse üles laaditud",
"local_assets": "Lokaalsed üksused",
"local_network": "Kohalik võrk", "local_network": "Kohalik võrk",
"local_network_sheet_info": "Rakendus ühendub valitud Wi-Fi võrgus olles serveriga selle URL-i kaudu", "local_network_sheet_info": "Rakendus ühendub valitud Wi-Fi võrgus olles serveriga selle URL-i kaudu",
"location_permission": "Asukoha luba", "location_permission": "Asukoha luba",
@@ -1322,6 +1330,7 @@
"no_results": "Vasteid pole", "no_results": "Vasteid pole",
"no_results_description": "Proovi sünonüümi või üldisemat märksõna", "no_results_description": "Proovi sünonüümi või üldisemat märksõna",
"no_shared_albums_message": "Lisa album, et fotosid ja videosid teistega jagada", "no_shared_albums_message": "Lisa album, et fotosid ja videosid teistega jagada",
"no_uploads_in_progress": "Üleslaadimisi käimas ei ole",
"not_in_any_album": "Pole üheski albumis", "not_in_any_album": "Pole üheski albumis",
"not_selected": "Ei ole valitud", "not_selected": "Ei ole valitud",
"note_apply_storage_label_to_previously_uploaded assets": "Märkus: Et rakendada talletussilt varem üleslaaditud üksustele, käivita", "note_apply_storage_label_to_previously_uploaded assets": "Märkus: Et rakendada talletussilt varem üleslaaditud üksustele, käivita",
@@ -1359,6 +1368,7 @@
"original": "originaal", "original": "originaal",
"other": "Muud", "other": "Muud",
"other_devices": "Muud seadmed", "other_devices": "Muud seadmed",
"other_entities": "Muud objektid",
"other_variables": "Muud muutujad", "other_variables": "Muud muutujad",
"owned": "Minu omad", "owned": "Minu omad",
"owner": "Omanik", "owner": "Omanik",
@@ -1519,6 +1529,8 @@
"refreshing_faces": "Nägude värskendamine", "refreshing_faces": "Nägude värskendamine",
"refreshing_metadata": "Metaandmete värskendamine", "refreshing_metadata": "Metaandmete värskendamine",
"regenerating_thumbnails": "Pisipiltide uuesti genereerimine", "regenerating_thumbnails": "Pisipiltide uuesti genereerimine",
"remote": "Kaugüksus",
"remote_assets": "Kaugüksused",
"remove": "Eemalda", "remove": "Eemalda",
"remove_assets_album_confirmation": "Kas oled kindel, et soovid {count, plural, one {# üksuse} other {# üksust}} albumist eemaldada?", "remove_assets_album_confirmation": "Kas oled kindel, et soovid {count, plural, one {# üksuse} other {# üksust}} albumist eemaldada?",
"remove_assets_shared_link_confirmation": "Kas oled kindel, et soovid eemaldada {count, plural, one {# üksuse} other {# üksust}} sellelt jagatud lingilt?", "remove_assets_shared_link_confirmation": "Kas oled kindel, et soovid eemaldada {count, plural, one {# üksuse} other {# üksust}} sellelt jagatud lingilt?",
@@ -1556,11 +1568,15 @@
"reset_password": "Lähtesta parool", "reset_password": "Lähtesta parool",
"reset_people_visibility": "Lähtesta isikute nähtavus", "reset_people_visibility": "Lähtesta isikute nähtavus",
"reset_pin_code": "Lähtesta PIN-kood", "reset_pin_code": "Lähtesta PIN-kood",
"reset_sqlite": "Lähtesta SQLite andmebaas",
"reset_sqlite_confirmation": "Kas oled kindel, et soovid SQLite andmebaasi lähtestada? Andmete uuesti sünkroonimiseks pead välja ja jälle sisse logima",
"reset_sqlite_success": "SQLite andmebaas edukalt lähtestatud",
"reset_to_default": "Lähtesta", "reset_to_default": "Lähtesta",
"resolve_duplicates": "Lahenda duplikaadid", "resolve_duplicates": "Lahenda duplikaadid",
"resolved_all_duplicates": "Kõik duplikaadid lahendatud", "resolved_all_duplicates": "Kõik duplikaadid lahendatud",
"restore": "Taasta", "restore": "Taasta",
"restore_all": "Taasta kõik", "restore_all": "Taasta kõik",
"restore_trash_action_prompt": "{count} prügikastust taastatud",
"restore_user": "Taasta kasutaja", "restore_user": "Taasta kasutaja",
"restored_asset": "Üksus taastatud", "restored_asset": "Üksus taastatud",
"resume": "Jätka", "resume": "Jätka",
@@ -1569,6 +1585,7 @@
"role": "Roll", "role": "Roll",
"role_editor": "Muutja", "role_editor": "Muutja",
"role_viewer": "Vaataja", "role_viewer": "Vaataja",
"running": "Käimas",
"save": "Salvesta", "save": "Salvesta",
"save_to_gallery": "Salvesta galeriisse", "save_to_gallery": "Salvesta galeriisse",
"saved_api_key": "API võti salvestatud", "saved_api_key": "API võti salvestatud",
@@ -1822,6 +1839,7 @@
"storage_quota": "Talletuskvoot", "storage_quota": "Talletuskvoot",
"storage_usage": "{used}/{available} kasutatud", "storage_usage": "{used}/{available} kasutatud",
"submit": "Saada", "submit": "Saada",
"success": "Õnnestus",
"suggestions": "Soovitused", "suggestions": "Soovitused",
"sunrise_on_the_beach": "Päikesetõus rannal", "sunrise_on_the_beach": "Päikesetõus rannal",
"support": "Tugi", "support": "Tugi",
@@ -1831,6 +1849,8 @@
"sync": "Sünkrooni", "sync": "Sünkrooni",
"sync_albums": "Sünkrooni albumid", "sync_albums": "Sünkrooni albumid",
"sync_albums_manual_subtitle": "Sünkrooni kõik üleslaaditud videod ja fotod valitud varundusalbumitesse", "sync_albums_manual_subtitle": "Sünkrooni kõik üleslaaditud videod ja fotod valitud varundusalbumitesse",
"sync_local": "Sünkrooni lokaalsed üksused",
"sync_remote": "Sünkrooni kaugüksused",
"sync_upload_album_setting_subtitle": "Loo ja laadi oma pildid ja videod üles Immich'isse valitud albumitesse", "sync_upload_album_setting_subtitle": "Loo ja laadi oma pildid ja videod üles Immich'isse valitud albumitesse",
"tag": "Silt", "tag": "Silt",
"tag_assets": "Sildista üksuseid", "tag_assets": "Sildista üksuseid",
@@ -1841,6 +1861,7 @@
"tag_updated": "Muudetud silt: {tag}", "tag_updated": "Muudetud silt: {tag}",
"tagged_assets": "{count, plural, one {# üksus} other {# üksust}} sildistatud", "tagged_assets": "{count, plural, one {# üksus} other {# üksust}} sildistatud",
"tags": "Sildid", "tags": "Sildid",
"tap_to_run_job": "Puuduta tööte käivitamiseks",
"template": "Mall", "template": "Mall",
"theme": "Teema", "theme": "Teema",
"theme_selection": "Teema valik", "theme_selection": "Teema valik",

View File

@@ -406,6 +406,7 @@
"album_options": "Options de l'album", "album_options": "Options de l'album",
"album_remove_user": "Supprimer l'utilisateur?", "album_remove_user": "Supprimer l'utilisateur?",
"album_remove_user_confirmation": "Êtes-vous sûr de vouloir supprimer {user}?", "album_remove_user_confirmation": "Êtes-vous sûr de vouloir supprimer {user}?",
"album_search_not_found": "Aucun album trouvé ne correspond à votre recherche",
"album_share_no_users": "Il semble que vous ayez partagé cet album avec tous les utilisateurs ou que vous n'ayez aucun utilisateur avec lequel le partager.", "album_share_no_users": "Il semble que vous ayez partagé cet album avec tous les utilisateurs ou que vous n'ayez aucun utilisateur avec lequel le partager.",
"album_updated": "Album mis à jour", "album_updated": "Album mis à jour",
"album_updated_setting_description": "Recevoir une notification par courriel lorsqu'un album partagé a de nouveaux médias", "album_updated_setting_description": "Recevoir une notification par courriel lorsqu'un album partagé a de nouveaux médias",
@@ -425,6 +426,7 @@
"albums_default_sort_order": "Ordre de tri par défaut des albums", "albums_default_sort_order": "Ordre de tri par défaut des albums",
"albums_default_sort_order_description": "Ordre de tri des médias pour les nouveaux albums créés.", "albums_default_sort_order_description": "Ordre de tri des médias pour les nouveaux albums créés.",
"albums_feature_description": "Bibliothèques de médias pouvant être partagés avec d'autres utilisateurs.", "albums_feature_description": "Bibliothèques de médias pouvant être partagés avec d'autres utilisateurs.",
"albums_on_device_count": "Album sur l'appareil ({count})",
"all": "Tout", "all": "Tout",
"all_albums": "Tous les albums", "all_albums": "Tous les albums",
"all_people": "Toutes les personnes", "all_people": "Toutes les personnes",
@@ -571,6 +573,8 @@
"backup_options_page_title": "Options de sauvegarde", "backup_options_page_title": "Options de sauvegarde",
"backup_setting_subtitle": "Ajuster les paramètres d'envoi au premier et en arrière-plan", "backup_setting_subtitle": "Ajuster les paramètres d'envoi au premier et en arrière-plan",
"backward": "Arrière", "backward": "Arrière",
"beta_sync": "Statut de la synchronisation béta",
"beta_sync_subtitle": "Gérer le nouveau système de synchronisation",
"biometric_auth_enabled": "Authentification biométrique activée", "biometric_auth_enabled": "Authentification biométrique activée",
"biometric_locked_out": "L'authentification biométrique est verrouillé", "biometric_locked_out": "L'authentification biométrique est verrouillé",
"biometric_no_options": "Aucune option biométrique disponible", "biometric_no_options": "Aucune option biométrique disponible",
@@ -605,6 +609,7 @@
"cancel": "Annuler", "cancel": "Annuler",
"cancel_search": "Annuler la recherche", "cancel_search": "Annuler la recherche",
"canceled": "Annulé", "canceled": "Annulé",
"canceling": "Annulation",
"cannot_merge_people": "Impossible de fusionner les personnes", "cannot_merge_people": "Impossible de fusionner les personnes",
"cannot_undo_this_action": "Vous ne pouvez pas annuler cette action!", "cannot_undo_this_action": "Vous ne pouvez pas annuler cette action!",
"cannot_update_the_description": "Impossible de mettre à jour la description", "cannot_update_the_description": "Impossible de mettre à jour la description",
@@ -765,6 +770,7 @@
"description": "Description", "description": "Description",
"description_input_hint_text": "Ajouter une description...", "description_input_hint_text": "Ajouter une description...",
"description_input_submit_error": "Erreur de mise à jour de la description, vérifier le journal pour plus de détails", "description_input_submit_error": "Erreur de mise à jour de la description, vérifier le journal pour plus de détails",
"deselect_all": "Tout désélectionner",
"details": "Détails", "details": "Détails",
"direction": "Ordre", "direction": "Ordre",
"disabled": "Désactivé", "disabled": "Désactivé",
@@ -839,6 +845,7 @@
"empty_trash": "Vider la corbeille", "empty_trash": "Vider la corbeille",
"empty_trash_confirmation": "Êtes-vous sûr de vouloir vider la corbeille? Cela supprimera définitivement de Immich tous les médias qu'elle contient.\nVous ne pouvez pas annuler cette action!", "empty_trash_confirmation": "Êtes-vous sûr de vouloir vider la corbeille? Cela supprimera définitivement de Immich tous les médias qu'elle contient.\nVous ne pouvez pas annuler cette action!",
"enable": "Active", "enable": "Active",
"enable_backup": "Activer Backup",
"enable_biometric_auth_description": "Entrez votre code PIN pour activer l'authentification biométrique", "enable_biometric_auth_description": "Entrez votre code PIN pour activer l'authentification biométrique",
"enabled": "Activé", "enabled": "Activé",
"end_date": "Date de fin", "end_date": "Date de fin",
@@ -1046,6 +1053,9 @@
"haptic_feedback_switch": "Activer le retour haptique", "haptic_feedback_switch": "Activer le retour haptique",
"haptic_feedback_title": "Retour haptique", "haptic_feedback_title": "Retour haptique",
"has_quota": "Quota", "has_quota": "Quota",
"hash_asset": "Hasher le média",
"hashed_assets": "Média hashés",
"hashing": "Hash",
"header_settings_add_header_tip": "Ajouter un en-tête", "header_settings_add_header_tip": "Ajouter un en-tête",
"header_settings_field_validator_msg": "Cette valeur ne peut pas être vide", "header_settings_field_validator_msg": "Cette valeur ne peut pas être vide",
"header_settings_header_name_input": "Nom de l'en-tête", "header_settings_header_name_input": "Nom de l'en-tête",
@@ -1160,7 +1170,9 @@
"list": "Liste", "list": "Liste",
"loading": "Chargement", "loading": "Chargement",
"loading_search_results_failed": "Chargement des résultats échoué", "loading_search_results_failed": "Chargement des résultats échoué",
"local": "Local",
"local_asset_cast_failed": "Impossible de caster un média qui n'a pas envoyé vers le serveur", "local_asset_cast_failed": "Impossible de caster un média qui n'a pas envoyé vers le serveur",
"local_assets": "Média locaux",
"local_network": "Réseau local", "local_network": "Réseau local",
"local_network_sheet_info": "L'application va se connecter au serveur via cette URL quand l'appareil est connecté à ce réseau Wi-Fi", "local_network_sheet_info": "L'application va se connecter au serveur via cette URL quand l'appareil est connecté à ce réseau Wi-Fi",
"location_permission": "Autorisation de localisation", "location_permission": "Autorisation de localisation",
@@ -1317,6 +1329,7 @@
"no_results": "Aucun résultat", "no_results": "Aucun résultat",
"no_results_description": "Essayez un synonyme ou un mot-clé plus général", "no_results_description": "Essayez un synonyme ou un mot-clé plus général",
"no_shared_albums_message": "Créer un album pour partager vos photos et vidéos avec les personnes de votre réseau", "no_shared_albums_message": "Créer un album pour partager vos photos et vidéos avec les personnes de votre réseau",
"no_uploads_in_progress": "Pas d'envoi en cours",
"not_in_any_album": "Dans aucun album", "not_in_any_album": "Dans aucun album",
"not_selected": "Non sélectionné", "not_selected": "Non sélectionné",
"note_apply_storage_label_to_previously_uploaded assets": "Note : Pour appliquer l'étiquette de stockage aux médias précédemment envoyés, exécutez", "note_apply_storage_label_to_previously_uploaded assets": "Note : Pour appliquer l'étiquette de stockage aux médias précédemment envoyés, exécutez",
@@ -1354,6 +1367,7 @@
"original": "original", "original": "original",
"other": "Autre", "other": "Autre",
"other_devices": "Autres appareils", "other_devices": "Autres appareils",
"other_entities": "Autres entités",
"other_variables": "Autres variables", "other_variables": "Autres variables",
"owned": "Possédé", "owned": "Possédé",
"owner": "Propriétaire", "owner": "Propriétaire",
@@ -1485,6 +1499,7 @@
"purchase_server_description_2": "Statut de contributeur", "purchase_server_description_2": "Statut de contributeur",
"purchase_server_title": "Serveur", "purchase_server_title": "Serveur",
"purchase_settings_server_activated": "La clé du produit pour le Serveur est gérée par l'administrateur", "purchase_settings_server_activated": "La clé du produit pour le Serveur est gérée par l'administrateur",
"queue_status": "File d'attente {count}/{total}",
"rating": "Étoile d'évaluation", "rating": "Étoile d'évaluation",
"rating_clear": "Effacer l'évaluation", "rating_clear": "Effacer l'évaluation",
"rating_count": "{count, plural, one {# étoile} other {# étoiles}}", "rating_count": "{count, plural, one {# étoile} other {# étoiles}}",
@@ -1513,6 +1528,8 @@
"refreshing_faces": "Actualisation des visages", "refreshing_faces": "Actualisation des visages",
"refreshing_metadata": "Actualisation des métadonnées", "refreshing_metadata": "Actualisation des métadonnées",
"regenerating_thumbnails": "Regénération des miniatures", "regenerating_thumbnails": "Regénération des miniatures",
"remote": "A distance",
"remote_assets": "Média à distance",
"remove": "Supprimer", "remove": "Supprimer",
"remove_assets_album_confirmation": "Êtes-vous sûr de vouloir supprimer {count, plural, one {# média} other {# médias}} de l'album?", "remove_assets_album_confirmation": "Êtes-vous sûr de vouloir supprimer {count, plural, one {# média} other {# médias}} de l'album?",
"remove_assets_shared_link_confirmation": "Êtes-vous sûr de vouloir supprimer {count, plural, one {# média} other {# médias}} de ce lien partagé?", "remove_assets_shared_link_confirmation": "Êtes-vous sûr de vouloir supprimer {count, plural, one {# média} other {# médias}} de ce lien partagé?",
@@ -1550,11 +1567,15 @@
"reset_password": "Réinitialiser le mot de passe", "reset_password": "Réinitialiser le mot de passe",
"reset_people_visibility": "Réinitialiser la visibilité des personnes", "reset_people_visibility": "Réinitialiser la visibilité des personnes",
"reset_pin_code": "Réinitialiser le code PIN", "reset_pin_code": "Réinitialiser le code PIN",
"reset_sqlite": "Réinitialiser la base de données SQLite",
"reset_sqlite_confirmation": "Êtes vous sur que vous voulez réinitialiser la base de données SQLite? Vous devrez vous déconnecter and vous reconnecter à nouveau pour re-synchroniser les données",
"reset_sqlite_success": "La base de données SQLite à été réinitialisé avec succès",
"reset_to_default": "Rétablir les valeurs par défaut", "reset_to_default": "Rétablir les valeurs par défaut",
"resolve_duplicates": "Résoudre les doublons", "resolve_duplicates": "Résoudre les doublons",
"resolved_all_duplicates": "Résolution de tous les doublons", "resolved_all_duplicates": "Résolution de tous les doublons",
"restore": "Restaurer", "restore": "Restaurer",
"restore_all": "Tout restaurer", "restore_all": "Tout restaurer",
"restore_trash_action_prompt": "{count} restauré de la corbeille",
"restore_user": "Restaurer l'utilisateur", "restore_user": "Restaurer l'utilisateur",
"restored_asset": "Média restauré", "restored_asset": "Média restauré",
"resume": "Reprendre", "resume": "Reprendre",
@@ -1563,6 +1584,7 @@
"role": "Rôle", "role": "Rôle",
"role_editor": "Éditeur", "role_editor": "Éditeur",
"role_viewer": "Visionneuse", "role_viewer": "Visionneuse",
"running": "En marche",
"save": "Sauvegarder", "save": "Sauvegarder",
"save_to_gallery": "Enregistrer", "save_to_gallery": "Enregistrer",
"saved_api_key": "Clé API sauvegardée", "saved_api_key": "Clé API sauvegardée",
@@ -1816,6 +1838,7 @@
"storage_quota": "Quota de stockage", "storage_quota": "Quota de stockage",
"storage_usage": "{used} sur {available} utilisé", "storage_usage": "{used} sur {available} utilisé",
"submit": "Soumettre", "submit": "Soumettre",
"success": "Réussi",
"suggestions": "Suggestions", "suggestions": "Suggestions",
"sunrise_on_the_beach": "Lever de soleil sur la plage", "sunrise_on_the_beach": "Lever de soleil sur la plage",
"support": "Soutenir", "support": "Soutenir",
@@ -1825,6 +1848,8 @@
"sync": "Synchroniser", "sync": "Synchroniser",
"sync_albums": "Synchroniser dans des albums", "sync_albums": "Synchroniser dans des albums",
"sync_albums_manual_subtitle": "Synchroniser toutes les vidéos et photos envoyées dans les albums sélectionnés", "sync_albums_manual_subtitle": "Synchroniser toutes les vidéos et photos envoyées dans les albums sélectionnés",
"sync_local": "Synchronisation locale",
"sync_remote": "Synchronisation à distance",
"sync_upload_album_setting_subtitle": "Créez et envoyez vos photos et vidéos dans les albums sélectionnés sur Immich", "sync_upload_album_setting_subtitle": "Créez et envoyez vos photos et vidéos dans les albums sélectionnés sur Immich",
"tag": "Étiquette", "tag": "Étiquette",
"tag_assets": "Étiqueter les médias", "tag_assets": "Étiqueter les médias",
@@ -1835,6 +1860,7 @@
"tag_updated": "Étiquette mise à jour: {tag}", "tag_updated": "Étiquette mise à jour: {tag}",
"tagged_assets": "Étiquette ajoutée à {count, plural, one {# média} other {# médias}}", "tagged_assets": "Étiquette ajoutée à {count, plural, one {# média} other {# médias}}",
"tags": "Étiquettes", "tags": "Étiquettes",
"tap_to_run_job": "Appuyez pour démarrer la tâche",
"template": "Modèle", "template": "Modèle",
"theme": "Thème", "theme": "Thème",
"theme_selection": "Sélection du thème", "theme_selection": "Sélection du thème",
@@ -1915,6 +1941,7 @@
"updated_password": "Mot de passe mis à jour", "updated_password": "Mot de passe mis à jour",
"upload": "Envoyer", "upload": "Envoyer",
"upload_concurrency": "Envois simultanés", "upload_concurrency": "Envois simultanés",
"upload_details": "Uploader les details",
"upload_dialog_info": "Voulez-vous sauvegarder la sélection vers le serveur?", "upload_dialog_info": "Voulez-vous sauvegarder la sélection vers le serveur?",
"upload_dialog_title": "Envoyer le média", "upload_dialog_title": "Envoyer le média",
"upload_errors": "L'envoi s'est complété avec {count, plural, one {# erreur} other {# erreurs}}. Rafraîchissez la page pour voir les nouveaux médias envoyés.", "upload_errors": "L'envoi s'est complété avec {count, plural, one {# erreur} other {# erreurs}}. Rafraîchissez la page pour voir les nouveaux médias envoyés.",
@@ -1965,6 +1992,7 @@
"view_album": "Afficher l'album", "view_album": "Afficher l'album",
"view_all": "Voir tout", "view_all": "Voir tout",
"view_all_users": "Voir tous les utilisateurs", "view_all_users": "Voir tous les utilisateurs",
"view_details": "Voir les détails",
"view_in_timeline": "Voir dans la vue chronologique", "view_in_timeline": "Voir dans la vue chronologique",
"view_link": "Voir le lien", "view_link": "Voir le lien",
"view_links": "Voir les liens", "view_links": "Voir les liens",

View File

@@ -140,7 +140,7 @@
"machine_learning_smart_search_description": "Képek szemantikai keresése CLIP beágyazások segítségével", "machine_learning_smart_search_description": "Képek szemantikai keresése CLIP beágyazások segítségével",
"machine_learning_smart_search_enabled": "Okos keresés engedélyezése", "machine_learning_smart_search_enabled": "Okos keresés engedélyezése",
"machine_learning_smart_search_enabled_description": "Ha ki van kapcsolva, a képek nem lesznek átalakítva okos kereséshez.", "machine_learning_smart_search_enabled_description": "Ha ki van kapcsolva, a képek nem lesznek átalakítva okos kereséshez.",
"machine_learning_url_description": "Gépi tanulás szerver URL címe. Ha többi, mint egy URL van megadva, mindegyik szervert egyenként próbálja meg, amíg az egyik sikeresen nem válaszol, sorrendben az elsőtől az utólsóig. A nem válaszoló szervereket átmenetileg figyelmen kívül hagyja, amíg újra online nem lesznek.", "machine_learning_url_description": "Gépi tanulás szerver URL címe. Ha többi, mint egy URL van megadva, mindegyik szervert egyenként próbálja meg, amíg az egyik sikeresen nem válaszol, sorrendben az elsőtől az utólsóig. A nem elérhető szervereket átmenetileg figyelmen kívül lesznek hagyva, amíg újra online nem lesznek.",
"manage_concurrency": "Párhuzamos Feladatok Kezelése", "manage_concurrency": "Párhuzamos Feladatok Kezelése",
"manage_log_settings": "Naplózási beállítások kezelése", "manage_log_settings": "Naplózási beállítások kezelése",
"map_dark_style": "Sötét stílus", "map_dark_style": "Sötét stílus",
@@ -166,6 +166,12 @@
"metadata_settings_description": "Metaadat beállítások kezelése", "metadata_settings_description": "Metaadat beállítások kezelése",
"migration_job": "Migrálás", "migration_job": "Migrálás",
"migration_job_description": "Az elemek és arcok bélyegképeinek migrálása a legújabb mappastruktúrába", "migration_job_description": "Az elemek és arcok bélyegképeinek migrálása a legújabb mappastruktúrába",
"nightly_tasks_cluster_faces_setting_description": "Arcfelismerés futtatása az újonnan érzékelt arcokon",
"nightly_tasks_database_cleanup_setting": "Adatbázis-tisztítási feladatok",
"nightly_tasks_database_cleanup_setting_description": "A régi, lejárt adatok törlése az adatbázisból",
"nightly_tasks_generate_memories_setting": "Emlékek generálása",
"nightly_tasks_generate_memories_setting_description": "Új emlékek létrehozása elemekből",
"nightly_tasks_missing_thumbnails_setting": "Hiányzó indexképek generálása",
"no_paths_added": "Nincs megadva elérési útvonal", "no_paths_added": "Nincs megadva elérési útvonal",
"no_pattern_added": "Nincs megadva minta (pattern)", "no_pattern_added": "Nincs megadva minta (pattern)",
"note_apply_storage_label_previous_assets": "Megjegyzés: Ha a korábban feltöltött elemekhez is szeretne Tárhely Címkéket társítani, akkor futtassa ezt", "note_apply_storage_label_previous_assets": "Megjegyzés: Ha a korábban feltöltött elemekhez is szeretne Tárhely Címkéket társítani, akkor futtassa ezt",
@@ -360,7 +366,7 @@
"advanced_settings_enable_alternate_media_filter_subtitle": "Ezzel a beállítással a szinkronizálás során alternatív kritériumok alapján szűrheted a fájlokat. Csak akkor próbáld ki, ha problémáid vannak azzal, hogy az alkalmazás nem ismeri fel az összes albumot.", "advanced_settings_enable_alternate_media_filter_subtitle": "Ezzel a beállítással a szinkronizálás során alternatív kritériumok alapján szűrheted a fájlokat. Csak akkor próbáld ki, ha problémáid vannak azzal, hogy az alkalmazás nem ismeri fel az összes albumot.",
"advanced_settings_enable_alternate_media_filter_title": "[KÍSÉRLETI] Alternatív eszköz album szinkronizálási szűrő használata", "advanced_settings_enable_alternate_media_filter_title": "[KÍSÉRLETI] Alternatív eszköz album szinkronizálási szűrő használata",
"advanced_settings_log_level_title": "Naplózás szintje: {level}", "advanced_settings_log_level_title": "Naplózás szintje: {level}",
"advanced_settings_prefer_remote_subtitle": "Néhány eszköz fájdalmasan lassan tölti be az eszközön lévő bélyegképeket. Ez a beállítás inkább a távoli képeket tölti be helyettük.", "advanced_settings_prefer_remote_subtitle": "Néhány eszköz fájdalmasan lassan tölti be az eszközön lévő indexképeket. Ez a beállítás inkább a távoli képeket (a szerverről) tölti be helyettük.",
"advanced_settings_prefer_remote_title": "Távoli képek előnyben részesítése", "advanced_settings_prefer_remote_title": "Távoli képek előnyben részesítése",
"advanced_settings_proxy_headers_subtitle": "Add meg azokat a proxy fejléceket, amiket az app elküldjön minden hálózati kérésnél", "advanced_settings_proxy_headers_subtitle": "Add meg azokat a proxy fejléceket, amiket az app elküldjön minden hálózati kérésnél",
"advanced_settings_proxy_headers_title": "Proxy Fejlécek", "advanced_settings_proxy_headers_title": "Proxy Fejlécek",
@@ -517,7 +523,7 @@
"backup_controller_page_background_is_on": "Automatikus mentés a háttérben be van kapcsolva", "backup_controller_page_background_is_on": "Automatikus mentés a háttérben be van kapcsolva",
"backup_controller_page_background_turn_off": "Háttérszolgáltatás kikapcsolása", "backup_controller_page_background_turn_off": "Háttérszolgáltatás kikapcsolása",
"backup_controller_page_background_turn_on": "Háttérszolgáltatás bekapcsolása", "backup_controller_page_background_turn_on": "Háttérszolgáltatás bekapcsolása",
"backup_controller_page_background_wifi": "Csak WiFi-n", "backup_controller_page_background_wifi": "Csak Wi-Fi-n",
"backup_controller_page_backup": "Mentés", "backup_controller_page_backup": "Mentés",
"backup_controller_page_backup_selected": "Kiválasztva: ", "backup_controller_page_backup_selected": "Kiválasztva: ",
"backup_controller_page_backup_sub": "Mentett fotók és videók", "backup_controller_page_backup_sub": "Mentett fotók és videók",
@@ -551,8 +557,8 @@
"backup_setting_subtitle": "A háttérben és előtérben mentés beállításainak kezelése", "backup_setting_subtitle": "A háttérben és előtérben mentés beállításainak kezelése",
"backward": "Visszafele", "backward": "Visszafele",
"biometric_auth_enabled": "Biometrikus azonosítás engedélyezve", "biometric_auth_enabled": "Biometrikus azonosítás engedélyezve",
"biometric_locked_out": "A biometrikus azonosításból kizárva", "biometric_locked_out": "Ki vagy zárva a biometrikus azonosításból",
"biometric_no_options": "A biometrikus azonosítás nem elérhető", "biometric_no_options": "Nincsen elérhető biometrikus azonosítás",
"biometric_not_available": "Biometrikus azonosítás ezen az eszközön nem elérhető", "biometric_not_available": "Biometrikus azonosítás ezen az eszközön nem elérhető",
"birthdate_saved": "Születésnap elmentve", "birthdate_saved": "Születésnap elmentve",
"birthdate_set_description": "A születés napját a rendszer arra használja, hogy kiírja, hogy a fénykép készítésekor a személy hány éves volt.", "birthdate_set_description": "A születés napját a rendszer arra használja, hogy kiírja, hogy a fénykép készítésekor a személy hány éves volt.",
@@ -642,7 +648,7 @@
"confirm_keep_this_delete_others": "Minden más elem a készletben törlésre kerül, kivéve ezt az elemet. Biztosan folytatni szeretnéd?", "confirm_keep_this_delete_others": "Minden más elem a készletben törlésre kerül, kivéve ezt az elemet. Biztosan folytatni szeretnéd?",
"confirm_new_pin_code": "Új PIN kód megerősítése", "confirm_new_pin_code": "Új PIN kód megerősítése",
"confirm_password": "Jelszó megerősítése", "confirm_password": "Jelszó megerősítése",
"confirm_tag_face": "Szeretnéd ezt az arcot {name}-ként megjelölni?", "confirm_tag_face": "Szeretnéd ezt az arcot {name}-nak/nek megjelölni?",
"confirm_tag_face_unnamed": "Szeretnéd ezt az arcot megjelölni?", "confirm_tag_face_unnamed": "Szeretnéd ezt az arcot megjelölni?",
"connected_device": "Kapcsolt eszköz", "connected_device": "Kapcsolt eszköz",
"connected_to": "Kapcsolódva", "connected_to": "Kapcsolódva",
@@ -770,7 +776,7 @@
"download_started": "Letöltés megkezdve", "download_started": "Letöltés megkezdve",
"download_sucess": "Sikeres letöltés", "download_sucess": "Sikeres letöltés",
"download_sucess_android": "Média letöltve a DCIM/Immich mappába", "download_sucess_android": "Média letöltve a DCIM/Immich mappába",
"download_waiting_to_retry": "Várakozás újrapróbálkozáshoz", "download_waiting_to_retry": "Várás az újrapróbálkozásra",
"downloading": "Letöltés", "downloading": "Letöltés",
"downloading_asset_filename": "{filename} elem letöltése", "downloading_asset_filename": "{filename} elem letöltése",
"downloading_media": "Média letöltése", "downloading_media": "Média letöltése",
@@ -816,7 +822,7 @@
"enqueued": "Sorba állítva", "enqueued": "Sorba állítva",
"enter_wifi_name": "Add meg a Wi-Fi hálózat nevét", "enter_wifi_name": "Add meg a Wi-Fi hálózat nevét",
"enter_your_pin_code": "Add meg a jelszavad", "enter_your_pin_code": "Add meg a jelszavad",
"enter_your_pin_code_subtitle": "Add meg a jelszavad a zárolt mappa megnyitásához", "enter_your_pin_code_subtitle": "Add meg a PIN kódodat a zárolt mappa megnyitásához",
"error": "Hiba", "error": "Hiba",
"error_change_sort_album": "Album sorbarendezésének megváltoztatása sikertelen", "error_change_sort_album": "Album sorbarendezésének megváltoztatása sikertelen",
"error_delete_face": "Hiba az arc törlése során", "error_delete_face": "Hiba az arc törlése során",
@@ -916,7 +922,7 @@
"unable_to_remove_partner": "Partner eltávolítása sikertelen", "unable_to_remove_partner": "Partner eltávolítása sikertelen",
"unable_to_remove_reaction": "Reakció eltávolítása sikertelen", "unable_to_remove_reaction": "Reakció eltávolítása sikertelen",
"unable_to_reset_password": "Jelszó visszaállítása sikertelen", "unable_to_reset_password": "Jelszó visszaállítása sikertelen",
"unable_to_reset_pin_code": "Jelszó visszaállítása sikertelen", "unable_to_reset_pin_code": "PIN kód visszaállítása sikertelen",
"unable_to_resolve_duplicate": "Duplikátum feloldása sikertelen", "unable_to_resolve_duplicate": "Duplikátum feloldása sikertelen",
"unable_to_restore_assets": "Elemek visszaállítása sikertelen", "unable_to_restore_assets": "Elemek visszaállítása sikertelen",
"unable_to_restore_trash": "Az összes elem visszaállítása sikertelen", "unable_to_restore_trash": "Az összes elem visszaállítása sikertelen",
@@ -988,7 +994,7 @@
"filetype": "Fájltípus", "filetype": "Fájltípus",
"filter": "Szűrő", "filter": "Szűrő",
"filter_people": "Személyek szűrése", "filter_people": "Személyek szűrése",
"filter_places": "Helyek szűrése", "filter_places": "Helyszínek szűrése",
"find_them_fast": "Név alapján kereséssel gyorsan megtalálhatóak", "find_them_fast": "Név alapján kereséssel gyorsan megtalálhatóak",
"fix_incorrect_match": "Hibás találat javítása", "fix_incorrect_match": "Hibás találat javítása",
"folder": "Mappa", "folder": "Mappa",
@@ -1029,9 +1035,9 @@
"hide_person": "Személy elrejtése", "hide_person": "Személy elrejtése",
"hide_unnamed_people": "Név nélküli személyek elrejtése", "hide_unnamed_people": "Név nélküli személyek elrejtése",
"home_page_add_to_album_conflicts": "{added} elem hozzáadva a(z) \"{album}\" albumhoz. {failed} elem már eleve az albumban volt.", "home_page_add_to_album_conflicts": "{added} elem hozzáadva a(z) \"{album}\" albumhoz. {failed} elem már eleve az albumban volt.",
"home_page_add_to_album_err_local": "Helyi elemeket még nem lehet albumba tenni, kihagyás", "home_page_add_to_album_err_local": "Helyi elemeket még nem lehet albumba tenni, ki lesznek hagyva",
"home_page_add_to_album_success": "{added} elem hozzáadva a(z) \"{album}\" albumhoz.", "home_page_add_to_album_success": "{added} elem hozzáadva a(z) \"{album}\" albumhoz.",
"home_page_album_err_partner": "Még nem lehet a partner elemeit albumokhoz adni, kihagyás", "home_page_album_err_partner": "Még nem lehet a partner elemeit albumokhoz adni, ki lesznek hagyva",
"home_page_archive_err_local": "Helyi elemek archiválása még nem támogatott, úgyhogy kihagyjuk", "home_page_archive_err_local": "Helyi elemek archiválása még nem támogatott, úgyhogy kihagyjuk",
"home_page_archive_err_partner": "Partner elemeit nem lehet archiválni, úgyhogy kihagyjuk", "home_page_archive_err_partner": "Partner elemeit nem lehet archiválni, úgyhogy kihagyjuk",
"home_page_building_timeline": "Idővonal összeállítása", "home_page_building_timeline": "Idővonal összeállítása",
@@ -1040,7 +1046,7 @@
"home_page_favorite_err_local": "Helyi elemeket még nem lehet a kedvencek közé tenni, úgyhogy ezeket kihagyjuk", "home_page_favorite_err_local": "Helyi elemeket még nem lehet a kedvencek közé tenni, úgyhogy ezeket kihagyjuk",
"home_page_favorite_err_partner": "Partner elemeit még nem lehet a kedvencek közé tenni, úgyhogy ezeket kihagyjuk", "home_page_favorite_err_partner": "Partner elemeit még nem lehet a kedvencek közé tenni, úgyhogy ezeket kihagyjuk",
"home_page_first_time_notice": "Ha most használod először az alkalmazást, a fotók és videók megjelenítéséhez az idővonaladon, állítsd be, hogy melyik albumaidról készüljön biztonsági mentés", "home_page_first_time_notice": "Ha most használod először az alkalmazást, a fotók és videók megjelenítéséhez az idővonaladon, állítsd be, hogy melyik albumaidról készüljön biztonsági mentés",
"home_page_locked_error_local": "Helyi elemek nem mozgathatóak a zárolt mappába, átugorva", "home_page_locked_error_local": "A Helyi elemek nem mozgathatóak a zárolt mappába, ki lesznek hagyva",
"home_page_locked_error_partner": "Partner elemek nem mozgathatóak a zárolt mappába, átugorva", "home_page_locked_error_partner": "Partner elemek nem mozgathatóak a zárolt mappába, átugorva",
"home_page_share_err_local": "Helyi elemekről nem lehet megosztott linket készíteni, úgyhogy kihagyjuk", "home_page_share_err_local": "Helyi elemekről nem lehet megosztott linket készíteni, úgyhogy kihagyjuk",
"home_page_upload_err_limit": "Csak 30 elemet tudsz egyszerre feltölteni, úgyhogy kihagyjuk", "home_page_upload_err_limit": "Csak 30 elemet tudsz egyszerre feltölteni, úgyhogy kihagyjuk",
@@ -1087,10 +1093,10 @@
"invite_people": "Személyek Meghívása", "invite_people": "Személyek Meghívása",
"invite_to_album": "Meghívás az albumba", "invite_to_album": "Meghívás az albumba",
"ios_debug_info_last_sync_at": "Utoljára szinkronizálva {dateTime}", "ios_debug_info_last_sync_at": "Utoljára szinkronizálva {dateTime}",
"ios_debug_info_no_processes_queued": "Nincs sorba állított hátterfolyamat", "ios_debug_info_no_processes_queued": "Nincs a sorban háttérfolyamat jelenleg",
"ios_debug_info_no_sync_yet": "Még nem futott szinkronizáló háttérfolyamat", "ios_debug_info_no_sync_yet": "Még nem futott szinkronizáló háttérfolyamat",
"ios_debug_info_processes_queued": "{count, plural, one {{count} háttérfolyamat előkészítve} other {{count} háttérfolyamat előkészítve}}", "ios_debug_info_processes_queued": "{count, plural, one {{count} háttérfolyamat előkészítve} other {{count} háttérfolyamat előkészítve}}",
"ios_debug_info_processing_ran_at": "Feldolgozás futott {dateTime}", "ios_debug_info_processing_ran_at": "A feldolgozás ekkor futott: {dateTime}",
"items_count": "{count, plural, other {# elem}}", "items_count": "{count, plural, other {# elem}}",
"jobs": "Feladatok", "jobs": "Feladatok",
"keep": "Megtart", "keep": "Megtart",
@@ -1099,7 +1105,7 @@
"kept_this_deleted_others": "Ez az elem és a töröltek meg lettek hagyva {count, plural, one {# asset} other {# assets}}", "kept_this_deleted_others": "Ez az elem és a töröltek meg lettek hagyva {count, plural, one {# asset} other {# assets}}",
"keyboard_shortcuts": "Billentyűparancsok", "keyboard_shortcuts": "Billentyűparancsok",
"language": "Nyelv", "language": "Nyelv",
"language_no_results_subtitle": "Próbáld a keresésed módosítását", "language_no_results_subtitle": "Próbáld módosítani a szavaidat a keresésnél",
"language_search_hint": "Nyelvek keresése...", "language_search_hint": "Nyelvek keresése...",
"language_setting_description": "Válaszd ki preferált nyelvet", "language_setting_description": "Válaszd ki preferált nyelvet",
"last_seen": "Utoljára láttuk", "last_seen": "Utoljára láttuk",
@@ -1129,7 +1135,7 @@
"local_network": "Helyi hálózat", "local_network": "Helyi hálózat",
"local_network_sheet_info": "Az alkalmazés ezen az URL címen fogja elérni a szervert, ha a megadott WiFi hálózathoz van csatlankozva", "local_network_sheet_info": "Az alkalmazés ezen az URL címen fogja elérni a szervert, ha a megadott WiFi hálózathoz van csatlankozva",
"location_permission": "Helymeghatározási engedély", "location_permission": "Helymeghatározási engedély",
"location_permission_content": "Hálózatok automatikus váltásához az Immich-nek szüksége van a pontos helymeghatározásra, hogy az alkalmazás le tudja kérni a Wi-Fi hálózat nevét", "location_permission_content": "A Hálózatok automatikus váltásához az Immich-nek szüksége van a pontos helymeghatározásra, hogy az alkalmazás le tudja kérni a Wi-Fi hálózat nevét",
"location_picker_choose_on_map": "Válassz a térképen", "location_picker_choose_on_map": "Válassz a térképen",
"location_picker_latitude_error": "Érvényes szélességi kört írj be", "location_picker_latitude_error": "Érvényes szélességi kört írj be",
"location_picker_latitude_hint": "Ide írd a szélességi kört", "location_picker_latitude_hint": "Ide írd a szélességi kört",
@@ -1139,7 +1145,7 @@
"locked_folder": "Zárolt mappa", "locked_folder": "Zárolt mappa",
"log_out": "Kijelentkezés", "log_out": "Kijelentkezés",
"log_out_all_devices": "Kijelentkezés Minden Eszközön", "log_out_all_devices": "Kijelentkezés Minden Eszközön",
"logged_in_as": "{user}-ként belépve", "logged_in_as": "Belépve: {user} néven",
"logged_out_all_devices": "Minden eszköz kijelentkeztetve", "logged_out_all_devices": "Minden eszköz kijelentkeztetve",
"logged_out_device": "Eszköz kijelentkeztetve", "logged_out_device": "Eszköz kijelentkeztetve",
"login": "Bejelentkezés", "login": "Bejelentkezés",
@@ -1234,9 +1240,9 @@
"monthly_title_text_date_format": "y MMMM", "monthly_title_text_date_format": "y MMMM",
"more": "Továbbiak", "more": "Továbbiak",
"move": "Áthelyezés", "move": "Áthelyezés",
"move_off_locked_folder": "Zárolt mappából kivonás", "move_off_locked_folder": "Átmozgatás a zárolt mappából",
"move_to_locked_folder": "Áthelyezés a zárolt mappába", "move_to_locked_folder": "Áthelyezés a zárolt mappába",
"move_to_locked_folder_confirmation": "Ezek a képek és videók az összes albumból kikerülnek, és csak a zárolt mappából lesznek elérhetőek", "move_to_locked_folder_confirmation": "Ezek a képek és videók az összes albumból kikerülnek, és csak a zárolt mappában lesznek elérhetőek",
"moved_to_archive": "{count, plural, one {# Elem} other {# Elemek}} archiválva", "moved_to_archive": "{count, plural, one {# Elem} other {# Elemek}} archiválva",
"moved_to_library": "{count, plural, one {# Elem} other {# Elemek}} másik könyvtárba költöztetve", "moved_to_library": "{count, plural, one {# Elem} other {# Elemek}} másik könyvtárba költöztetve",
"moved_to_trash": "Áthelyezve a lomtárba", "moved_to_trash": "Áthelyezve a lomtárba",
@@ -1254,7 +1260,7 @@
"new_password": "Új jelszó", "new_password": "Új jelszó",
"new_person": "Új személy", "new_person": "Új személy",
"new_pin_code": "Új PIN kód", "new_pin_code": "Új PIN kód",
"new_pin_code_subtitle": "Ez az első alkalom hogy megnyitod a zárolt mappát. Hozz létre egy jelszót az oldal biztosítására", "new_pin_code_subtitle": "Ez az első alkalom hogy megnyitod a zárolt mappát. Hozz létre egy jelszót a mappa biztonságos eléréséhez",
"new_user_created": "Új felhasználó létrehozva", "new_user_created": "Új felhasználó létrehozva",
"new_version_available": "ÚJ VERZIÓ ÉRHETŐ EL", "new_version_available": "ÚJ VERZIÓ ÉRHETŐ EL",
"newest_first": "Legújabb először", "newest_first": "Legújabb először",
@@ -1283,7 +1289,7 @@
"not_selected": "Nincs kiválasztva", "not_selected": "Nincs kiválasztva",
"note_apply_storage_label_to_previously_uploaded assets": "Megjegyzés: a korábban feltöltött elemek Tárhely Címkézéséhez futtasd a(z)", "note_apply_storage_label_to_previously_uploaded assets": "Megjegyzés: a korábban feltöltött elemek Tárhely Címkézéséhez futtasd a(z)",
"notes": "Megjegyzések", "notes": "Megjegyzések",
"nothing_here_yet": "Itt még nincs semmi", "nothing_here_yet": "Még semmi sincs itt",
"notification_permission_dialog_content": "Az értesítések bekapcsolásához a Beállítások menüben válaszd ki az Engedélyezés-t.", "notification_permission_dialog_content": "Az értesítések bekapcsolásához a Beállítások menüben válaszd ki az Engedélyezés-t.",
"notification_permission_list_tile_content": "Értesítések engedélyezése.", "notification_permission_list_tile_content": "Értesítések engedélyezése.",
"notification_permission_list_tile_enable_button": "Értesítések Bekapcsolása", "notification_permission_list_tile_enable_button": "Értesítések Bekapcsolása",
@@ -1293,7 +1299,7 @@
"notifications_setting_description": "Értesítések kezelése", "notifications_setting_description": "Értesítések kezelése",
"oauth": "OAuth", "oauth": "OAuth",
"official_immich_resources": "Hivatalos Immich Források", "official_immich_resources": "Hivatalos Immich Források",
"offline": "Offline", "offline": "Nem elérhető (offline)",
"ok": "Rendben", "ok": "Rendben",
"oldest_first": "Legrégebbi először", "oldest_first": "Legrégebbi először",
"on_this_device": "Ezen az eszközön", "on_this_device": "Ezen az eszközön",
@@ -1303,7 +1309,7 @@
"onboarding_theme_description": "Válassz egy színtémát. Ezt bármikor megváltoztathatod a beállításokban.", "onboarding_theme_description": "Válassz egy színtémát. Ezt bármikor megváltoztathatod a beállításokban.",
"onboarding_user_welcome_description": "Kezdjünk bele!", "onboarding_user_welcome_description": "Kezdjünk bele!",
"onboarding_welcome_user": "Üdvözöllek {user}", "onboarding_welcome_user": "Üdvözöllek {user}",
"online": "Online", "online": "Online (elérhető)",
"only_favorites": "Csak kedvencek", "only_favorites": "Csak kedvencek",
"open": "Nyitva", "open": "Nyitva",
"open_in_map_view": "Megnyitás térkép nézetben", "open_in_map_view": "Megnyitás térkép nézetben",
@@ -1754,7 +1760,7 @@
"stack_select_one_photo": "Válassz egy fő képet a csoportból", "stack_select_one_photo": "Válassz egy fő képet a csoportból",
"stack_selected_photos": "Kiválasztott fényképek csoportosítása", "stack_selected_photos": "Kiválasztott fényképek csoportosítása",
"stacked_assets_count": "{count, plural, other {# elem}} csoportosítva", "stacked_assets_count": "{count, plural, other {# elem}} csoportosítva",
"stacktrace": "Hibaleírás", "stacktrace": "Hiba leírása",
"start": "Elindít", "start": "Elindít",
"start_date": "Kezdő dátum", "start_date": "Kezdő dátum",
"state": "Megye/Állam", "state": "Megye/Állam",
@@ -1882,7 +1888,7 @@
"user_liked": "{user} felhasználónak {type, select, photo {ez a fénykép} video {ez a videó} asset {ez az elem} other {ez}} tetszik", "user_liked": "{user} felhasználónak {type, select, photo {ez a fénykép} video {ez a videó} asset {ez az elem} other {ez}} tetszik",
"user_pin_code_settings": "PIN kód", "user_pin_code_settings": "PIN kód",
"user_pin_code_settings_description": "PIN kód kezelése", "user_pin_code_settings_description": "PIN kód kezelése",
"user_privacy": "Felhasználói biztonság", "user_privacy": "Felhasználói adatvédelem",
"user_purchase_settings": "Megvásárlás", "user_purchase_settings": "Megvásárlás",
"user_purchase_settings_description": "Vásárlás kezelése", "user_purchase_settings_description": "Vásárlás kezelése",
"user_role_set": "{user} felhasználónak {role} jogkör biztosítása", "user_role_set": "{user} felhasználónak {role} jogkör biztosítása",

View File

@@ -169,15 +169,23 @@
"nightly_tasks_cluster_faces_setting_description": "Mulai pengenalan wajah pada semua wajah yang baru saja terdeteksi", "nightly_tasks_cluster_faces_setting_description": "Mulai pengenalan wajah pada semua wajah yang baru saja terdeteksi",
"nightly_tasks_cluster_new_faces_setting": "Kelompokkan semua wajah baru", "nightly_tasks_cluster_new_faces_setting": "Kelompokkan semua wajah baru",
"nightly_tasks_database_cleanup_setting": "Tugas pembersihan basis data", "nightly_tasks_database_cleanup_setting": "Tugas pembersihan basis data",
"nightly_tasks_database_cleanup_setting_description": "Membersihkan data lama, kadaluarsa dari database",
"nightly_tasks_generate_memories_setting": "Buat kenang-kenangan", "nightly_tasks_generate_memories_setting": "Buat kenang-kenangan",
"nightly_tasks_generate_memories_setting_description": "Buat kenang-kenangan baru dari berbagai aset", "nightly_tasks_generate_memories_setting_description": "Buat kenang-kenangan baru dari berbagai aset",
"nightly_tasks_missing_thumbnails_setting": "Membuat thumbnail yang hilang",
"nightly_tasks_missing_thumbnails_setting_description": "Mengantrikan aset tanpa thumbnail untuk pembuatan thumbnail",
"nightly_tasks_settings": "Pengaturan Tugas Malam",
"nightly_tasks_settings_description": "Atur tugas malam",
"nightly_tasks_start_time_setting": "Waktu mulai", "nightly_tasks_start_time_setting": "Waktu mulai",
"nightly_tasks_start_time_setting_description": "Waktu saat server mulai menjalankan tugas malam",
"nightly_tasks_sync_quota_usage_setting": "Sinkronisasi penggunaan kuota",
"nightly_tasks_sync_quota_usage_setting_description": "Pembaruan kuota penyimpanan pengguna, berdasarkan penggunaan sekarang",
"no_paths_added": "Tidak ada jalur yang ditambahkan", "no_paths_added": "Tidak ada jalur yang ditambahkan",
"no_pattern_added": "Tidak ada pola yang ditambahkan", "no_pattern_added": "Tidak ada pola yang ditambahkan",
"note_apply_storage_label_previous_assets": "Catatan: Untuk menerapkan Label Penyimpanan untuk aset yang telah diunggah sebelumnya, jalankan", "note_apply_storage_label_previous_assets": "Catatan: Untuk menerapkan Label Penyimpanan untuk aset yang telah diunggah sebelumnya, jalankan",
"note_cannot_be_changed_later": "CATATAN: Ini tidak akan dapat diubah lagi!", "note_cannot_be_changed_later": "CATATAN: Ini tidak akan dapat diubah lagi!",
"notification_email_from_address": "Dari alamat", "notification_email_from_address": "Dari alamat",
"notification_email_from_address_description": "Alamat surel pengirim, misalnya: \"Server Foto Immich <noreply@example.com>\". Pastikan untuk menggunakan alamat yang diizinkan untuk mengirim email", "notification_email_from_address_description": "Alamat surel pengirim, misalnya: \"Server Foto Immich <noreply@example.com>\". Pastikan untuk menggunakan alamat yang diizinkan untuk mengirim email.",
"notification_email_host_description": "Hos server surel (mis. smtp.immich.app)", "notification_email_host_description": "Hos server surel (mis. smtp.immich.app)",
"notification_email_ignore_certificate_errors": "Abaikan eror sertifikat", "notification_email_ignore_certificate_errors": "Abaikan eror sertifikat",
"notification_email_ignore_certificate_errors_description": "Abaikan eror validasi sertifikat TLS (tidak disarankan)", "notification_email_ignore_certificate_errors_description": "Abaikan eror validasi sertifikat TLS (tidak disarankan)",

View File

@@ -406,6 +406,7 @@
"album_options": "Impostazioni Album", "album_options": "Impostazioni Album",
"album_remove_user": "Rimuovi l'utente?", "album_remove_user": "Rimuovi l'utente?",
"album_remove_user_confirmation": "Sicuro di voler rimuovere l'utente {user}?", "album_remove_user_confirmation": "Sicuro di voler rimuovere l'utente {user}?",
"album_search_not_found": "Nessun album trovato corrispondente alla tua ricerca",
"album_share_no_users": "Sembra che tu abbia condiviso questo album con tutti gli utenti oppure non hai nessun utente con cui condividere.", "album_share_no_users": "Sembra che tu abbia condiviso questo album con tutti gli utenti oppure non hai nessun utente con cui condividere.",
"album_updated": "Album aggiornato", "album_updated": "Album aggiornato",
"album_updated_setting_description": "Ricevi una notifica email quando un album condiviso ha nuovi media", "album_updated_setting_description": "Ricevi una notifica email quando un album condiviso ha nuovi media",
@@ -425,6 +426,7 @@
"albums_default_sort_order": "Ordinamento predefinito degli album", "albums_default_sort_order": "Ordinamento predefinito degli album",
"albums_default_sort_order_description": "Ordine iniziale degli elementi alla creazione di nuovi album.", "albums_default_sort_order_description": "Ordine iniziale degli elementi alla creazione di nuovi album.",
"albums_feature_description": "Raggruppamento di elementi che possono essere condivisi con altri utenti.", "albums_feature_description": "Raggruppamento di elementi che possono essere condivisi con altri utenti.",
"albums_on_device_count": "Album sul dispositivo ({count})",
"all": "Tutti", "all": "Tutti",
"all_albums": "Tutti gli album", "all_albums": "Tutti gli album",
"all_people": "Tutte le persone", "all_people": "Tutte le persone",
@@ -605,6 +607,7 @@
"cancel": "Annulla", "cancel": "Annulla",
"cancel_search": "Annulla ricerca", "cancel_search": "Annulla ricerca",
"canceled": "Annullato", "canceled": "Annullato",
"canceling": "Annullamento",
"cannot_merge_people": "Impossibile unire le persone", "cannot_merge_people": "Impossibile unire le persone",
"cannot_undo_this_action": "Non puoi annullare questa azione!", "cannot_undo_this_action": "Non puoi annullare questa azione!",
"cannot_update_the_description": "Impossibile aggiornare la descrizione", "cannot_update_the_description": "Impossibile aggiornare la descrizione",
@@ -751,6 +754,7 @@
"delete_key": "Elimina chiave", "delete_key": "Elimina chiave",
"delete_library": "Elimina libreria", "delete_library": "Elimina libreria",
"delete_link": "Elimina link", "delete_link": "Elimina link",
"delete_local_action_prompt": "{count} elementi rimossi in locale",
"delete_local_dialog_ok_backed_up_only": "Elimina solo con backup", "delete_local_dialog_ok_backed_up_only": "Elimina solo con backup",
"delete_local_dialog_ok_force": "Elimina comunque", "delete_local_dialog_ok_force": "Elimina comunque",
"delete_others": "Elimina gli altri", "delete_others": "Elimina gli altri",
@@ -764,6 +768,7 @@
"description": "Descrizione", "description": "Descrizione",
"description_input_hint_text": "Aggiungi descrizione...", "description_input_hint_text": "Aggiungi descrizione...",
"description_input_submit_error": "Errore modificare descrizione, controlli I log per maggiori dettagli", "description_input_submit_error": "Errore modificare descrizione, controlli I log per maggiori dettagli",
"deselect_all": "Deseleziona Tutto",
"details": "Dettagli", "details": "Dettagli",
"direction": "Direzione", "direction": "Direzione",
"disabled": "Disabilitato", "disabled": "Disabilitato",
@@ -781,6 +786,7 @@
"documentation": "Documentazione", "documentation": "Documentazione",
"done": "Fatto", "done": "Fatto",
"download": "Scarica", "download": "Scarica",
"download_action_prompt": "Scaricando {count} elementi",
"download_canceled": "Download annullato", "download_canceled": "Download annullato",
"download_complete": "Download completato", "download_complete": "Download completato",
"download_enqueue": "Download in coda", "download_enqueue": "Download in coda",
@@ -837,6 +843,7 @@
"empty_trash": "Svuota cestino", "empty_trash": "Svuota cestino",
"empty_trash_confirmation": "Sei sicuro di volere svuotare il cestino? Questo rimuoverà tutte le risorse nel cestino in modo permanente da Immich.\nNon puoi annullare questa azione!", "empty_trash_confirmation": "Sei sicuro di volere svuotare il cestino? Questo rimuoverà tutte le risorse nel cestino in modo permanente da Immich.\nNon puoi annullare questa azione!",
"enable": "Abilita", "enable": "Abilita",
"enable_backup": "Abilita Backup",
"enable_biometric_auth_description": "Inserire il codice PIN per abilitare l'autenticazione biometrica", "enable_biometric_auth_description": "Inserire il codice PIN per abilitare l'autenticazione biometrica",
"enabled": "Abilitato", "enabled": "Abilitato",
"end_date": "Data Fine", "end_date": "Data Fine",
@@ -1483,6 +1490,7 @@
"purchase_server_description_2": "Stato di Contributore", "purchase_server_description_2": "Stato di Contributore",
"purchase_server_title": "Server", "purchase_server_title": "Server",
"purchase_settings_server_activated": "La chiave del prodotto del server è gestita dall'amministratore", "purchase_settings_server_activated": "La chiave del prodotto del server è gestita dall'amministratore",
"queue_status": "Messi in coda {count}/{total}",
"rating": "Valutazione a stelle", "rating": "Valutazione a stelle",
"rating_clear": "Crea valutazione", "rating_clear": "Crea valutazione",
"rating_count": "{count, plural, one {# stella} other {# stelle}}", "rating_count": "{count, plural, one {# stella} other {# stelle}}",
@@ -1518,6 +1526,7 @@
"remove_custom_date_range": "Rimuovi intervallo data personalizzato", "remove_custom_date_range": "Rimuovi intervallo data personalizzato",
"remove_deleted_assets": "Rimuovi file offline", "remove_deleted_assets": "Rimuovi file offline",
"remove_from_album": "Rimuovere dall'album", "remove_from_album": "Rimuovere dall'album",
"remove_from_album_action_prompt": "{count} elementi rimossi dall'album",
"remove_from_favorites": "Rimuovi dai preferiti", "remove_from_favorites": "Rimuovi dai preferiti",
"remove_from_lock_folder_action_prompt": "{count} elementi rimossi dalla cartella sicura", "remove_from_lock_folder_action_prompt": "{count} elementi rimossi dalla cartella sicura",
"remove_from_locked_folder": "Rimuovi dalla cartella privata", "remove_from_locked_folder": "Rimuovi dalla cartella privata",
@@ -1691,6 +1700,7 @@
"settings_saved": "Impostazioni salvate", "settings_saved": "Impostazioni salvate",
"setup_pin_code": "Configura un codice PIN", "setup_pin_code": "Configura un codice PIN",
"share": "Condivisione", "share": "Condivisione",
"share_action_prompt": "Condivisi {count} elementi",
"share_add_photos": "Aggiungi foto", "share_add_photos": "Aggiungi foto",
"share_assets_selected": "{count} selezionati", "share_assets_selected": "{count} selezionati",
"share_dialog_preparing": "Preparo…", "share_dialog_preparing": "Preparo…",
@@ -1792,6 +1802,7 @@
"sort_title": "Titolo", "sort_title": "Titolo",
"source": "Fonte", "source": "Fonte",
"stack": "Raggruppa", "stack": "Raggruppa",
"stack_action_prompt": "{count} elementi raggruppati",
"stack_duplicates": "Raggruppa i duplicati", "stack_duplicates": "Raggruppa i duplicati",
"stack_select_one_photo": "Seleziona una foto principale per il gruppo", "stack_select_one_photo": "Seleziona una foto principale per il gruppo",
"stack_selected_photos": "Impila foto selezionate", "stack_selected_photos": "Impila foto selezionate",
@@ -1880,6 +1891,7 @@
"unable_to_change_pin_code": "Impossibile cambiare il codice PIN", "unable_to_change_pin_code": "Impossibile cambiare il codice PIN",
"unable_to_setup_pin_code": "Impossibile configurare il codice PIN", "unable_to_setup_pin_code": "Impossibile configurare il codice PIN",
"unarchive": "Annulla l'archiviazione", "unarchive": "Annulla l'archiviazione",
"unarchive_action_prompt": "{count} elementi rimossi dall'Archivio",
"unarchived_count": "{count, plural, other {Non archiviati #}}", "unarchived_count": "{count, plural, other {Non archiviati #}}",
"undo": "Annulla", "undo": "Annulla",
"unfavorite": "Rimuovi preferito", "unfavorite": "Rimuovi preferito",

View File

@@ -707,6 +707,9 @@
"next_memory": "Nākamā atmiņa", "next_memory": "Nākamā atmiņa",
"no": "Nē", "no": "Nē",
"no_albums_message": "Izveido albumu, lai organizētu savas fotogrāfijas un video", "no_albums_message": "Izveido albumu, lai organizētu savas fotogrāfijas un video",
"no_albums_with_name_yet": "Izskatās, ka tev vēl nav albumu ar šādu nosaukumu.",
"no_albums_yet": "Izskatās, ka tev vēl nav neviena albuma.",
"no_archived_assets_message": "Arhivē fotoattēlus un videoklipus, lai paslēptu tos no Fotoattēli skata",
"no_assets_message": "NOKLIKŠĶINIET, LAI AUGŠUPIELĀDĒTU SAVU PIRMO FOTOATTĒLU", "no_assets_message": "NOKLIKŠĶINIET, LAI AUGŠUPIELĀDĒTU SAVU PIRMO FOTOATTĒLU",
"no_assets_to_show": "Nav uzrādāmo aktīvu", "no_assets_to_show": "Nav uzrādāmo aktīvu",
"no_duplicates_found": "Dublikāti netika atrasti.", "no_duplicates_found": "Dublikāti netika atrasti.",
@@ -730,6 +733,10 @@
"official_immich_resources": "Oficiālie Immich resursi", "official_immich_resources": "Oficiālie Immich resursi",
"offline": "Bezsaistē", "offline": "Bezsaistē",
"ok": "Labi", "ok": "Labi",
"onboarding": "Uzņemšana",
"onboarding_locale_description": "Izvēlies vēlamo valodu. To vēlāk var mainīt iestatījumos.",
"onboarding_theme_description": "Izvēlies savas instances krāsu motīvu. To vēlāk var mainīt iestatījumos.",
"onboarding_user_welcome_description": "Sāksim darbu!",
"online": "Tiešsaistē", "online": "Tiešsaistē",
"only_favorites": "Tikai izlase", "only_favorites": "Tikai izlase",
"open_in_map_view": "Atvērt kartes skatā", "open_in_map_view": "Atvērt kartes skatā",
@@ -737,13 +744,16 @@
"open_the_search_filters": "Atvērt meklēšanas filtrus", "open_the_search_filters": "Atvērt meklēšanas filtrus",
"options": "Iestatījumi", "options": "Iestatījumi",
"or": "vai", "or": "vai",
"organize_your_library": "Bibliotēkas organizēšana",
"original": "oriģināls", "original": "oriģināls",
"other": "Citi", "other": "Citi",
"other_devices": "Citas ierīces", "other_devices": "Citas ierīces",
"other_variables": "Citi mainīgie", "other_variables": "Citi mainīgie",
"owned": "Īpašumā", "owned": "Īpašumā",
"owner": "Īpašnieks", "owner": "Īpašnieks",
"partner": "Partneris",
"partner_can_access": "{partner} var piekļūt", "partner_can_access": "{partner} var piekļūt",
"partner_can_access_location": "Fotogrāfiju uzņemšanas vieta",
"partner_list_user_photos": "{user} fotoattēli", "partner_list_user_photos": "{user} fotoattēli",
"partner_list_view_all": "Apskatīt visu", "partner_list_view_all": "Apskatīt visu",
"partner_page_empty_message": "Jūsu fotogrāfijas pagaidām nav kopīgotas ar nevienu partneri.", "partner_page_empty_message": "Jūsu fotogrāfijas pagaidām nav kopīgotas ar nevienu partneri.",
@@ -757,6 +767,7 @@
"password_does_not_match": "Parole nesakrīt", "password_does_not_match": "Parole nesakrīt",
"path": "Ceļš", "path": "Ceļš",
"pause": "Pauzēt", "pause": "Pauzēt",
"pause_memories": "Pauzēt atmiņas",
"paused": "Nopauzēts", "paused": "Nopauzēts",
"people": "Cilvēki", "people": "Cilvēki",
"permission_onboarding_back": "Atpakaļ", "permission_onboarding_back": "Atpakaļ",

View File

@@ -573,6 +573,8 @@
"backup_options_page_title": "Backupinnstillinger", "backup_options_page_title": "Backupinnstillinger",
"backup_setting_subtitle": "Administrer opplastingsinnstillinger for bakgrunn og forgrunn", "backup_setting_subtitle": "Administrer opplastingsinnstillinger for bakgrunn og forgrunn",
"backward": "Bakover", "backward": "Bakover",
"beta_sync": "Beta synkroniseringsstatus",
"beta_sync_subtitle": "Håndter det nye synkroniseringssystemet",
"biometric_auth_enabled": "Biometrisk autentisering aktivert", "biometric_auth_enabled": "Biometrisk autentisering aktivert",
"biometric_locked_out": "Du er låst ute av biometrisk verifisering", "biometric_locked_out": "Du er låst ute av biometrisk verifisering",
"biometric_no_options": "Ingen biometriske valg tilgjengelige", "biometric_no_options": "Ingen biometriske valg tilgjengelige",
@@ -590,7 +592,7 @@
"cache_settings_clear_cache_button": "Tøm buffer", "cache_settings_clear_cache_button": "Tøm buffer",
"cache_settings_clear_cache_button_title": "Tømmer app-ens buffer. Dette vil ha betydelig innvirkning på appens ytelse inntil bufferen er gjenoppbygd.", "cache_settings_clear_cache_button_title": "Tømmer app-ens buffer. Dette vil ha betydelig innvirkning på appens ytelse inntil bufferen er gjenoppbygd.",
"cache_settings_duplicated_assets_clear_button": "TØM", "cache_settings_duplicated_assets_clear_button": "TØM",
"cache_settings_duplicated_assets_subtitle": "Bilder og videoer som er svartelistet av app'en", "cache_settings_duplicated_assets_subtitle": "Bilder og videoer som er ignorert av app'en",
"cache_settings_duplicated_assets_title": "Dupliserte objekter ({count})", "cache_settings_duplicated_assets_title": "Dupliserte objekter ({count})",
"cache_settings_statistics_album": "Bibliotekminiatyrbilder", "cache_settings_statistics_album": "Bibliotekminiatyrbilder",
"cache_settings_statistics_full": "Originalbilder", "cache_settings_statistics_full": "Originalbilder",
@@ -1051,6 +1053,9 @@
"haptic_feedback_switch": "Aktivert haptisk tilbakemelding", "haptic_feedback_switch": "Aktivert haptisk tilbakemelding",
"haptic_feedback_title": "Haptisk tilbakemelding", "haptic_feedback_title": "Haptisk tilbakemelding",
"has_quota": "Kvote", "has_quota": "Kvote",
"hash_asset": "Hash objekter",
"hashed_assets": "Hashede objekter",
"hashing": "Hasher",
"header_settings_add_header_tip": "Legg til header", "header_settings_add_header_tip": "Legg til header",
"header_settings_field_validator_msg": "Verdi kan ikke være null", "header_settings_field_validator_msg": "Verdi kan ikke være null",
"header_settings_header_name_input": "Header navn", "header_settings_header_name_input": "Header navn",
@@ -1083,6 +1088,7 @@
"host": "Vert", "host": "Vert",
"hour": "Time", "hour": "Time",
"id": "ID", "id": "ID",
"idle": "Uvirksom",
"ignore_icloud_photos": "Ignorer iCloud bilder", "ignore_icloud_photos": "Ignorer iCloud bilder",
"ignore_icloud_photos_description": "Bilder som er lagret på iCloud vil ikke lastes opp til Immich", "ignore_icloud_photos_description": "Bilder som er lagret på iCloud vil ikke lastes opp til Immich",
"image": "Bilde", "image": "Bilde",
@@ -1165,7 +1171,9 @@
"list": "Liste", "list": "Liste",
"loading": "Laster", "loading": "Laster",
"loading_search_results_failed": "Klarte ikke å laste inn søkeresultater", "loading_search_results_failed": "Klarte ikke å laste inn søkeresultater",
"local": "Lokal",
"local_asset_cast_failed": "Kan ikke caste et bilde som ikke er lastet opp til serveren", "local_asset_cast_failed": "Kan ikke caste et bilde som ikke er lastet opp til serveren",
"local_assets": "Lokale objekter",
"local_network": "Lokalt nettverk", "local_network": "Lokalt nettverk",
"local_network_sheet_info": "Appen vil koble til serveren via denne URL-en når du bruker det angitte Wi-Fi-nettverket", "local_network_sheet_info": "Appen vil koble til serveren via denne URL-en når du bruker det angitte Wi-Fi-nettverket",
"location_permission": "Stedstillatelse", "location_permission": "Stedstillatelse",
@@ -1322,6 +1330,7 @@
"no_results": "Ingen resultater", "no_results": "Ingen resultater",
"no_results_description": "Prøv et synonym eller mer generelt søkeord", "no_results_description": "Prøv et synonym eller mer generelt søkeord",
"no_shared_albums_message": "Opprett et album for å dele bilder og videoer med personer i nettverket ditt", "no_shared_albums_message": "Opprett et album for å dele bilder og videoer med personer i nettverket ditt",
"no_uploads_in_progress": "Ingen opplasting pågår",
"not_in_any_album": "Ikke i noe album", "not_in_any_album": "Ikke i noe album",
"not_selected": "Ikke valgt", "not_selected": "Ikke valgt",
"note_apply_storage_label_to_previously_uploaded assets": "Merk: For å bruke lagringsetiketten på tidligere opplastede filer, kjør", "note_apply_storage_label_to_previously_uploaded assets": "Merk: For å bruke lagringsetiketten på tidligere opplastede filer, kjør",
@@ -1359,6 +1368,7 @@
"original": "original", "original": "original",
"other": "Annet", "other": "Annet",
"other_devices": "Andre enheter", "other_devices": "Andre enheter",
"other_entities": "Andre objekter",
"other_variables": "Andre variabler", "other_variables": "Andre variabler",
"owned": "Dine", "owned": "Dine",
"owner": "Eier", "owner": "Eier",
@@ -1519,6 +1529,8 @@
"refreshing_faces": "Oppdaterer ansikter", "refreshing_faces": "Oppdaterer ansikter",
"refreshing_metadata": "Oppdaterer matadata", "refreshing_metadata": "Oppdaterer matadata",
"regenerating_thumbnails": "Regenererer miniatyrbilder", "regenerating_thumbnails": "Regenererer miniatyrbilder",
"remote": "Eksternt",
"remote_assets": "Eksterne objekter",
"remove": "Fjern", "remove": "Fjern",
"remove_assets_album_confirmation": "Er du sikker på at du fil slette {count, plural, one {# asset} other {# assets}} fra albumet?", "remove_assets_album_confirmation": "Er du sikker på at du fil slette {count, plural, one {# asset} other {# assets}} fra albumet?",
"remove_assets_shared_link_confirmation": "Er du sikker på at du vil slette {count, plural, one {# asset} other {# assets}} fra den delte lenken?", "remove_assets_shared_link_confirmation": "Er du sikker på at du vil slette {count, plural, one {# asset} other {# assets}} fra den delte lenken?",
@@ -1556,11 +1568,15 @@
"reset_password": "Tilbakestill passord", "reset_password": "Tilbakestill passord",
"reset_people_visibility": "Tilbakestill personsynlighet", "reset_people_visibility": "Tilbakestill personsynlighet",
"reset_pin_code": "Resett PINkode", "reset_pin_code": "Resett PINkode",
"reset_sqlite": "Reset SQLite Databasen",
"reset_sqlite_confirmation": "Er du sikker på at du vil resette SQLite databasen? Du blir nødt til å logge ut og inn igjen for å resynkronisere data",
"reset_sqlite_success": "Vellykket resetting av SQLite databasen",
"reset_to_default": "Tilbakestill til standard", "reset_to_default": "Tilbakestill til standard",
"resolve_duplicates": "Løs duplikater", "resolve_duplicates": "Løs duplikater",
"resolved_all_duplicates": "Løste alle duplikater", "resolved_all_duplicates": "Løste alle duplikater",
"restore": "Gjenopprett", "restore": "Gjenopprett",
"restore_all": "Gjenopprett alle", "restore_all": "Gjenopprett alle",
"restore_trash_action_prompt": "{count} gjenopprettet fra søppelbøtten",
"restore_user": "Gjenopprett bruker", "restore_user": "Gjenopprett bruker",
"restored_asset": "Gjenopprettet ressurs", "restored_asset": "Gjenopprettet ressurs",
"resume": "Fortsett", "resume": "Fortsett",
@@ -1569,6 +1585,7 @@
"role": "Rolle", "role": "Rolle",
"role_editor": "Redigerer", "role_editor": "Redigerer",
"role_viewer": "Visning", "role_viewer": "Visning",
"running": "Kjører",
"save": "Lagre", "save": "Lagre",
"save_to_gallery": "Lagre til galleriet", "save_to_gallery": "Lagre til galleriet",
"saved_api_key": "Lagret API-nøkkel", "saved_api_key": "Lagret API-nøkkel",
@@ -1822,6 +1839,7 @@
"storage_quota": "Lagringsplass", "storage_quota": "Lagringsplass",
"storage_usage": "{used} av {available} brukt", "storage_usage": "{used} av {available} brukt",
"submit": "Send inn", "submit": "Send inn",
"success": "Vellykket",
"suggestions": "Forslag", "suggestions": "Forslag",
"sunrise_on_the_beach": "Soloppgang på stranden", "sunrise_on_the_beach": "Soloppgang på stranden",
"support": "Støtte", "support": "Støtte",
@@ -1831,6 +1849,8 @@
"sync": "Synkroniser", "sync": "Synkroniser",
"sync_albums": "Synkroniser albumer", "sync_albums": "Synkroniser albumer",
"sync_albums_manual_subtitle": "Synkroniser alle opplastede videoer og bilder til det valgte backupalbumet", "sync_albums_manual_subtitle": "Synkroniser alle opplastede videoer og bilder til det valgte backupalbumet",
"sync_local": "Synkroniser lokalt",
"sync_remote": "Synkroniser eksternt",
"sync_upload_album_setting_subtitle": "Opprett og last opp dine bilder og videoer til det valgte albumet på Immich", "sync_upload_album_setting_subtitle": "Opprett og last opp dine bilder og videoer til det valgte albumet på Immich",
"tag": "Tagg", "tag": "Tagg",
"tag_assets": "Merk ressurser", "tag_assets": "Merk ressurser",
@@ -1841,6 +1861,7 @@
"tag_updated": "Oppdater merke: {tag}", "tag_updated": "Oppdater merke: {tag}",
"tagged_assets": "Merket {count, plural, one {# asset} other {# assets}}", "tagged_assets": "Merket {count, plural, one {# asset} other {# assets}}",
"tags": "Merker", "tags": "Merker",
"tap_to_run_job": "Trykk for å kjøre jobben",
"template": "Mal", "template": "Mal",
"theme": "Tema", "theme": "Tema",
"theme_selection": "Temavalg", "theme_selection": "Temavalg",

View File

@@ -426,6 +426,7 @@
"albums_default_sort_order": "Standaard sorteervolgorde album", "albums_default_sort_order": "Standaard sorteervolgorde album",
"albums_default_sort_order_description": "Initiële sorteervolgorde bij het maken van nieuwe albums.", "albums_default_sort_order_description": "Initiële sorteervolgorde bij het maken van nieuwe albums.",
"albums_feature_description": "Collectie van assets die je kan delen met andere gebruikers.", "albums_feature_description": "Collectie van assets die je kan delen met andere gebruikers.",
"albums_on_device_count": "Albums op apparaat ({count})",
"all": "Alle", "all": "Alle",
"all_albums": "Alle albums", "all_albums": "Alle albums",
"all_people": "Alle mensen", "all_people": "Alle mensen",
@@ -572,6 +573,8 @@
"backup_options_page_title": "Back-up instellingen", "backup_options_page_title": "Back-up instellingen",
"backup_setting_subtitle": "Beheer achtergrond en voorgrond uploadinstellingen", "backup_setting_subtitle": "Beheer achtergrond en voorgrond uploadinstellingen",
"backward": "Achteruit", "backward": "Achteruit",
"beta_sync": "Beta Sync Status",
"beta_sync_subtitle": "Beheer het nieuwe synchronisatiesysteem",
"biometric_auth_enabled": "Biometrische authenticatie ingeschakeld", "biometric_auth_enabled": "Biometrische authenticatie ingeschakeld",
"biometric_locked_out": "Biometrische authenticatie is vergrendeld", "biometric_locked_out": "Biometrische authenticatie is vergrendeld",
"biometric_no_options": "Geen biometrische opties beschikbaar", "biometric_no_options": "Geen biometrische opties beschikbaar",
@@ -589,7 +592,7 @@
"cache_settings_clear_cache_button": "Cache wissen", "cache_settings_clear_cache_button": "Cache wissen",
"cache_settings_clear_cache_button_title": "Wist de cache van de app. Dit zal de presentaties van de app aanzienlijk beïnvloeden totdat de cache opnieuw is opgebouwd.", "cache_settings_clear_cache_button_title": "Wist de cache van de app. Dit zal de presentaties van de app aanzienlijk beïnvloeden totdat de cache opnieuw is opgebouwd.",
"cache_settings_duplicated_assets_clear_button": "MAAK VRIJ", "cache_settings_duplicated_assets_clear_button": "MAAK VRIJ",
"cache_settings_duplicated_assets_subtitle": "Foto's en video's op de zwarte lijst van de app", "cache_settings_duplicated_assets_subtitle": "Fotos en video's die de app negeert",
"cache_settings_duplicated_assets_title": "Gedupliceerde assets ({count})", "cache_settings_duplicated_assets_title": "Gedupliceerde assets ({count})",
"cache_settings_statistics_album": "Bibliotheekthumbnails", "cache_settings_statistics_album": "Bibliotheekthumbnails",
"cache_settings_statistics_full": "Volledige afbeeldingen", "cache_settings_statistics_full": "Volledige afbeeldingen",
@@ -1050,6 +1053,9 @@
"haptic_feedback_switch": "Aanraaktrillingen inschakelen", "haptic_feedback_switch": "Aanraaktrillingen inschakelen",
"haptic_feedback_title": "Aanraaktrillingen", "haptic_feedback_title": "Aanraaktrillingen",
"has_quota": "Heeft limiet", "has_quota": "Heeft limiet",
"hash_asset": "Hash asset",
"hashed_assets": "Gehashte assets",
"hashing": "Hashen",
"header_settings_add_header_tip": "Header toevoegen", "header_settings_add_header_tip": "Header toevoegen",
"header_settings_field_validator_msg": "Waarde kan niet leeg zijn", "header_settings_field_validator_msg": "Waarde kan niet leeg zijn",
"header_settings_header_name_input": "Header naam", "header_settings_header_name_input": "Header naam",
@@ -1082,6 +1088,7 @@
"host": "Host", "host": "Host",
"hour": "Uur", "hour": "Uur",
"id": "ID", "id": "ID",
"idle": "Idle",
"ignore_icloud_photos": "Negeer iCloud foto's", "ignore_icloud_photos": "Negeer iCloud foto's",
"ignore_icloud_photos_description": "Foto's die op iCloud zijn opgeslagen, worden niet geüpload naar de Immich server", "ignore_icloud_photos_description": "Foto's die op iCloud zijn opgeslagen, worden niet geüpload naar de Immich server",
"image": "Afbeelding", "image": "Afbeelding",
@@ -1164,7 +1171,9 @@
"list": "Lijst", "list": "Lijst",
"loading": "Laden", "loading": "Laden",
"loading_search_results_failed": "Laden van zoekresultaten mislukt", "loading_search_results_failed": "Laden van zoekresultaten mislukt",
"local": "Lokaal",
"local_asset_cast_failed": "Kan geen asset casten die nog niet geüpload is naar de server", "local_asset_cast_failed": "Kan geen asset casten die nog niet geüpload is naar de server",
"local_assets": "Lokale Assets",
"local_network": "Lokaal netwerk", "local_network": "Lokaal netwerk",
"local_network_sheet_info": "De app maakt verbinding met de server via deze URL wanneer het opgegeven WiFi-netwerk wordt gebruikt", "local_network_sheet_info": "De app maakt verbinding met de server via deze URL wanneer het opgegeven WiFi-netwerk wordt gebruikt",
"location_permission": "Locatietoestemming", "location_permission": "Locatietoestemming",
@@ -1321,6 +1330,7 @@
"no_results": "Geen resultaten", "no_results": "Geen resultaten",
"no_results_description": "Probeer een synoniem of een algemener zoekwoord", "no_results_description": "Probeer een synoniem of een algemener zoekwoord",
"no_shared_albums_message": "Maak een album om foto's en video's te delen met mensen in je netwerk", "no_shared_albums_message": "Maak een album om foto's en video's te delen met mensen in je netwerk",
"no_uploads_in_progress": "Geen uploads bezig",
"not_in_any_album": "Niet in een album", "not_in_any_album": "Niet in een album",
"not_selected": "Niet geselecteerd", "not_selected": "Niet geselecteerd",
"note_apply_storage_label_to_previously_uploaded assets": "Opmerking: om het opslaglabel toe te passen op eerder geüploade assets, voer de volgende taak uit", "note_apply_storage_label_to_previously_uploaded assets": "Opmerking: om het opslaglabel toe te passen op eerder geüploade assets, voer de volgende taak uit",
@@ -1358,6 +1368,7 @@
"original": "origineel", "original": "origineel",
"other": "Overige", "other": "Overige",
"other_devices": "Andere apparaten", "other_devices": "Andere apparaten",
"other_entities": "Andere entities",
"other_variables": "Andere variabelen", "other_variables": "Andere variabelen",
"owned": "Eigenaar", "owned": "Eigenaar",
"owner": "Eigenaar", "owner": "Eigenaar",
@@ -1518,6 +1529,8 @@
"refreshing_faces": "Gezichten aan het vernieuwen", "refreshing_faces": "Gezichten aan het vernieuwen",
"refreshing_metadata": "Metadata aan het vernieuwen", "refreshing_metadata": "Metadata aan het vernieuwen",
"regenerating_thumbnails": "Thumbnails opnieuw aan het genereren", "regenerating_thumbnails": "Thumbnails opnieuw aan het genereren",
"remote": "Remote",
"remote_assets": "Remote Assets",
"remove": "Verwijderen", "remove": "Verwijderen",
"remove_assets_album_confirmation": "Weet je zeker dat je {count, plural, one {# asset} other {# assets}} uit het album wilt verwijderen?", "remove_assets_album_confirmation": "Weet je zeker dat je {count, plural, one {# asset} other {# assets}} uit het album wilt verwijderen?",
"remove_assets_shared_link_confirmation": "Weet je zeker dat je {count, plural, one {# asset} other {# assets}} uit deze gedeelde link wilt verwijderen?", "remove_assets_shared_link_confirmation": "Weet je zeker dat je {count, plural, one {# asset} other {# assets}} uit deze gedeelde link wilt verwijderen?",
@@ -1555,11 +1568,15 @@
"reset_password": "Wachtwoord resetten", "reset_password": "Wachtwoord resetten",
"reset_people_visibility": "Zichtbaarheid mensen resetten", "reset_people_visibility": "Zichtbaarheid mensen resetten",
"reset_pin_code": "Reset PIN code", "reset_pin_code": "Reset PIN code",
"reset_sqlite": "Reset SQLite Database",
"reset_sqlite_confirmation": "Ben je zeker dat je de SQLite database wilt resetten? Je zal moetenn uitloggen om de data opnieuw te synchroniseren.",
"reset_sqlite_success": "De SQLite database is succesvol gereset",
"reset_to_default": "Resetten naar standaard", "reset_to_default": "Resetten naar standaard",
"resolve_duplicates": "Duplicaten oplossen", "resolve_duplicates": "Duplicaten oplossen",
"resolved_all_duplicates": "Alle duplicaten opgelost", "resolved_all_duplicates": "Alle duplicaten opgelost",
"restore": "Herstellen", "restore": "Herstellen",
"restore_all": "Herstel alle", "restore_all": "Herstel alle",
"restore_trash_action_prompt": "{count} teruggezet uit prullenbak",
"restore_user": "Gebruiker herstellen", "restore_user": "Gebruiker herstellen",
"restored_asset": "Asset hersteld", "restored_asset": "Asset hersteld",
"resume": "Hervatten", "resume": "Hervatten",
@@ -1568,6 +1585,7 @@
"role": "Rol", "role": "Rol",
"role_editor": "Bewerker", "role_editor": "Bewerker",
"role_viewer": "Bekijker", "role_viewer": "Bekijker",
"running": "Actief",
"save": "Opslaan", "save": "Opslaan",
"save_to_gallery": "Opslaan in galerij", "save_to_gallery": "Opslaan in galerij",
"saved_api_key": "API-sleutel opgeslagen", "saved_api_key": "API-sleutel opgeslagen",
@@ -1821,6 +1839,7 @@
"storage_quota": "Opslaglimiet", "storage_quota": "Opslaglimiet",
"storage_usage": "{used} van {available} gebruikt", "storage_usage": "{used} van {available} gebruikt",
"submit": "Verzenden", "submit": "Verzenden",
"success": "Succes",
"suggestions": "Suggesties", "suggestions": "Suggesties",
"sunrise_on_the_beach": "Zonsopkomst op het strand", "sunrise_on_the_beach": "Zonsopkomst op het strand",
"support": "Ondersteuning", "support": "Ondersteuning",
@@ -1830,6 +1849,8 @@
"sync": "Sync", "sync": "Sync",
"sync_albums": "Albums synchroniseren", "sync_albums": "Albums synchroniseren",
"sync_albums_manual_subtitle": "Synchroniseer alle geüploade videos en fotos naar de geselecteerde back-up albums", "sync_albums_manual_subtitle": "Synchroniseer alle geüploade videos en fotos naar de geselecteerde back-up albums",
"sync_local": "Lokaal synchroniseren",
"sync_remote": "Op afstand synchroniseren",
"sync_upload_album_setting_subtitle": "Maak en upload je foto's en video's naar de geselecteerde albums op Immich", "sync_upload_album_setting_subtitle": "Maak en upload je foto's en video's naar de geselecteerde albums op Immich",
"tag": "Tag", "tag": "Tag",
"tag_assets": "Assets taggen", "tag_assets": "Assets taggen",
@@ -1840,6 +1861,7 @@
"tag_updated": "Tag bijgewerkt: {tag}", "tag_updated": "Tag bijgewerkt: {tag}",
"tagged_assets": "{count, plural, one {# asset} other {# assets}} getagd", "tagged_assets": "{count, plural, one {# asset} other {# assets}} getagd",
"tags": "Tags", "tags": "Tags",
"tap_to_run_job": "Klik om job te starten",
"template": "Template", "template": "Template",
"theme": "Thema", "theme": "Thema",
"theme_selection": "Thema selectie", "theme_selection": "Thema selectie",

View File

@@ -228,7 +228,7 @@
"password_settings_description": "Управление настройками входа по паролю", "password_settings_description": "Управление настройками входа по паролю",
"paths_validated_successfully": "Все пути успешно прошли проверку", "paths_validated_successfully": "Все пути успешно прошли проверку",
"person_cleanup_job": "Очистка персоны", "person_cleanup_job": "Очистка персоны",
"quota_size_gib": "Размер квоты (ГБ)", "quota_size_gib": "Размер квоты (GiB)",
"refreshing_all_libraries": "Обновление всех библиотек", "refreshing_all_libraries": "Обновление всех библиотек",
"registration": "Регистрация администратора", "registration": "Регистрация администратора",
"registration_description": "Первый зарегистрированный пользователь будет назначен администратором. В дальнейшем этой учетной записи будет доступно создание дополнительных пользователей и управление сервером.", "registration_description": "Первый зарегистрированный пользователь будет назначен администратором. В дальнейшем этой учетной записи будет доступно создание дополнительных пользователей и управление сервером.",
@@ -241,7 +241,7 @@
"server_external_domain_settings": "Внешний домен", "server_external_domain_settings": "Внешний домен",
"server_external_domain_settings_description": "Домен для публичных ссылок, включая http(s)://", "server_external_domain_settings_description": "Домен для публичных ссылок, включая http(s)://",
"server_public_users": "Публичные пользователи", "server_public_users": "Публичные пользователи",
"server_public_users_description": "Отображать всех пользователей (имена и email) для добавления в общие альбомы. Когда отключено, список пользователей будет доступен только администраторам.", "server_public_users_description": "Выводить список пользователей (имена и email) в общих альбомах. Когда отключено, список доступен только администраторам, пользователи смогут делиться только ссылкой.",
"server_settings": "Настройки сервера", "server_settings": "Настройки сервера",
"server_settings_description": "Управление настройками сервера", "server_settings_description": "Управление настройками сервера",
"server_welcome_message": "Приветственное сообщение", "server_welcome_message": "Приветственное сообщение",
@@ -407,7 +407,7 @@
"album_remove_user": "Удалить пользователя?", "album_remove_user": "Удалить пользователя?",
"album_remove_user_confirmation": "Вы уверены, что хотите удалить пользователя {user}?", "album_remove_user_confirmation": "Вы уверены, что хотите удалить пользователя {user}?",
"album_search_not_found": "Не найдено альбомов по вашему запросу", "album_search_not_found": "Не найдено альбомов по вашему запросу",
"album_share_no_users": "Похоже, вы поделились этим альбомом со всеми пользователями или у вас нет пользователей, с которыми можно поделиться.", "album_share_no_users": "Нет доступных пользователей, с которыми можно поделиться альбомом.",
"album_updated": "Альбом обновлён", "album_updated": "Альбом обновлён",
"album_updated_setting_description": "Получать уведомление по электронной почте при добавлении новых ресурсов в общий альбом", "album_updated_setting_description": "Получать уведомление по электронной почте при добавлении новых ресурсов в общий альбом",
"album_user_left": "Вы покинули {album}", "album_user_left": "Вы покинули {album}",
@@ -433,8 +433,8 @@
"all_videos": "Все видео", "all_videos": "Все видео",
"allow_dark_mode": "Разрешить темный режим", "allow_dark_mode": "Разрешить темный режим",
"allow_edits": "Разрешить редактирование", "allow_edits": "Разрешить редактирование",
"allow_public_user_to_download": "Разрешить скачивание публичным пользователям", "allow_public_user_to_download": "Разрешить скачивание",
"allow_public_user_to_upload": "Разрешить публичным пользователям загружать файлы", "allow_public_user_to_upload": "Разрешить добавление файлов",
"alt_text_qr_code": "QR-код", "alt_text_qr_code": "QR-код",
"anti_clockwise": "Против часовой", "anti_clockwise": "Против часовой",
"api_key": "API ключ", "api_key": "API ключ",
@@ -573,6 +573,8 @@
"backup_options_page_title": "Резервное копирование", "backup_options_page_title": "Резервное копирование",
"backup_setting_subtitle": "Настройка активного и фонового резервного копирования", "backup_setting_subtitle": "Настройка активного и фонового резервного копирования",
"backward": "Назад", "backward": "Назад",
"beta_sync": "Статус бета-синхронизации",
"beta_sync_subtitle": "Управление новой системой синхронизации",
"biometric_auth_enabled": "Биометрическая аутентификация включена", "biometric_auth_enabled": "Биометрическая аутентификация включена",
"biometric_locked_out": "Вам закрыт доступ к биометрической аутентификации", "biometric_locked_out": "Вам закрыт доступ к биометрической аутентификации",
"biometric_no_options": "Биометрическая аутентификация недоступна", "biometric_no_options": "Биометрическая аутентификация недоступна",
@@ -590,7 +592,7 @@
"cache_settings_clear_cache_button": "Очистить кэш", "cache_settings_clear_cache_button": "Очистить кэш",
"cache_settings_clear_cache_button_title": "Очищает кэш приложения. Это негативно повлияет на производительность, пока кэш не будет создан заново.", "cache_settings_clear_cache_button_title": "Очищает кэш приложения. Это негативно повлияет на производительность, пока кэш не будет создан заново.",
"cache_settings_duplicated_assets_clear_button": "ОЧИСТИТЬ", "cache_settings_duplicated_assets_clear_button": "ОЧИСТИТЬ",
"cache_settings_duplicated_assets_subtitle": "Фото и видео, занесенные приложением в черный список", "cache_settings_duplicated_assets_subtitle": "Фото и видео, пропускаемые приложением",
"cache_settings_duplicated_assets_title": "Дублирующиеся объекты ({count})", "cache_settings_duplicated_assets_title": "Дублирующиеся объекты ({count})",
"cache_settings_statistics_album": "Миниатюры библиотеки", "cache_settings_statistics_album": "Миниатюры библиотеки",
"cache_settings_statistics_full": "Полные изображения", "cache_settings_statistics_full": "Полные изображения",
@@ -616,7 +618,7 @@
"change_date": "Изменить дату", "change_date": "Изменить дату",
"change_description": "Изменить описание", "change_description": "Изменить описание",
"change_display_order": "Изменить порядок отображения", "change_display_order": "Изменить порядок отображения",
"change_expiration_time": "Изменить время окончания", "change_expiration_time": "Изменить срок действия",
"change_location": "Изменить местоположение", "change_location": "Изменить местоположение",
"change_name": "Изменить имя", "change_name": "Изменить имя",
"change_name_successfully": "Имя успешно изменено", "change_name_successfully": "Имя успешно изменено",
@@ -692,7 +694,7 @@
"copy_link": "Копировать ссылку", "copy_link": "Копировать ссылку",
"copy_link_to_clipboard": "Скопировать ссылку в буфер обмена", "copy_link_to_clipboard": "Скопировать ссылку в буфер обмена",
"copy_password": "Скопировать пароль", "copy_password": "Скопировать пароль",
"copy_to_clipboard": "Скопировать в буфер обмена", "copy_to_clipboard": "Скопировать настройки в буфер обмена",
"country": "Страна", "country": "Страна",
"cover": "Обложка", "cover": "Обложка",
"covers": "Обложки", "covers": "Обложки",
@@ -830,7 +832,7 @@
"edit_people": "Редактировать людей", "edit_people": "Редактировать людей",
"edit_tag": "Изменить тег", "edit_tag": "Изменить тег",
"edit_title": "Редактировать Заголовок", "edit_title": "Редактировать Заголовок",
"edit_user": "Редактирование пользователя", "edit_user": "Изменить пользователя",
"edited": "Отредактировано", "edited": "Отредактировано",
"editor": "Редактор", "editor": "Редактор",
"editor_close_without_save_prompt": "Изменения не будут сохранены", "editor_close_without_save_prompt": "Изменения не будут сохранены",
@@ -994,7 +996,7 @@
"experimental_settings_subtitle": "Используйте на свой страх и риск!", "experimental_settings_subtitle": "Используйте на свой страх и риск!",
"experimental_settings_title": "Экспериментальные функции", "experimental_settings_title": "Экспериментальные функции",
"expire_after": "Истекает через", "expire_after": "Истекает через",
"expired": "Срок действия истек", "expired": "Срок действия истёк",
"expires_date": "Срок действия до {date}", "expires_date": "Срок действия до {date}",
"explore": "Поиск", "explore": "Поиск",
"explorer": "Проводник", "explorer": "Проводник",
@@ -1051,6 +1053,9 @@
"haptic_feedback_switch": "Включить тактильную отдачу", "haptic_feedback_switch": "Включить тактильную отдачу",
"haptic_feedback_title": "Тактильная отдача", "haptic_feedback_title": "Тактильная отдача",
"has_quota": "Квота", "has_quota": "Квота",
"hash_asset": "Хешированный объект",
"hashed_assets": "Хешированные объекты",
"hashing": "Хеширование",
"header_settings_add_header_tip": "Добавить заголовок", "header_settings_add_header_tip": "Добавить заголовок",
"header_settings_field_validator_msg": "Значение не может быть пустым", "header_settings_field_validator_msg": "Значение не может быть пустым",
"header_settings_header_name_input": "Имя заголовка", "header_settings_header_name_input": "Имя заголовка",
@@ -1083,6 +1088,7 @@
"host": "Хост", "host": "Хост",
"hour": "Час", "hour": "Час",
"id": "ID", "id": "ID",
"idle": "В ожидании",
"ignore_icloud_photos": "Пропускать файлы из iCloud", "ignore_icloud_photos": "Пропускать файлы из iCloud",
"ignore_icloud_photos_description": "Не загружать файлы в Immich, если они хранятся в iCloud", "ignore_icloud_photos_description": "Не загружать файлы в Immich, если они хранятся в iCloud",
"image": "Изображения", "image": "Изображения",
@@ -1109,8 +1115,8 @@
"include_archived": "Отображать архив", "include_archived": "Отображать архив",
"include_shared_albums": "Включать общие альбомы", "include_shared_albums": "Включать общие альбомы",
"include_shared_partner_assets": "Включать общие ресурсы партнера", "include_shared_partner_assets": "Включать общие ресурсы партнера",
"individual_share": "Персональный доступ", "individual_share": "Индивидуальная подборка",
"individual_shares": "Индивидуальный доступ", "individual_shares": "Подборки",
"info": "Информация", "info": "Информация",
"interval": { "interval": {
"day_at_onepm": "Каждый день в 13:00", "day_at_onepm": "Каждый день в 13:00",
@@ -1165,7 +1171,9 @@
"list": "Список", "list": "Список",
"loading": "Загрузка", "loading": "Загрузка",
"loading_search_results_failed": "Загрузка результатов поиска не удалась", "loading_search_results_failed": "Загрузка результатов поиска не удалась",
"local": "На устройстве",
"local_asset_cast_failed": "Невозможно транслировать объект, который ещё не загружен на сервер", "local_asset_cast_failed": "Невозможно транслировать объект, который ещё не загружен на сервер",
"local_assets": "Объекты на устройстве",
"local_network": "Локальная сеть", "local_network": "Локальная сеть",
"local_network_sheet_info": "Приложение будет подключаться к серверу по этому адресу, когда устройство подключено к выбранной Wi-Fi сети", "local_network_sheet_info": "Приложение будет подключаться к серверу по этому адресу, когда устройство подключено к выбранной Wi-Fi сети",
"location_permission": "Доступ к местоположению", "location_permission": "Доступ к местоположению",
@@ -1322,6 +1330,7 @@
"no_results": "Нет результатов", "no_results": "Нет результатов",
"no_results_description": "Попробуйте использовать синоним или более общее ключевое слово", "no_results_description": "Попробуйте использовать синоним или более общее ключевое слово",
"no_shared_albums_message": "Создайте альбом для обмена фотографиями и видеозаписями с людьми в вашей сети", "no_shared_albums_message": "Создайте альбом для обмена фотографиями и видеозаписями с людьми в вашей сети",
"no_uploads_in_progress": "Нет активных загрузок",
"not_in_any_album": "Ни в одном альбоме", "not_in_any_album": "Ни в одном альбоме",
"not_selected": "Не выбрано", "not_selected": "Не выбрано",
"note_apply_storage_label_to_previously_uploaded assets": "Примечание: Чтобы применить метку хранилища к ранее загруженным ресурсам, запустите", "note_apply_storage_label_to_previously_uploaded assets": "Примечание: Чтобы применить метку хранилища к ранее загруженным ресурсам, запустите",
@@ -1359,6 +1368,7 @@
"original": "оригинал", "original": "оригинал",
"other": "Другое", "other": "Другое",
"other_devices": "Другие устройства", "other_devices": "Другие устройства",
"other_entities": "Другие объекты",
"other_variables": "Другие переменные", "other_variables": "Другие переменные",
"owned": "Мои", "owned": "Мои",
"owner": "Владелец", "owner": "Владелец",
@@ -1456,7 +1466,7 @@
"profile_drawer_server_out_of_date_minor": "Версия сервера устарела. Пожалуйста, обновите его.", "profile_drawer_server_out_of_date_minor": "Версия сервера устарела. Пожалуйста, обновите его.",
"profile_image_of_user": "Изображение профиля {user}", "profile_image_of_user": "Изображение профиля {user}",
"profile_picture_set": "Фото профиля установлено.", "profile_picture_set": "Фото профиля установлено.",
"public_album": "Публичный альбом", "public_album": "Общий альбом",
"public_share": "Публичный доступ", "public_share": "Публичный доступ",
"purchase_account_info": "Поддержка", "purchase_account_info": "Поддержка",
"purchase_activated_subtitle": "Благодарим вас за поддержку Immich и программного обеспечения с открытым исходным кодом", "purchase_activated_subtitle": "Благодарим вас за поддержку Immich и программного обеспечения с открытым исходным кодом",
@@ -1519,6 +1529,8 @@
"refreshing_faces": "Обновление лиц", "refreshing_faces": "Обновление лиц",
"refreshing_metadata": "Обновление метаданных", "refreshing_metadata": "Обновление метаданных",
"regenerating_thumbnails": "Восстановление миниатюр", "regenerating_thumbnails": "Восстановление миниатюр",
"remote": "На сервере",
"remote_assets": "Объекты на сервере",
"remove": "Удалить", "remove": "Удалить",
"remove_assets_album_confirmation": "Вы действительно хотите удалить {count, plural, one {# объект} many {# объектов} other {# объекта}} из альбома?", "remove_assets_album_confirmation": "Вы действительно хотите удалить {count, plural, one {# объект} many {# объектов} other {# объекта}} из альбома?",
"remove_assets_shared_link_confirmation": "Вы действительно хотите удалить {count, plural, one {# объект} many {# объектов} other {# объекта}} из публичного доступа по этой ссылке?", "remove_assets_shared_link_confirmation": "Вы действительно хотите удалить {count, plural, one {# объект} many {# объектов} other {# объекта}} из публичного доступа по этой ссылке?",
@@ -1556,11 +1568,15 @@
"reset_password": "Сброс пароля", "reset_password": "Сброс пароля",
"reset_people_visibility": "Восстановить видимость людей", "reset_people_visibility": "Восстановить видимость людей",
"reset_pin_code": "Сбросить PIN-код", "reset_pin_code": "Сбросить PIN-код",
"reset_sqlite": "Очистить базу данных SQLite",
"reset_sqlite_confirmation": "Вы уверены, что хотите очистить базу данных SQLite? Вам потребуется выйти из системы и снова войти для повторной синхронизации данных.",
"reset_sqlite_success": "База данных SQLite успешно очищена",
"reset_to_default": "Восстановление значений по умолчанию", "reset_to_default": "Восстановление значений по умолчанию",
"resolve_duplicates": "Устранить дубликаты", "resolve_duplicates": "Устранить дубликаты",
"resolved_all_duplicates": "Все дубликаты устранены", "resolved_all_duplicates": "Все дубликаты устранены",
"restore": "Восстановить", "restore": "Восстановить",
"restore_all": "Восстановить все", "restore_all": "Восстановить все",
"restore_trash_action_prompt": "{count} восстановлено из корзины",
"restore_user": "Восстановить пользователя", "restore_user": "Восстановить пользователя",
"restored_asset": "Восстановленный объект", "restored_asset": "Восстановленный объект",
"resume": "Продолжить", "resume": "Продолжить",
@@ -1569,6 +1585,7 @@
"role": "Роль", "role": "Роль",
"role_editor": "Редактор", "role_editor": "Редактор",
"role_viewer": "Зритель", "role_viewer": "Зритель",
"running": "Выполняется",
"save": "Сохранить", "save": "Сохранить",
"save_to_gallery": "Сохранить в галерею", "save_to_gallery": "Сохранить в галерею",
"saved_api_key": "API ключ изменён", "saved_api_key": "API ключ изменён",
@@ -1822,6 +1839,7 @@
"storage_quota": "Квота хранилища", "storage_quota": "Квота хранилища",
"storage_usage": "{used} из {available}", "storage_usage": "{used} из {available}",
"submit": "Подтвердить", "submit": "Подтвердить",
"success": "Успешно",
"suggestions": "Предложения", "suggestions": "Предложения",
"sunrise_on_the_beach": "Восход солнца на пляже", "sunrise_on_the_beach": "Восход солнца на пляже",
"support": "Поддержка", "support": "Поддержка",
@@ -1831,6 +1849,8 @@
"sync": "Синхр.", "sync": "Синхр.",
"sync_albums": "Синхронизировать альбомы", "sync_albums": "Синхронизировать альбомы",
"sync_albums_manual_subtitle": "Синхронизировать все загруженные фото и видео в выбранные альбомы для резервного копирования", "sync_albums_manual_subtitle": "Синхронизировать все загруженные фото и видео в выбранные альбомы для резервного копирования",
"sync_local": "Синхронизировать локально",
"sync_remote": "Синхронизация с сервером",
"sync_upload_album_setting_subtitle": "Создавайте и загружайте свои фотографии и видео в выбранные альбомы на сервер Immich", "sync_upload_album_setting_subtitle": "Создавайте и загружайте свои фотографии и видео в выбранные альбомы на сервер Immich",
"tag": "Тег", "tag": "Тег",
"tag_assets": "Добавить теги", "tag_assets": "Добавить теги",
@@ -1841,6 +1861,7 @@
"tag_updated": "Тег {tag} изменен", "tag_updated": "Тег {tag} изменен",
"tagged_assets": "Тег назначен для {count, plural, one {# объекта} other {# объектов}}", "tagged_assets": "Тег назначен для {count, plural, one {# объекта} other {# объектов}}",
"tags": "Теги", "tags": "Теги",
"tap_to_run_job": "Нажмите для запуска задачи",
"template": "Шаблон", "template": "Шаблон",
"theme": "Тема", "theme": "Тема",
"theme_selection": "Выбор темы", "theme_selection": "Выбор темы",

View File

@@ -45,14 +45,14 @@
"backup_database_enable_description": "Povoliť výpisy z databázy", "backup_database_enable_description": "Povoliť výpisy z databázy",
"backup_keep_last_amount": "Množstvo predchádzajúcich výpisov, ktoré sa majú zachovať", "backup_keep_last_amount": "Množstvo predchádzajúcich výpisov, ktoré sa majú zachovať",
"backup_settings": "Nastavenia výpisu databázy", "backup_settings": "Nastavenia výpisu databázy",
"backup_settings_description": "Správa nastavení výpisu databázy.", "backup_settings_description": "Spravovať nastavenia výpisu databázy.",
"cleared_jobs": "Hotové úlohy pre: {job}", "cleared_jobs": "Hotové úlohy pre: {job}",
"config_set_by_file": "Konfigurácia je v súčasnosti nastavená konfiguračným súborom", "config_set_by_file": "Konfigurácia je v súčasnosti nastavená konfiguračným súborom",
"confirm_delete_library": "Naozaj chcete vymazať knižnicu {library}?", "confirm_delete_library": "Naozaj chcete vymazať knižnicu {library}?",
"confirm_delete_library_assets": "Ste si istí, že chcete vymazať túto knižnicu? Tato operácia nenávratne odstráni {count, plural, one {# zahrnutú položku} few {# zahrnuté položky} other {všetkých # zahrnutých položiek}} z aplikácie Immich. Súbory budú ponechané na disku.", "confirm_delete_library_assets": "Ste si istí, že chcete vymazať túto knižnicu? Tato operácia nenávratne odstráni {count, plural, one {# zahrnutú položku} few {# zahrnuté položky} other {všetkých # zahrnutých položiek}} z aplikácie Immich. Súbory budú ponechané na disku.",
"confirm_email_below": "Pre potvrdenie zadajte \"{email}\" nižšie", "confirm_email_below": "Pre potvrdenie zadajte \"{email}\" nižšie",
"confirm_reprocess_all_faces": "Naozaj chcete spracovať všetky tváre znova? Tento proces vymaže pomenovaných ľudí.", "confirm_reprocess_all_faces": "Naozaj chcete spracovať všetky tváre znova? Tento proces vymaže pomenovaných ľudí.",
"confirm_user_password_reset": "Naozaj chcete resetovať heslo pre {user}?", "confirm_user_password_reset": "Naozaj chcete obnoviť heslo pre {user}?",
"confirm_user_pin_code_reset": "Ste si istí, že chcete opätovne nastaviť PIN kód používateľa {user}?", "confirm_user_pin_code_reset": "Ste si istí, že chcete opätovne nastaviť PIN kód používateľa {user}?",
"create_job": "Vytvoriť úlohu", "create_job": "Vytvoriť úlohu",
"cron_expression": "Výraz cron", "cron_expression": "Výraz cron",
@@ -61,10 +61,10 @@
"disable_login": "Zakázať prihlásenie", "disable_login": "Zakázať prihlásenie",
"duplicate_detection_job_description": "Spustite strojové učenie na položkách pre detekciu podobných obrázkov. Spolieha sa na inteligentné vyhľadávanie", "duplicate_detection_job_description": "Spustite strojové učenie na položkách pre detekciu podobných obrázkov. Spolieha sa na inteligentné vyhľadávanie",
"exclusion_pattern_description": "Vylučovacie vzory Vám umožňujú ignorovať súbory a priečinky pri skenovaní Vašej knižnice. Toto je užitočné, ak máte priečinky obsahujúce súbory, ktoré nechcete importovať, napríklad RAW súbory.", "exclusion_pattern_description": "Vylučovacie vzory Vám umožňujú ignorovať súbory a priečinky pri skenovaní Vašej knižnice. Toto je užitočné, ak máte priečinky obsahujúce súbory, ktoré nechcete importovať, napríklad RAW súbory.",
"external_library_management": "Správa Externej Knižnice", "external_library_management": "Spravovanie externej knižnice",
"face_detection": "Detekcia tvárí", "face_detection": "Detekcia tvárí",
"face_detection_description": "Rozpoznajte tváre v položkách pomocou strojového učenia. V prípade videí sa berie do úvahy len náhľad. „Obnoviť“ (znovu) spracuje všetky položky. „Resetovať“ dodatočne vymaže všetky aktuálne údaje o tvárach. „Chýbajúce“ zaradí do poradia médiá, ktoré ešte neboli spracované. Zistené tváre sa po dokončení rozpoznávania tvárí zaradia do poradia na rozpoznávanie tvárí, pričom sa zoskupia do existujúcich alebo nových osôb.", "face_detection_description": "Rozpoznajte tváre v položkách pomocou strojového učenia. V prípade videí sa berie do úvahy len náhľad. „Aktualizovať“ (znovu) spracuje všetky položky. „Obnoviť“ dodatočne vymaže všetky aktuálne údaje o tvárach. „Chýbajúce“ zaradí do poradia médiá, ktoré ešte neboli spracované. Zistené tváre sa po dokončení rozpoznávania tvárí zaradia do poradia na rozpoznávanie tvárí, pričom sa zoskupia do existujúcich alebo nových osôb.",
"facial_recognition_job_description": "Zoskupte rozpoznané tváre do osôb. Tento krok sa vykoná po dokončení rozpoznávania tvárí. „Resetovať“ (znovu) zoskupí všetky tváre. „Chýbajúce“ zaradí tváre, ktoré nemajú pridelenú osobu.", "facial_recognition_job_description": "Zoskupte rozpoznané tváre do osôb. Tento krok sa vykoná po dokončení rozpoznávania tvárí. „Obnoviť“ (znovu) zoskupí všetky tváre. „Chýbajúce“ zaradí tváre, ktoré nemajú pridelenú osobu.",
"failed_job_command": "Príkaz {command} zlyhal pre úlohu: {job}", "failed_job_command": "Príkaz {command} zlyhal pre úlohu: {job}",
"force_delete_user_warning": "VAROVANIE: Toto okamžite odstráni používateľa a všetky položky. Tento krok nie je možné vrátiť späť a súbory nebude možné obnoviť.", "force_delete_user_warning": "VAROVANIE: Toto okamžite odstráni používateľa a všetky položky. Tento krok nie je možné vrátiť späť a súbory nebude možné obnoviť.",
"image_format": "Formát", "image_format": "Formát",
@@ -94,7 +94,7 @@
"job_not_concurrency_safe": "Táto úloha nie je bezpečná pre súbežné spracovanie.", "job_not_concurrency_safe": "Táto úloha nie je bezpečná pre súbežné spracovanie.",
"job_settings": "Úlohy", "job_settings": "Úlohy",
"job_settings_description": "Spravovať súbežnosť úloh", "job_settings_description": "Spravovať súbežnosť úloh",
"job_status": "Stav Úloh", "job_status": "Stav úloh",
"jobs_delayed": "{jobCount, plural, one {# oneskorený} few {# oneskorené} other {# oneskorených}}", "jobs_delayed": "{jobCount, plural, one {# oneskorený} few {# oneskorené} other {# oneskorených}}",
"jobs_failed": "{jobCount, plural, one {# neúspešný} few {# neúspešné} other {# neúspešných}}", "jobs_failed": "{jobCount, plural, one {# neúspešný} few {# neúspešné} other {# neúspešných}}",
"library_created": "Vytvorená knižnica: {library}", "library_created": "Vytvorená knižnica: {library}",
@@ -141,15 +141,15 @@
"machine_learning_smart_search_enabled": "Povoliť inteligentné vyhľadávanie", "machine_learning_smart_search_enabled": "Povoliť inteligentné vyhľadávanie",
"machine_learning_smart_search_enabled_description": "Ak je vypnuté, obrázky nebudú spracované pre inteligentné vyhľadávanie.", "machine_learning_smart_search_enabled_description": "Ak je vypnuté, obrázky nebudú spracované pre inteligentné vyhľadávanie.",
"machine_learning_url_description": "URL adresa servera strojového učenia. Ak je zadaných viacero adries URL, každý server bude testovaný postupne, kým jeden z nich neodpovie úspešne, v poradí od prvého po posledný. Servery, ktoré neodpovedajú, budú dočasne ignorované, kým nebudú opäť online.", "machine_learning_url_description": "URL adresa servera strojového učenia. Ak je zadaných viacero adries URL, každý server bude testovaný postupne, kým jeden z nich neodpovie úspešne, v poradí od prvého po posledný. Servery, ktoré neodpovedajú, budú dočasne ignorované, kým nebudú opäť online.",
"manage_concurrency": "Správa súbežnosti", "manage_concurrency": "Spravovať súbežnosť",
"manage_log_settings": "Spravovať nastavenia ukladania záznamov", "manage_log_settings": "Spravovať nastavenia ukladania záznamov",
"map_dark_style": "Tmavý štýl", "map_dark_style": "Tmavý štýl",
"map_enable_description": "Povoliť funkcie mapy", "map_enable_description": "Povoliť funkcie mapy",
"map_gps_settings": "Mapa a nastavenia GPS", "map_gps_settings": "Mapa a nastavenia GPS",
"map_gps_settings_description": "Spravujte nastavenia mapy a GPS (reverzné geokódovanie)", "map_gps_settings_description": "Spravovať nastavenia mapy a GPS (reverzné geokódovanie)",
"map_implications": "Táto funkčnosť sa spolieha na externý servis spracovania mapových dlaždíc (tiles.immich.cloud)", "map_implications": "Táto funkčnosť sa spolieha na externý servis spracovania mapových dlaždíc (tiles.immich.cloud)",
"map_light_style": "Svetlý štýl", "map_light_style": "Svetlý štýl",
"map_manage_reverse_geocoding_settings": "Správa nastavení <link>Reverzného geokódovania</link>", "map_manage_reverse_geocoding_settings": "Spravovať nastavenia <link>reverzného geokódovania</link>",
"map_reverse_geocoding": "Reverzné Geokódovanie", "map_reverse_geocoding": "Reverzné Geokódovanie",
"map_reverse_geocoding_enable_description": "Povoliť reverzné geokódovanie", "map_reverse_geocoding_enable_description": "Povoliť reverzné geokódovanie",
"map_reverse_geocoding_settings": "Reverzné geokódovanie", "map_reverse_geocoding_settings": "Reverzné geokódovanie",
@@ -214,7 +214,7 @@
"oauth_role_claim_description": "Automaticky udeliť prístup správcu na základe prítomnosti tejto požiadavky. Požiadavka môže mať príznak „user“ alebo „admin“.", "oauth_role_claim_description": "Automaticky udeliť prístup správcu na základe prítomnosti tejto požiadavky. Požiadavka môže mať príznak „user“ alebo „admin“.",
"oauth_settings": "OAuth", "oauth_settings": "OAuth",
"oauth_settings_description": "Spravovať nastavenia prihlásenia OAuth", "oauth_settings_description": "Spravovať nastavenia prihlásenia OAuth",
"oauth_settings_more_details": "Pre viac informácii o tejto funkcii, prejdite na <link>docs</link>.", "oauth_settings_more_details": "Pre viac informácii o tejto funkcii, prejdite na <link>dokumentáciu</link>.",
"oauth_storage_label_claim": "Nárokovať Štítok úložiska", "oauth_storage_label_claim": "Nárokovať Štítok úložiska",
"oauth_storage_label_claim_description": "Automaticky nastaviť štítok úložiska používateľa na hodnotu tohto nároku.", "oauth_storage_label_claim_description": "Automaticky nastaviť štítok úložiska používateľa na hodnotu tohto nároku.",
"oauth_storage_quota_claim": "Deklarácia kvóty úložiska", "oauth_storage_quota_claim": "Deklarácia kvóty úložiska",
@@ -234,7 +234,7 @@
"registration_description": "Keďže ste prvým používateľom v systéme, budú vám pridelené správcovské práva na vykonávanie všetkých úloh a vrátane tvorby nových používateľov.", "registration_description": "Keďže ste prvým používateľom v systéme, budú vám pridelené správcovské práva na vykonávanie všetkých úloh a vrátane tvorby nových používateľov.",
"require_password_change_on_login": "Vyžadovať od používateľa zmenu hesla pri prvom prihlásení", "require_password_change_on_login": "Vyžadovať od používateľa zmenu hesla pri prvom prihlásení",
"reset_settings_to_default": "Obnoviť pôvodné nastavenia", "reset_settings_to_default": "Obnoviť pôvodné nastavenia",
"reset_settings_to_recent_saved": "Obnov naposledy uložené nastavenia", "reset_settings_to_recent_saved": "Nastavenia boli obnovené na posled uložené nastavenia",
"scanning_library": "Knižnica sa skenuje", "scanning_library": "Knižnica sa skenuje",
"search_jobs": "Vyhľadať úlohy…", "search_jobs": "Vyhľadať úlohy…",
"send_welcome_email": "Odoslať uvítací e-mail", "send_welcome_email": "Odoslať uvítací e-mail",
@@ -259,7 +259,7 @@
"storage_template_migration_description": "Použite aktuálnu <link>{template}</link> na predtým nahrané médiá", "storage_template_migration_description": "Použite aktuálnu <link>{template}</link> na predtým nahrané médiá",
"storage_template_migration_info": "Šablóna úložiska skonvertuje všetky prípony na malé písmená. Zmeny šablón sa budú vzťahovať iba na nové diela. Ak chcete šablónu spätne použiť na predtým nahrané médiá, spustite <link>{job}</link>.", "storage_template_migration_info": "Šablóna úložiska skonvertuje všetky prípony na malé písmená. Zmeny šablón sa budú vzťahovať iba na nové diela. Ak chcete šablónu spätne použiť na predtým nahrané médiá, spustite <link>{job}</link>.",
"storage_template_migration_job": "Úloha migrácie šablóny úložiska", "storage_template_migration_job": "Úloha migrácie šablóny úložiska",
"storage_template_more_details": "Ďalšie podrobnosti o tejto funkcii nájdete v <template-link>Šablóna úložiska</template-link> a jej <implications-link>sledky</implications-link>", "storage_template_more_details": "Podrobnejšie informácie o tejto funkcii nájdete v časti <template-link>šablóna úložiska</template-link> a jej <implications-link>sledky</implications-link>",
"storage_template_onboarding_description_v2": "Ak je táto funkcia zapnutá, automaticky usporiada súbory na základe šablóny definovanej používateľom. Ďalšie informácie nájdete v <link>dokumentácii</link>.", "storage_template_onboarding_description_v2": "Ak je táto funkcia zapnutá, automaticky usporiada súbory na základe šablóny definovanej používateľom. Ďalšie informácie nájdete v <link>dokumentácii</link>.",
"storage_template_path_length": "Približný limit dĺžky cesty: <b>{length, number}</b>/{limit, number}", "storage_template_path_length": "Približný limit dĺžky cesty: <b>{length, number}</b>/{limit, number}",
"storage_template_settings": "Šablóna úložiska", "storage_template_settings": "Šablóna úložiska",
@@ -278,9 +278,9 @@
"template_settings_description": "Spravovanie vlastných šablón upozornení", "template_settings_description": "Spravovanie vlastných šablón upozornení",
"theme_custom_css_settings": "Vlastné CSS", "theme_custom_css_settings": "Vlastné CSS",
"theme_custom_css_settings_description": "CSS štýly umožňujú prispôsobiť dizajn Immich.", "theme_custom_css_settings_description": "CSS štýly umožňujú prispôsobiť dizajn Immich.",
"theme_settings": "Motívy", "theme_settings": "Nastavenia témy",
"theme_settings_description": "Spravovať prispôsobenie webového rozhrania Immich", "theme_settings_description": "Spravovať prispôsobenie webového rozhrania Immich",
"thumbnail_generation_job": "Generovať Miniatúry", "thumbnail_generation_job": "Generovať miniatúry",
"thumbnail_generation_job_description": "Generujte veľké, malé a rozmazané miniatúry pre každú položku, ako aj miniatúry pre každú osobu", "thumbnail_generation_job_description": "Generujte veľké, malé a rozmazané miniatúry pre každú položku, ako aj miniatúry pre každú osobu",
"transcoding_acceleration_api": "API pre akceleráciu", "transcoding_acceleration_api": "API pre akceleráciu",
"transcoding_acceleration_api_description": "Rozhranie API, ktoré bude spolupracovať s vaším zariadením s cieľom urýchliť prekódovanie. Toto nastavenie je „najlepšie úsilie“: pri zlyhaní sa vráti k softvérovému prekódovaniu. VP9 môže alebo nemusí fungovať v závislosti od vášho hardvéru.", "transcoding_acceleration_api_description": "Rozhranie API, ktoré bude spolupracovať s vaším zariadením s cieľom urýchliť prekódovanie. Toto nastavenie je „najlepšie úsilie“: pri zlyhaní sa vráti k softvérovému prekódovaniu. VP9 môže alebo nemusí fungovať v závislosti od vášho hardvéru.",
@@ -300,7 +300,7 @@
"transcoding_bitrate_description": "Videá presahujúce maximálnu bitovú rýchlosť alebo videá, ktoré nie sú v akceptovanom formáte", "transcoding_bitrate_description": "Videá presahujúce maximálnu bitovú rýchlosť alebo videá, ktoré nie sú v akceptovanom formáte",
"transcoding_codecs_learn_more": "Ak sa chcete dozvedieť viac o tu použitej terminológii, pozrite si dokumentáciu FFmpeg pre <h264-link>kodek H.264</h264-link>, <hevc-link>kodek HEVC</hevc-link> a <vp9-link>VP9 kodek</vp9-link>.", "transcoding_codecs_learn_more": "Ak sa chcete dozvedieť viac o tu použitej terminológii, pozrite si dokumentáciu FFmpeg pre <h264-link>kodek H.264</h264-link>, <hevc-link>kodek HEVC</hevc-link> a <vp9-link>VP9 kodek</vp9-link>.",
"transcoding_constant_quality_mode": "Režim konštantnej kvality", "transcoding_constant_quality_mode": "Režim konštantnej kvality",
"transcoding_constant_quality_mode_description": "ICQ je lepšie ako CQP, ale niektoré zariadenia na hardvérovú akceleráciu tento režim nepodporujú. Nastavenie tejto možnosti uprednostní špecifikovaný režim pri použití kódovania založeného na kvalite. Ignorované spoločnosťou NVENC, pretože nepodporuje ICQ.", "transcoding_constant_quality_mode_description": "ICQ je lepšie ako CQP, ale niektoré zariadenia na hardvérovú akceleráciu tento režim nepodporujú. Nastavenie tejto možnosti uprednostní špecifikovaný režim pri použití kódovania založeného na kvalite. Ignorované funkciou NVENC, pretože nepodporuje ICQ.",
"transcoding_constant_rate_factor": "Faktor konštantnej rýchlosti (-crf)", "transcoding_constant_rate_factor": "Faktor konštantnej rýchlosti (-crf)",
"transcoding_constant_rate_factor_description": "Úroveň kvality videa. Typické hodnoty sú 23 pre H.264, 28 pre HEVC, 31 pre VP9 a 35 pre AV1. Nižšie je lepšie, ale vytvára väčšie súbory.", "transcoding_constant_rate_factor_description": "Úroveň kvality videa. Typické hodnoty sú 23 pre H.264, 28 pre HEVC, 31 pre VP9 a 35 pre AV1. Nižšie je lepšie, ale vytvára väčšie súbory.",
"transcoding_disabled_description": "Neprekódovať žiadne videá, na niektorých klientoch môže prerušiť prehrávanie", "transcoding_disabled_description": "Neprekódovať žiadne videá, na niektorých klientoch môže prerušiť prehrávanie",
@@ -321,13 +321,13 @@
"transcoding_policy_description": "Nastavte, kedy bude video prekódované", "transcoding_policy_description": "Nastavte, kedy bude video prekódované",
"transcoding_preferred_hardware_device": "Uprednostňované hardvérové zariadenie", "transcoding_preferred_hardware_device": "Uprednostňované hardvérové zariadenie",
"transcoding_preferred_hardware_device_description": "Platí len pre VAAPI a QSV. Nastavuje uzol dri, ktorý sa používa na hardvérové prekódovanie.", "transcoding_preferred_hardware_device_description": "Platí len pre VAAPI a QSV. Nastavuje uzol dri, ktorý sa používa na hardvérové prekódovanie.",
"transcoding_preset_preset": "Prednastavenie (-preset)", "transcoding_preset_preset": "Predvoľba (-preset)",
"transcoding_preset_preset_description": "Rýchlosť kompresie. Pomalšie predvoľby vytvárajú menšie súbory a zvyšujú kvalitu, keď sa zameriavajú na určitý dátový tok. VP9 ignoruje rýchlosti vyššie ako „rýchlejšie“.", "transcoding_preset_preset_description": "Rýchlosť kompresie. Pomalšie predvoľby vytvárajú menšie súbory a zvyšujú kvalitu, keď sa zameriavajú na určitý dátový tok. VP9 ignoruje rýchlosti vyššie ako „rýchlejšie“.",
"transcoding_reference_frames": "Referenčné snímky", "transcoding_reference_frames": "Referenčné snímky",
"transcoding_reference_frames_description": "Počet snímok, na ktoré sa má odkazovať pri kompresii daného snímku. Vyššie hodnoty zvyšujú účinnosť kompresie, ale spomaľujú kódovanie. Hodnota 0 sa nastavuje automaticky.", "transcoding_reference_frames_description": "Počet snímok, na ktoré sa má odkazovať pri kompresii daného snímku. Vyššie hodnoty zvyšujú účinnosť kompresie, ale spomaľujú kódovanie. Hodnota 0 sa nastavuje automaticky.",
"transcoding_required_description": "Iba videá, ktoré nie sú v prijatom formáte", "transcoding_required_description": "Iba videá, ktoré nie sú v prijatom formáte",
"transcoding_settings": "Nastavenia prekódovania videa", "transcoding_settings": "Nastavenia prekódovania videa",
"transcoding_settings_description": "Spravujte, ktoré videá sa majú prekódovať a ako ich spracovať", "transcoding_settings_description": "Spravovať, ktoré videá sa majú prekódovať a ako sa majú spracovať",
"transcoding_target_resolution": "Cieľové rozlíšenie", "transcoding_target_resolution": "Cieľové rozlíšenie",
"transcoding_target_resolution_description": "Vyššie rozlíšenia môžu zachovať viac detailov, ale ich kódovanie trvá dlhšie, majú väčšiu veľkosť súborov a môžu znížiť odozvu aplikácie.", "transcoding_target_resolution_description": "Vyššie rozlíšenia môžu zachovať viac detailov, ale ich kódovanie trvá dlhšie, majú väčšiu veľkosť súborov a môžu znížiť odozvu aplikácie.",
"transcoding_temporal_aq": "Časové AQ", "transcoding_temporal_aq": "Časové AQ",
@@ -349,13 +349,13 @@
"trash_settings_description": "Spravovať nastavenia koša", "trash_settings_description": "Spravovať nastavenia koša",
"user_cleanup_job": "Premazanie používateľov", "user_cleanup_job": "Premazanie používateľov",
"user_delete_delay": "Konto <b>{user}</b> a jeho médiá budú podľa plánu natrvalo vymazané za {delay, plural, one {# deň} few {# dni} other {# dní}}.", "user_delete_delay": "Konto <b>{user}</b> a jeho médiá budú podľa plánu natrvalo vymazané za {delay, plural, one {# deň} few {# dni} other {# dní}}.",
"user_delete_delay_settings": "Odstrániť oneskorenie", "user_delete_delay_settings": "Oneskorenie vymazania",
"user_delete_delay_settings_description": "Počet dní po odstránení na trvalé vymazanie účtu a médií používateľa. Úloha odstraňovania používateľov sa spúšťa o polnoci, aby sa skontrolovali používatelia, ktorí sú pripravení na odstránenie. Zmeny tohto nastavenia sa vyhodnotia pri ďalšom spustení.", "user_delete_delay_settings_description": "Počet dní, po ktorých sa po odstránení používateľa natrvalo odstráni jeho účet a položky. Úloha odstraňovania používateľov sa spúšťa o polnoci, aby sa skontrolovali používatelia, ktorí sú pripravení na odstránenie. Zmeny tohto nastavenia sa vyhodnotia pri ďalšom spustení.",
"user_delete_immediately": "Konto a médiá používateľa <b>{user}</b> budú zaradené do poradia na trvalé vymazanie <b>okamžite</b>.", "user_delete_immediately": "Konto a médiá používateľa <b>{user}</b> budú zaradené do poradia na trvalé vymazanie <b>okamžite</b>.",
"user_delete_immediately_checkbox": "Používateľ a médiá budú zaradení do frontu na okamžité vymazanie", "user_delete_immediately_checkbox": "Používateľ a médiá budú zaradení do frontu na okamžité vymazanie",
"user_details": "Podrobnosti o používateľovi", "user_details": "Podrobnosti o používateľovi",
"user_management": "Správa používateľov", "user_management": "Spravovanie používateľov",
"user_password_has_been_reset": "Heslo používateľa bolo resetované:", "user_password_has_been_reset": "Heslo používateľa bolo obnovené:",
"user_password_reset_description": "Poskytnite používateľovi dočasné heslo a informujte ho, že si ho bude musieť zmeniť pri ďalšom prihlásení.", "user_password_reset_description": "Poskytnite používateľovi dočasné heslo a informujte ho, že si ho bude musieť zmeniť pri ďalšom prihlásení.",
"user_restore_description": "<b>{user}</b> bude účet obnovený.", "user_restore_description": "<b>{user}</b> bude účet obnovený.",
"user_restore_scheduled_removal": "Obnoviť používateľa - plánované odstránenie na {date, date, long}", "user_restore_scheduled_removal": "Obnoviť používateľa - plánované odstránenie na {date, date, long}",
@@ -393,7 +393,7 @@
"age_year_months": "Vek 1 rok, {months, plural, one {# month} other {# months}}", "age_year_months": "Vek 1 rok, {months, plural, one {# month} other {# months}}",
"age_years": "{years, plural, other {Vek #}}", "age_years": "{years, plural, other {Vek #}}",
"album_added": "Album bol pridaný", "album_added": "Album bol pridaný",
"album_added_notification_setting_description": "Obdržať upozornenie emailom, keď ste prida do zdieľaného albumu", "album_added_notification_setting_description": "Obdržať upozornenie emailom, keď vás prida do zdieľaného albumu",
"album_cover_updated": "Obal albumu aktualizovaný", "album_cover_updated": "Obal albumu aktualizovaný",
"album_delete_confirmation": "Ste si istý, že chcete odstrániť album {album}?", "album_delete_confirmation": "Ste si istý, že chcete odstrániť album {album}?",
"album_delete_confirmation_description": "Ak je tento album zdieľaný, ostatní používatelia k nemu už nebudú mať prístup.", "album_delete_confirmation_description": "Ak je tento album zdieľaný, ostatní používatelia k nemu už nebudú mať prístup.",
@@ -573,6 +573,8 @@
"backup_options_page_title": "Možnosti zálohovania", "backup_options_page_title": "Možnosti zálohovania",
"backup_setting_subtitle": "Spravovať nastavenia odosielania na pozadí a v popredí", "backup_setting_subtitle": "Spravovať nastavenia odosielania na pozadí a v popredí",
"backward": "Dozadu", "backward": "Dozadu",
"beta_sync": "Stav synchronizácie verzie Beta",
"beta_sync_subtitle": "Spravovať nový systém synchronizácie",
"biometric_auth_enabled": "Biometrické overovanie je povolené", "biometric_auth_enabled": "Biometrické overovanie je povolené",
"biometric_locked_out": "Ste vymknutí z biometrického overovania", "biometric_locked_out": "Ste vymknutí z biometrického overovania",
"biometric_no_options": "Nie sú k dispozícii žiadne biometrické možnosti", "biometric_no_options": "Nie sú k dispozícii žiadne biometrické možnosti",
@@ -590,7 +592,7 @@
"cache_settings_clear_cache_button": "Vymazať vyrovnávaciu pamäť", "cache_settings_clear_cache_button": "Vymazať vyrovnávaciu pamäť",
"cache_settings_clear_cache_button_title": "Vymaže vyrovnávaciu pamäť aplikácie. To výrazne ovplyvní výkon aplikácie, kým sa vyrovnávacia pamäť neobnoví.", "cache_settings_clear_cache_button_title": "Vymaže vyrovnávaciu pamäť aplikácie. To výrazne ovplyvní výkon aplikácie, kým sa vyrovnávacia pamäť neobnoví.",
"cache_settings_duplicated_assets_clear_button": "VYČISTIŤ", "cache_settings_duplicated_assets_clear_button": "VYČISTIŤ",
"cache_settings_duplicated_assets_subtitle": "Fotky a videá ktoré sú na čiernej listine zvolené aplikáciou", "cache_settings_duplicated_assets_subtitle": "Fotografie a videá, ktoré aplikácia ignoruje podľa zoznamu",
"cache_settings_duplicated_assets_title": "Duplicitné položky ({count})", "cache_settings_duplicated_assets_title": "Duplicitné položky ({count})",
"cache_settings_statistics_album": "Knižnica náhľadov", "cache_settings_statistics_album": "Knižnica náhľadov",
"cache_settings_statistics_full": "Kompletné fotografie", "cache_settings_statistics_full": "Kompletné fotografie",
@@ -628,7 +630,7 @@
"change_password_form_password_mismatch": "Heslá sa nezhodujú", "change_password_form_password_mismatch": "Heslá sa nezhodujú",
"change_password_form_reenter_new_password": "Znova zadajte nové heslo", "change_password_form_reenter_new_password": "Znova zadajte nové heslo",
"change_pin_code": "Zmeniť PIN kód", "change_pin_code": "Zmeniť PIN kód",
"change_your_password": "Zmeňte si heslo", "change_your_password": "Zmeniť heslo",
"changed_visibility_successfully": "Viditeľnosť bola úspešne zmenená", "changed_visibility_successfully": "Viditeľnosť bola úspešne zmenená",
"check_corrupt_asset_backup": "Skontrolovať, či nie sú poškodené zálohy položiek", "check_corrupt_asset_backup": "Skontrolovať, či nie sú poškodené zálohy položiek",
"check_corrupt_asset_backup_button": "Vykonať kontrolu", "check_corrupt_asset_backup_button": "Vykonať kontrolu",
@@ -723,7 +725,7 @@
"custom_locale_description": "Formátovanie dátumov a čísel podľa jazyka a regiónu", "custom_locale_description": "Formátovanie dátumov a čísel podľa jazyka a regiónu",
"daily_title_text_date": "EEEE, d. MMMM", "daily_title_text_date": "EEEE, d. MMMM",
"daily_title_text_date_year": "EEEE, d. MMMM y", "daily_title_text_date_year": "EEEE, d. MMMM y",
"dark": "Tmavý", "dark": "Tmavá",
"dark_theme": "Prepnúť tmavú tému", "dark_theme": "Prepnúť tmavú tému",
"date_after": "Dátum po", "date_after": "Dátum po",
"date_and_time": "Dátum a Čas", "date_and_time": "Dátum a Čas",
@@ -949,7 +951,7 @@
"unable_to_remove_library": "Nie je možné odstrániť knižnicu", "unable_to_remove_library": "Nie je možné odstrániť knižnicu",
"unable_to_remove_partner": "Nie je možné odstrániť partnera", "unable_to_remove_partner": "Nie je možné odstrániť partnera",
"unable_to_remove_reaction": "Nie je možné odstrániť reakciu", "unable_to_remove_reaction": "Nie je možné odstrániť reakciu",
"unable_to_reset_password": "Nie je možné resetovať heslo", "unable_to_reset_password": "Nie je možné obnoviť heslo",
"unable_to_reset_pin_code": "Nie je možné obnoviť PIN kód", "unable_to_reset_pin_code": "Nie je možné obnoviť PIN kód",
"unable_to_resolve_duplicate": "Nie je možné vyriešiť duplikát", "unable_to_resolve_duplicate": "Nie je možné vyriešiť duplikát",
"unable_to_restore_assets": "Nie je možné obnoviť položky", "unable_to_restore_assets": "Nie je možné obnoviť položky",
@@ -987,7 +989,7 @@
"exif_bottom_sheet_person_age_months": "Vek {months} mesiacov", "exif_bottom_sheet_person_age_months": "Vek {months} mesiacov",
"exif_bottom_sheet_person_age_year_months": "Vek 1 rok, {months} mesiacov", "exif_bottom_sheet_person_age_year_months": "Vek 1 rok, {months} mesiacov",
"exif_bottom_sheet_person_age_years": "Vek {years}", "exif_bottom_sheet_person_age_years": "Vek {years}",
"exit_slideshow": "Opustiť Slideshow", "exit_slideshow": "Opustiť prezentáciu",
"expand_all": "Rozbaliť všetko", "expand_all": "Rozbaliť všetko",
"experimental_settings_new_asset_list_subtitle": "Prebiehajúca práca", "experimental_settings_new_asset_list_subtitle": "Prebiehajúca práca",
"experimental_settings_new_asset_list_title": "Povolenie experimentálnej mriežky fotografií", "experimental_settings_new_asset_list_title": "Povolenie experimentálnej mriežky fotografií",
@@ -1051,6 +1053,9 @@
"haptic_feedback_switch": "Povoliť hmatovú odozvu", "haptic_feedback_switch": "Povoliť hmatovú odozvu",
"haptic_feedback_title": "Hmatová odozva", "haptic_feedback_title": "Hmatová odozva",
"has_quota": "Má kvótu", "has_quota": "Má kvótu",
"hash_asset": "Hashovať položku",
"hashed_assets": "Hashované položky",
"hashing": "Hashovanie",
"header_settings_add_header_tip": "Pridať hlavičku", "header_settings_add_header_tip": "Pridať hlavičku",
"header_settings_field_validator_msg": "Hodnota nemôže byť prázdna", "header_settings_field_validator_msg": "Hodnota nemôže byť prázdna",
"header_settings_header_name_input": "Názov hlavičky", "header_settings_header_name_input": "Názov hlavičky",
@@ -1083,6 +1088,7 @@
"host": "Hostiteľ", "host": "Hostiteľ",
"hour": "Hodina", "hour": "Hodina",
"id": "ID", "id": "ID",
"idle": "Nečinné",
"ignore_icloud_photos": "Ignorovať fotky v službe iCloud", "ignore_icloud_photos": "Ignorovať fotky v službe iCloud",
"ignore_icloud_photos_description": "Fotografie uložené v službe iCloud sa nebudú odosielať na server Immich", "ignore_icloud_photos_description": "Fotografie uložené v službe iCloud sa nebudú odosielať na server Immich",
"image": "Obrázok", "image": "Obrázok",
@@ -1139,7 +1145,7 @@
"language_no_results_subtitle": "Skúste upraviť hľadaný výraz", "language_no_results_subtitle": "Skúste upraviť hľadaný výraz",
"language_no_results_title": "Neboli nájdené žiadne jazyky", "language_no_results_title": "Neboli nájdené žiadne jazyky",
"language_search_hint": "Vyhľadať jazyky...", "language_search_hint": "Vyhľadať jazyky...",
"language_setting_description": "Vyberte preferovaný jazyk", "language_setting_description": "Vyberte požadovaný jazyk",
"last_seen": "Naposledy videné", "last_seen": "Naposledy videné",
"latest_version": "Najnovšia verzia", "latest_version": "Najnovšia verzia",
"latitude": "Zemepisná šírka", "latitude": "Zemepisná šírka",
@@ -1156,7 +1162,7 @@
"library_page_sort_last_modified": "Naposledy upravené", "library_page_sort_last_modified": "Naposledy upravené",
"library_page_sort_title": "Podľa názvu albumu", "library_page_sort_title": "Podľa názvu albumu",
"licenses": "Licencie", "licenses": "Licencie",
"light": "Svetlý", "light": "Svetlá",
"like_deleted": "Like odstránený", "like_deleted": "Like odstránený",
"link_motion_video": "Pripojiť pohyblivé video", "link_motion_video": "Pripojiť pohyblivé video",
"link_options": "Možnosti odkazu", "link_options": "Možnosti odkazu",
@@ -1165,7 +1171,9 @@
"list": "Zoznam", "list": "Zoznam",
"loading": "Načítavanie", "loading": "Načítavanie",
"loading_search_results_failed": "Načítanie výsledkov hľadania sa nepodarilo", "loading_search_results_failed": "Načítanie výsledkov hľadania sa nepodarilo",
"local": "Lokálne",
"local_asset_cast_failed": "Nie je možné preniesť médium, ktoré nie je nahrané na serveri", "local_asset_cast_failed": "Nie je možné preniesť médium, ktoré nie je nahrané na serveri",
"local_assets": "Lokálne položky",
"local_network": "Miestna sieť", "local_network": "Miestna sieť",
"local_network_sheet_info": "Pri použití zadanej siete Wi-Fi sa aplikácia pripojí k serveru prostredníctvom tejto URL adresy", "local_network_sheet_info": "Pri použití zadanej siete Wi-Fi sa aplikácia pripojí k serveru prostredníctvom tejto URL adresy",
"location_permission": "Povolenie na určenie polohy", "location_permission": "Povolenie na určenie polohy",
@@ -1277,7 +1285,7 @@
"move_off_locked_folder": "Presunúť zo zamknutého priečinka", "move_off_locked_folder": "Presunúť zo zamknutého priečinka",
"move_to_lock_folder_action_prompt": "{count} pridaných do zamknutého priečinka", "move_to_lock_folder_action_prompt": "{count} pridaných do zamknutého priečinka",
"move_to_locked_folder": "Presunúť do zamknutého priečinka", "move_to_locked_folder": "Presunúť do zamknutého priečinka",
"move_to_locked_folder_confirmation": "Tieto fotografie a videá budú odstránené zo všetkých albumov a bude ich možné zobraziť len v zamknutom priečinku", "move_to_locked_folder_confirmation": "Tieto fotografie a videá budú odobrané zo všetkých albumov a bude ich možné zobraziť len v zamknutom priečinku",
"moved_to_archive": "{count, plural, one {Presunutá # položka} few {Presunuté # položky} other {Presunutých # položiek}} do archívu", "moved_to_archive": "{count, plural, one {Presunutá # položka} few {Presunuté # položky} other {Presunutých # položiek}} do archívu",
"moved_to_library": "{count, plural, one {Presunutá # položka} few {Presunuté # položky} other {Presunutých # položiek}} do knižnice", "moved_to_library": "{count, plural, one {Presunutá # položka} few {Presunuté # položky} other {Presunutých # položiek}} do knižnice",
"moved_to_trash": "Presunuté do koša", "moved_to_trash": "Presunuté do koša",
@@ -1322,6 +1330,7 @@
"no_results": "Žiadne výsledky", "no_results": "Žiadne výsledky",
"no_results_description": "Skúste synonymum alebo všeobecnejší výraz", "no_results_description": "Skúste synonymum alebo všeobecnejší výraz",
"no_shared_albums_message": "Vytvorí album na zdieľanie fotiek a videí s ľuďmi vo vašej sieti", "no_shared_albums_message": "Vytvorí album na zdieľanie fotiek a videí s ľuďmi vo vašej sieti",
"no_uploads_in_progress": "Žiadne prebiehajúce nahrávanie",
"not_in_any_album": "Nie je v žiadnom albume", "not_in_any_album": "Nie je v žiadnom albume",
"not_selected": "Nevybrané", "not_selected": "Nevybrané",
"note_apply_storage_label_to_previously_uploaded assets": "Poznámka: Ak chcete použiť Štítok úložiska na predtým nahrané médiá, spustite príkaz", "note_apply_storage_label_to_previously_uploaded assets": "Poznámka: Ak chcete použiť Štítok úložiska na predtým nahrané médiá, spustite príkaz",
@@ -1343,7 +1352,7 @@
"onboarding": "Na palube", "onboarding": "Na palube",
"onboarding_locale_description": "Vyberte požadovaný jazyk. Neskôr ho môžete zmeniť v nastaveniach.", "onboarding_locale_description": "Vyberte požadovaný jazyk. Neskôr ho môžete zmeniť v nastaveniach.",
"onboarding_privacy_description": "Nasledujúce (voliteľné) funkcie závisia na externých službách a kedykoľvek ich môžete vypnúť nastaveniach.", "onboarding_privacy_description": "Nasledujúce (voliteľné) funkcie závisia na externých službách a kedykoľvek ich môžete vypnúť nastaveniach.",
"onboarding_server_welcome_description": "Nastavme vašu inštanciu pomocou bežných nastavení.", "onboarding_server_welcome_description": "Poďme si nastav vašu inštanciu s niekoľkými bežnými nastaveniami.",
"onboarding_theme_description": "Vyberte farbu témy pre váš server. Môžete to aj neskôr zmeniť vo vašich nastaveniach.", "onboarding_theme_description": "Vyberte farbu témy pre váš server. Môžete to aj neskôr zmeniť vo vašich nastaveniach.",
"onboarding_user_welcome_description": "Začnime!", "onboarding_user_welcome_description": "Začnime!",
"onboarding_welcome_user": "Vitaj, {user}", "onboarding_welcome_user": "Vitaj, {user}",
@@ -1359,6 +1368,7 @@
"original": "originál", "original": "originál",
"other": "Ostatné", "other": "Ostatné",
"other_devices": "Ďalšie zariadenia", "other_devices": "Ďalšie zariadenia",
"other_entities": "Ostatné subjekty",
"other_variables": "Ostatné premenné", "other_variables": "Ostatné premenné",
"owned": "Vlastnené", "owned": "Vlastnené",
"owner": "Vlastník", "owner": "Vlastník",
@@ -1434,9 +1444,9 @@
"play_or_pause_video": "Pustí alebo pozastaví video", "play_or_pause_video": "Pustí alebo pozastaví video",
"please_auth_to_access": "Prosím, potvrďte overenie pre prístup", "please_auth_to_access": "Prosím, potvrďte overenie pre prístup",
"port": "Port", "port": "Port",
"preferences_settings_subtitle": "Spravujte predvoľby aplikácie", "preferences_settings_subtitle": "Spravovať predvoľby aplikácie",
"preferences_settings_title": "Predvoľby", "preferences_settings_title": "Predvoľby",
"preset": "Prednastavenie", "preset": "Predvoľba",
"preview": "Náhľad", "preview": "Náhľad",
"previous": "Predošlé", "previous": "Predošlé",
"previous_memory": "Predošlá spomienka", "previous_memory": "Predošlá spomienka",
@@ -1508,7 +1518,7 @@
"recently_added_page_title": "Nedávno pridané", "recently_added_page_title": "Nedávno pridané",
"recently_taken": "Nedávno nasnímané", "recently_taken": "Nedávno nasnímané",
"recently_taken_page_title": "Nedávno zhotovené", "recently_taken_page_title": "Nedávno zhotovené",
"refresh": "Obnoviť", "refresh": "Aktualizovať",
"refresh_encoded_videos": "Obnoviť enkódované videá", "refresh_encoded_videos": "Obnoviť enkódované videá",
"refresh_faces": "Obnoviť tváre", "refresh_faces": "Obnoviť tváre",
"refresh_metadata": "Obnoviť metadáta", "refresh_metadata": "Obnoviť metadáta",
@@ -1519,6 +1529,8 @@
"refreshing_faces": "Obnovovanie tvárí", "refreshing_faces": "Obnovovanie tvárí",
"refreshing_metadata": "Obnovovanie metadát", "refreshing_metadata": "Obnovovanie metadát",
"regenerating_thumbnails": "Pregenerovanie náhľadov", "regenerating_thumbnails": "Pregenerovanie náhľadov",
"remote": "Vzdialené",
"remote_assets": "Vzdialené položky",
"remove": "Odstrániť", "remove": "Odstrániť",
"remove_assets_album_confirmation": "Naozaj chcete odstrániť {count, plural, one {# položku} few {# položky} other {# položiek}} z albumu?", "remove_assets_album_confirmation": "Naozaj chcete odstrániť {count, plural, one {# položku} few {# položky} other {# položiek}} z albumu?",
"remove_assets_shared_link_confirmation": "Naozaj chcete odstrániť {count, plural, one {# položku} few {# položky} other {# položiek}} z tohoto zdieľaného odkazu?", "remove_assets_shared_link_confirmation": "Naozaj chcete odstrániť {count, plural, one {# položku} few {# položky} other {# položiek}} z tohoto zdieľaného odkazu?",
@@ -1529,8 +1541,8 @@
"remove_from_album_action_prompt": "{count} odstránené z albumu", "remove_from_album_action_prompt": "{count} odstránené z albumu",
"remove_from_favorites": "Odstrániť z obľúbených", "remove_from_favorites": "Odstrániť z obľúbených",
"remove_from_lock_folder_action_prompt": "{count} odobrané zo zamknutého priečinka", "remove_from_lock_folder_action_prompt": "{count} odobrané zo zamknutého priečinka",
"remove_from_locked_folder": "Odstrániť zo zamknutého priečinka", "remove_from_locked_folder": "Odobrať zo zamknutého priečinka",
"remove_from_locked_folder_confirmation": "Ste si istí, že chcete tieto fotografie a videá presunúť zo zamknutého priečinka? Budú viditeľné vo vašej knižnici.", "remove_from_locked_folder_confirmation": "Ste si istí, že chcete tieto fotografie a videá odobrať zo zamknutého priečinka? Budú viditeľné vo vašej knižnici.",
"remove_from_shared_link": "Odstrániť zo zdieľaného odkazu", "remove_from_shared_link": "Odstrániť zo zdieľaného odkazu",
"remove_memory": "Odstrániť spomienku", "remove_memory": "Odstrániť spomienku",
"remove_photo_from_memory": "Odstrániť fotografiu z tejto spomienky", "remove_photo_from_memory": "Odstrániť fotografiu z tejto spomienky",
@@ -1552,28 +1564,33 @@
"require_password": "Vyžadovať heslo", "require_password": "Vyžadovať heslo",
"require_user_to_change_password_on_first_login": "Vyžadovať zmenu hesla po prvom prihlásení", "require_user_to_change_password_on_first_login": "Vyžadovať zmenu hesla po prvom prihlásení",
"rescan": "Opätovné vyhľadávanie", "rescan": "Opätovné vyhľadávanie",
"reset": "Resetovať", "reset": "Obnoviť",
"reset_password": "Obnoviť heslo", "reset_password": "Obnoviť heslo",
"reset_people_visibility": "Resetovať viditeľnosť ľudí", "reset_people_visibility": "Obnoviť viditeľnosť ľudí",
"reset_pin_code": "Obnoviť PIN kód", "reset_pin_code": "Obnoviť PIN kód",
"reset_to_default": "Resetovať na predvolené", "reset_sqlite": "Obnoviť SQLite databázu",
"reset_sqlite_confirmation": "Ste si istí, že chcete obnoviť SQLite databázu? Na opätovnú synchronizáciu údajov sa budete musieť odhlásiť a znova prihlásiť",
"reset_sqlite_success": "Úspešné obnovenie databázy SQLite",
"reset_to_default": "Obnoviť na predvolené",
"resolve_duplicates": "Vyriešiť duplicity", "resolve_duplicates": "Vyriešiť duplicity",
"resolved_all_duplicates": "Vyriešené všetky duplicity", "resolved_all_duplicates": "Vyriešené všetky duplicity",
"restore": "Navrátiť", "restore": "Navrátiť",
"restore_all": "Navrátit všetko", "restore_all": "Navrátit všetko",
"restore_trash_action_prompt": "{count} obnovených z koša",
"restore_user": "Navrátiť používateľa", "restore_user": "Navrátiť používateľa",
"restored_asset": "Navrátené položky", "restored_asset": "Navrátené položky",
"resume": "Pokračovať", "resume": "Pokračovať",
"retry_upload": "Zopakovať nahrávanie", "retry_upload": "Zopakovať nahrávanie",
"review_duplicates": "Prezrieť duplikáty", "review_duplicates": "Preskúmať duplikáty",
"role": "Rola", "role": "Rola",
"role_editor": "Editor", "role_editor": "Editor",
"role_viewer": "Divák", "role_viewer": "Divák",
"running": "Spustené",
"save": "Uložiť", "save": "Uložiť",
"save_to_gallery": "Uložiť do galérie", "save_to_gallery": "Uložiť do galérie",
"saved_api_key": "Uložený API Kľúč", "saved_api_key": "Uložený API Kľúč",
"saved_profile": "Uložený profil", "saved_profile": "Uložený profil",
"saved_settings": "Uložené nastavenia", "saved_settings": "Nastavenia boli uložené",
"say_something": "Napíšte niečo", "say_something": "Napíšte niečo",
"scaffold_body_error_occurred": "Vyskytla sa chyba", "scaffold_body_error_occurred": "Vyskytla sa chyba",
"scan_all_libraries": "Preskenovať všetky knižnice", "scan_all_libraries": "Preskenovať všetky knižnice",
@@ -1585,7 +1602,7 @@
"search_by_context": "Hľadať s kontextom", "search_by_context": "Hľadať s kontextom",
"search_by_description": "Vyhľadávanie podľa popisu", "search_by_description": "Vyhľadávanie podľa popisu",
"search_by_description_example": "Pešia turistika v Sape", "search_by_description_example": "Pešia turistika v Sape",
"search_by_filename": "Hľadať s názvom alebo príponou súboru", "search_by_filename": "Hľadať podľa názvu alebo prípony súboru",
"search_by_filename_example": "napr. IMG_1234.JPG alebo PNG", "search_by_filename_example": "napr. IMG_1234.JPG alebo PNG",
"search_camera_make": "Hľadať značku fotoaparátu...", "search_camera_make": "Hľadať značku fotoaparátu...",
"search_camera_model": "Hľadať model fotoaparátu...", "search_camera_model": "Hľadať model fotoaparátu...",
@@ -1809,7 +1826,7 @@
"stacked_assets_count": "{count, plural, one {Zoskupená # položka} few {Zoskupené # položky} other {Zoskupených # položiek}}", "stacked_assets_count": "{count, plural, one {Zoskupená # položka} few {Zoskupené # položky} other {Zoskupených # položiek}}",
"stacktrace": "Výpis zásobníku", "stacktrace": "Výpis zásobníku",
"start": "Štart", "start": "Štart",
"start_date": "Začiatočný dátum", "start_date": "Počiatočný dátum",
"state": "Štát", "state": "Štát",
"status": "Stav", "status": "Stav",
"stop_casting": "Zastaviť prenos", "stop_casting": "Zastaviť prenos",
@@ -1822,6 +1839,7 @@
"storage_quota": "Úložný limit", "storage_quota": "Úložný limit",
"storage_usage": "Využitých {used} z {available}", "storage_usage": "Využitých {used} z {available}",
"submit": "Odoslať", "submit": "Odoslať",
"success": "Úspech",
"suggestions": "Návrhy", "suggestions": "Návrhy",
"sunrise_on_the_beach": "Východ slnka na pláži", "sunrise_on_the_beach": "Východ slnka na pláži",
"support": "Podpora", "support": "Podpora",
@@ -1831,9 +1849,11 @@
"sync": "Synchronizovať", "sync": "Synchronizovať",
"sync_albums": "Synchronizovať albumy", "sync_albums": "Synchronizovať albumy",
"sync_albums_manual_subtitle": "Synchronizujte všetky nahrané videá a fotografie s vybranými záložnými albumami", "sync_albums_manual_subtitle": "Synchronizujte všetky nahrané videá a fotografie s vybranými záložnými albumami",
"sync_local": "Synchronizovať lokálne",
"sync_remote": "Synchronizovať vzdialené",
"sync_upload_album_setting_subtitle": "Vytvárajte a nahrávajte svoje fotografie a videá do vybraných albumov na Immich", "sync_upload_album_setting_subtitle": "Vytvárajte a nahrávajte svoje fotografie a videá do vybraných albumov na Immich",
"tag": "Štítok", "tag": "Štítok",
"tag_assets": "Označiť položky", "tag_assets": "Pridať štítky",
"tag_created": "Vytvorený štítok: {tag}", "tag_created": "Vytvorený štítok: {tag}",
"tag_feature_description": "Prehliadanie fotiek a videá zoskupených podľa tematických štítkov", "tag_feature_description": "Prehliadanie fotiek a videá zoskupených podľa tematických štítkov",
"tag_not_found_question": "Neviete nájsť štítok? <link>Vytvorte nový štítok.</link>", "tag_not_found_question": "Neviete nájsť štítok? <link>Vytvorte nový štítok.</link>",
@@ -1841,6 +1861,7 @@
"tag_updated": "Upravený štítok: {tag}", "tag_updated": "Upravený štítok: {tag}",
"tagged_assets": "Štítok priradený {count, plural, one {# položke} other {# položkám}}", "tagged_assets": "Štítok priradený {count, plural, one {# položke} other {# položkám}}",
"tags": "Štítky", "tags": "Štítky",
"tap_to_run_job": "Ťuknutím na položku spustíte úlohu",
"template": "Šablóna", "template": "Šablóna",
"theme": "Téma", "theme": "Téma",
"theme_selection": "Výber témy", "theme_selection": "Výber témy",
@@ -1863,7 +1884,7 @@
"time_based_memories": "Časové spomienky", "time_based_memories": "Časové spomienky",
"timeline": "Časová os", "timeline": "Časová os",
"timezone": "Časové pásmo", "timezone": "Časové pásmo",
"to_archive": "Archív", "to_archive": "Archivovať",
"to_change_password": "Zmeniť heslo", "to_change_password": "Zmeniť heslo",
"to_favorite": "Obľúbiť", "to_favorite": "Obľúbiť",
"to_login": "Prihlásiť", "to_login": "Prihlásiť",
@@ -1898,7 +1919,7 @@
"unfavorite_action_prompt": "{count} odstránené z Obľúbených", "unfavorite_action_prompt": "{count} odstránené z Obľúbených",
"unhide_person": "Odkryť osobu", "unhide_person": "Odkryť osobu",
"unknown": "Neznáme", "unknown": "Neznáme",
"unknown_country": "Neznámy štát", "unknown_country": "Neznáma krajina",
"unknown_year": "Neznámy rok", "unknown_year": "Neznámy rok",
"unlimited": "Neobmedzené", "unlimited": "Neobmedzené",
"unlink_motion_video": "Odpojiť pohyblivé video", "unlink_motion_video": "Odpojiť pohyblivé video",
@@ -1986,7 +2007,7 @@
"viewer_stack_use_as_main_asset": "Použiť ako hlavnú fotku", "viewer_stack_use_as_main_asset": "Použiť ako hlavnú fotku",
"viewer_unstack": "Odskupiť", "viewer_unstack": "Odskupiť",
"visibility_changed": "Viditeľnosť zmenená pre {count, plural, one {# osobu} few {# osoby} other {# osôb}}", "visibility_changed": "Viditeľnosť zmenená pre {count, plural, one {# osobu} few {# osoby} other {# osôb}}",
"waiting": "Čaká", "waiting": "Čakajúce",
"warning": "Varovanie", "warning": "Varovanie",
"week": "Týždeň", "week": "Týždeň",
"welcome": "Vitajte", "welcome": "Vitajte",
@@ -1996,7 +2017,7 @@
"year": "Rok", "year": "Rok",
"years_ago": "pred {years, plural, one {# rokom} other {# rokmi}}", "years_ago": "pred {years, plural, one {# rokom} other {# rokmi}}",
"yes": "Áno", "yes": "Áno",
"you_dont_have_any_shared_links": "Nemáte žiadne zdielané linky", "you_dont_have_any_shared_links": "Nemáte žiadne zdielané odkazy",
"your_wifi_name": "Váš názov siete Wi-Fi", "your_wifi_name": "Váš názov siete Wi-Fi",
"zoom_image": "Priblížiť obrázok" "zoom_image": "Priblížiť obrázok"
} }

View File

@@ -573,6 +573,8 @@
"backup_options_page_title": "Možnosti varnostne kopije", "backup_options_page_title": "Možnosti varnostne kopije",
"backup_setting_subtitle": "Upravljaj nastavitve nalaganja v ozadju in ospredju", "backup_setting_subtitle": "Upravljaj nastavitve nalaganja v ozadju in ospredju",
"backward": "Nazaj", "backward": "Nazaj",
"beta_sync": "Stanje sinhronizacije beta različice",
"beta_sync_subtitle": "Upravljanje novega sistema sinhronizacije",
"biometric_auth_enabled": "Biometrična avtentikacija omogočena", "biometric_auth_enabled": "Biometrična avtentikacija omogočena",
"biometric_locked_out": "Biometrična avtentikacija vam je onemogočena", "biometric_locked_out": "Biometrična avtentikacija vam je onemogočena",
"biometric_no_options": "Biometrične možnosti niso na voljo", "biometric_no_options": "Biometrične možnosti niso na voljo",
@@ -590,7 +592,7 @@
"cache_settings_clear_cache_button": "Počisti predpomnilnik", "cache_settings_clear_cache_button": "Počisti predpomnilnik",
"cache_settings_clear_cache_button_title": "Počisti predpomnilnik aplikacije. To bo znatno vplivalo na delovanje aplikacije, dokler se predpomnilnik ne obnovi.", "cache_settings_clear_cache_button_title": "Počisti predpomnilnik aplikacije. To bo znatno vplivalo na delovanje aplikacije, dokler se predpomnilnik ne obnovi.",
"cache_settings_duplicated_assets_clear_button": "POČISTI", "cache_settings_duplicated_assets_clear_button": "POČISTI",
"cache_settings_duplicated_assets_subtitle": "Fotografije in videoposnetki, ki jih je aplikacija uvrstila na črni seznam", "cache_settings_duplicated_assets_subtitle": "Fotografije in videoposnetki, ki so prezrti s strani aplikacije",
"cache_settings_duplicated_assets_title": "Podvojena sredstva ({count})", "cache_settings_duplicated_assets_title": "Podvojena sredstva ({count})",
"cache_settings_statistics_album": "Sličice knjižnice", "cache_settings_statistics_album": "Sličice knjižnice",
"cache_settings_statistics_full": "Izvirne slike", "cache_settings_statistics_full": "Izvirne slike",
@@ -1051,6 +1053,9 @@
"haptic_feedback_switch": "Uporabi haptičen odziv", "haptic_feedback_switch": "Uporabi haptičen odziv",
"haptic_feedback_title": "Haptičen odziv", "haptic_feedback_title": "Haptičen odziv",
"has_quota": "Ima kvoto", "has_quota": "Ima kvoto",
"hash_asset": "Zgoščeno sredstvo",
"hashed_assets": "Zgoščena sredstva",
"hashing": "Zgoščevanje",
"header_settings_add_header_tip": "Dodaj glavo", "header_settings_add_header_tip": "Dodaj glavo",
"header_settings_field_validator_msg": "Vrednost ne sme biti prazna", "header_settings_field_validator_msg": "Vrednost ne sme biti prazna",
"header_settings_header_name_input": "Ime glave", "header_settings_header_name_input": "Ime glave",
@@ -1083,6 +1088,7 @@
"host": "Gostitelj", "host": "Gostitelj",
"hour": "Ura", "hour": "Ura",
"id": "ID", "id": "ID",
"idle": "Nedejavnost",
"ignore_icloud_photos": "Ignoriraj fotografije iCloud", "ignore_icloud_photos": "Ignoriraj fotografije iCloud",
"ignore_icloud_photos_description": "Fotografije, shranjene v iCloud, ne bodo naložene na strežnik Immich", "ignore_icloud_photos_description": "Fotografije, shranjene v iCloud, ne bodo naložene na strežnik Immich",
"image": "Slika", "image": "Slika",
@@ -1165,7 +1171,9 @@
"list": "Seznam", "list": "Seznam",
"loading": "Nalaganje", "loading": "Nalaganje",
"loading_search_results_failed": "Nalaganje rezultatov iskanja ni uspelo", "loading_search_results_failed": "Nalaganje rezultatov iskanja ni uspelo",
"local": "Lokalno",
"local_asset_cast_failed": "Sredstva, ki niso naložena na strežnik, ni mogoče predvajati", "local_asset_cast_failed": "Sredstva, ki niso naložena na strežnik, ni mogoče predvajati",
"local_assets": "Lokalna sredstva",
"local_network": "Lokalno omrežje", "local_network": "Lokalno omrežje",
"local_network_sheet_info": "Aplikacija se bo povezala s strežnikom prek tega URL-ja, ko bo uporabljala navedeno omrežje Wi-Fi", "local_network_sheet_info": "Aplikacija se bo povezala s strežnikom prek tega URL-ja, ko bo uporabljala navedeno omrežje Wi-Fi",
"location_permission": "Dovoljenje za lokacijo", "location_permission": "Dovoljenje za lokacijo",
@@ -1322,6 +1330,7 @@
"no_results": "Brez rezultatov", "no_results": "Brez rezultatov",
"no_results_description": "Poskusite s sinonimom ali bolj splošno ključno besedo", "no_results_description": "Poskusite s sinonimom ali bolj splošno ključno besedo",
"no_shared_albums_message": "Ustvarite album za skupno rabo fotografij in videoposnetkov z osebami v vašem omrežju", "no_shared_albums_message": "Ustvarite album za skupno rabo fotografij in videoposnetkov z osebami v vašem omrežju",
"no_uploads_in_progress": "Ni nalaganj v teku",
"not_in_any_album": "Ni v nobenem albumu", "not_in_any_album": "Ni v nobenem albumu",
"not_selected": "Ni izbrano", "not_selected": "Ni izbrano",
"note_apply_storage_label_to_previously_uploaded assets": "Opomba: Če želite oznako za shranjevanje uporabiti za predhodno naložena sredstva, zaženite", "note_apply_storage_label_to_previously_uploaded assets": "Opomba: Če želite oznako za shranjevanje uporabiti za predhodno naložena sredstva, zaženite",
@@ -1359,6 +1368,7 @@
"original": "izvirnik", "original": "izvirnik",
"other": "drugo", "other": "drugo",
"other_devices": "Druge naprave", "other_devices": "Druge naprave",
"other_entities": "Drugi subjekti",
"other_variables": "Druge spremenljivke", "other_variables": "Druge spremenljivke",
"owned": "V lasti", "owned": "V lasti",
"owner": "Lastnik", "owner": "Lastnik",
@@ -1390,7 +1400,7 @@
"pause": "Premor", "pause": "Premor",
"pause_memories": "Zaustavi spomine", "pause_memories": "Zaustavi spomine",
"paused": "Zaustavljeno", "paused": "Zaustavljeno",
"pending": "V teku", "pending": "Čakanje",
"people": "Osebe", "people": "Osebe",
"people_edits_count": "{count, plural, one {Urejena # oseba} two {Urejeni # osebi} few {Urejene # osebe} other {Urejenih # oseb}}", "people_edits_count": "{count, plural, one {Urejena # oseba} two {Urejeni # osebi} few {Urejene # osebe} other {Urejenih # oseb}}",
"people_feature_description": "Brskanje po fotografijah in videoposnetkih, razvrščenih po osebah", "people_feature_description": "Brskanje po fotografijah in videoposnetkih, razvrščenih po osebah",
@@ -1519,6 +1529,8 @@
"refreshing_faces": "Osveževanje obrazev", "refreshing_faces": "Osveževanje obrazev",
"refreshing_metadata": "Osveževanje metapodatkov", "refreshing_metadata": "Osveževanje metapodatkov",
"regenerating_thumbnails": "Obnavljanje sličic", "regenerating_thumbnails": "Obnavljanje sličic",
"remote": "Oddaljeno",
"remote_assets": "Oddaljena sredstva",
"remove": "Odstrani", "remove": "Odstrani",
"remove_assets_album_confirmation": "Ali ste prepričani, da želite odstraniti {count, plural, one {# sredstvo} two {# sredstvi} few {# sredstva} other {# sredstev}} iz albuma?", "remove_assets_album_confirmation": "Ali ste prepričani, da želite odstraniti {count, plural, one {# sredstvo} two {# sredstvi} few {# sredstva} other {# sredstev}} iz albuma?",
"remove_assets_shared_link_confirmation": "Ali ste prepričani, da želite odstraniti {count, plural, one {# sredstvo} two {# sredstvi} few {# sredstva} other {# sredstev}} iz te skupne povezave?", "remove_assets_shared_link_confirmation": "Ali ste prepričani, da želite odstraniti {count, plural, one {# sredstvo} two {# sredstvi} few {# sredstva} other {# sredstev}} iz te skupne povezave?",
@@ -1556,11 +1568,15 @@
"reset_password": "Ponastavi geslo", "reset_password": "Ponastavi geslo",
"reset_people_visibility": "Ponastavi vidnost ljudi", "reset_people_visibility": "Ponastavi vidnost ljudi",
"reset_pin_code": "Ponastavi PIN kodo", "reset_pin_code": "Ponastavi PIN kodo",
"reset_sqlite": "Ponastavi bazo podatkov SQLite",
"reset_sqlite_confirmation": "Ali ste prepričani, da želite ponastaviti bazo podatkov SQLite? Za ponovno sinhronizacijo podatkov se boste morali odjaviti in znova prijaviti",
"reset_sqlite_success": "Uspešno ponastavljena baza podatkov SQLite",
"reset_to_default": "Ponastavi na privzeto", "reset_to_default": "Ponastavi na privzeto",
"resolve_duplicates": "Razreši dvojnike", "resolve_duplicates": "Razreši dvojnike",
"resolved_all_duplicates": "Razrešeni vsi dvojniki", "resolved_all_duplicates": "Razrešeni vsi dvojniki",
"restore": "Obnovi", "restore": "Obnovi",
"restore_all": "Obnovi vse", "restore_all": "Obnovi vse",
"restore_trash_action_prompt": "{count} obnovljenih iz koša",
"restore_user": "Obnovi uporabnika", "restore_user": "Obnovi uporabnika",
"restored_asset": "Obnovljeno sredstvo", "restored_asset": "Obnovljeno sredstvo",
"resume": "Nadaljuj", "resume": "Nadaljuj",
@@ -1569,6 +1585,7 @@
"role": "Vloga", "role": "Vloga",
"role_editor": "Urejevalec", "role_editor": "Urejevalec",
"role_viewer": "Gledalec", "role_viewer": "Gledalec",
"running": "V teku",
"save": "Shrani", "save": "Shrani",
"save_to_gallery": "Shrani v galerijo", "save_to_gallery": "Shrani v galerijo",
"saved_api_key": "Shranjen API ključ", "saved_api_key": "Shranjen API ključ",
@@ -1822,6 +1839,7 @@
"storage_quota": "Kvota shranjevanja", "storage_quota": "Kvota shranjevanja",
"storage_usage": "uporabljeno {used} od {available}", "storage_usage": "uporabljeno {used} od {available}",
"submit": "Predloži", "submit": "Predloži",
"success": "Uspeh",
"suggestions": "Predlogi", "suggestions": "Predlogi",
"sunrise_on_the_beach": "Sončni vzhod na plaži", "sunrise_on_the_beach": "Sončni vzhod na plaži",
"support": "Podpora", "support": "Podpora",
@@ -1831,6 +1849,8 @@
"sync": "Sinhronizacija", "sync": "Sinhronizacija",
"sync_albums": "Sinhronizacija albumov", "sync_albums": "Sinhronizacija albumov",
"sync_albums_manual_subtitle": "Sinhronizirajte vse naložene videoposnetke in fotografije v izbrane varnostne albume", "sync_albums_manual_subtitle": "Sinhronizirajte vse naložene videoposnetke in fotografije v izbrane varnostne albume",
"sync_local": "Sinhroniziraj lokalno",
"sync_remote": "Sinhroniziraj oddaljeno",
"sync_upload_album_setting_subtitle": "Ustvarite in naložite svoje fotografije in videoposnetke v izbrane albume na Immich", "sync_upload_album_setting_subtitle": "Ustvarite in naložite svoje fotografije in videoposnetke v izbrane albume na Immich",
"tag": "Oznaka", "tag": "Oznaka",
"tag_assets": "Označi sredstva", "tag_assets": "Označi sredstva",
@@ -1841,6 +1861,7 @@
"tag_updated": "Posodobljena oznaka: {tag}", "tag_updated": "Posodobljena oznaka: {tag}",
"tagged_assets": "Označeno {count, plural, one {# sredstvo} two {# sredstvi} few {# sredstva} other {# sredstev}}", "tagged_assets": "Označeno {count, plural, one {# sredstvo} two {# sredstvi} few {# sredstva} other {# sredstev}}",
"tags": "Oznake", "tags": "Oznake",
"tap_to_run_job": "Dotaknite se za zagon opravila",
"template": "Predloga", "template": "Predloga",
"theme": "Tema", "theme": "Tema",
"theme_selection": "Izbira teme", "theme_selection": "Izbira teme",

View File

@@ -573,6 +573,8 @@
"backup_options_page_title": "备份选项", "backup_options_page_title": "备份选项",
"backup_setting_subtitle": "管理后台和前台上传设置", "backup_setting_subtitle": "管理后台和前台上传设置",
"backward": "后退", "backward": "后退",
"beta_sync": "测试版同步状态",
"beta_sync_subtitle": "管理新的同步系统",
"biometric_auth_enabled": "生物识别身份验证已启用", "biometric_auth_enabled": "生物识别身份验证已启用",
"biometric_locked_out": "您被锁定在生物识别身份验证之外", "biometric_locked_out": "您被锁定在生物识别身份验证之外",
"biometric_no_options": "没有可用的生物识别选项", "biometric_no_options": "没有可用的生物识别选项",
@@ -590,7 +592,7 @@
"cache_settings_clear_cache_button": "清除缓存", "cache_settings_clear_cache_button": "清除缓存",
"cache_settings_clear_cache_button_title": "清除应用缓存。在重新生成缓存之前,将显著影响应用的性能。", "cache_settings_clear_cache_button_title": "清除应用缓存。在重新生成缓存之前,将显著影响应用的性能。",
"cache_settings_duplicated_assets_clear_button": "清除", "cache_settings_duplicated_assets_clear_button": "清除",
"cache_settings_duplicated_assets_subtitle": "已加入黑名单的照片和视频", "cache_settings_duplicated_assets_subtitle": "应用程序忽略的照片和视频",
"cache_settings_duplicated_assets_title": "重复项目({count}", "cache_settings_duplicated_assets_title": "重复项目({count}",
"cache_settings_statistics_album": "图库缩略图", "cache_settings_statistics_album": "图库缩略图",
"cache_settings_statistics_full": "完整图像", "cache_settings_statistics_full": "完整图像",
@@ -1051,6 +1053,9 @@
"haptic_feedback_switch": "启用振动反馈", "haptic_feedback_switch": "启用振动反馈",
"haptic_feedback_title": "振动反馈", "haptic_feedback_title": "振动反馈",
"has_quota": "配额大小", "has_quota": "配额大小",
"hash_asset": "哈希项目",
"hashed_assets": "已哈希的项目",
"hashing": "正在哈希",
"header_settings_add_header_tip": "添加标头", "header_settings_add_header_tip": "添加标头",
"header_settings_field_validator_msg": "设置不可为空", "header_settings_field_validator_msg": "设置不可为空",
"header_settings_header_name_input": "标头名称", "header_settings_header_name_input": "标头名称",
@@ -1083,6 +1088,7 @@
"host": "服务器", "host": "服务器",
"hour": "时", "hour": "时",
"id": "ID", "id": "ID",
"idle": "空闲",
"ignore_icloud_photos": "忽略 iCloud 照片", "ignore_icloud_photos": "忽略 iCloud 照片",
"ignore_icloud_photos_description": "存储在 iCloud 中的照片不会上传至 Immich 服务器", "ignore_icloud_photos_description": "存储在 iCloud 中的照片不会上传至 Immich 服务器",
"image": "图片", "image": "图片",
@@ -1165,7 +1171,9 @@
"list": "列表", "list": "列表",
"loading": "加载中", "loading": "加载中",
"loading_search_results_failed": "加载搜索结果失败", "loading_search_results_failed": "加载搜索结果失败",
"local": "本地",
"local_asset_cast_failed": "无法投放未上传至服务器的项目", "local_asset_cast_failed": "无法投放未上传至服务器的项目",
"local_assets": "本地项目",
"local_network": "本地网络", "local_network": "本地网络",
"local_network_sheet_info": "当使用指定的 Wi-Fi 网络时,应用程序将通过此 URL 访问服务器", "local_network_sheet_info": "当使用指定的 Wi-Fi 网络时,应用程序将通过此 URL 访问服务器",
"location_permission": "定位权限", "location_permission": "定位权限",
@@ -1322,6 +1330,7 @@
"no_results": "无结果", "no_results": "无结果",
"no_results_description": "尝试使用同义词或更通用的关键词", "no_results_description": "尝试使用同义词或更通用的关键词",
"no_shared_albums_message": "创建相册以共享照片和视频", "no_shared_albums_message": "创建相册以共享照片和视频",
"no_uploads_in_progress": "没有正在进行的上传",
"not_in_any_album": "不在任何相册中", "not_in_any_album": "不在任何相册中",
"not_selected": "未选择", "not_selected": "未选择",
"note_apply_storage_label_to_previously_uploaded assets": "提示:要将存储标签应用于之前上传的项目,需要运行", "note_apply_storage_label_to_previously_uploaded assets": "提示:要将存储标签应用于之前上传的项目,需要运行",
@@ -1359,6 +1368,7 @@
"original": "原图", "original": "原图",
"other": "其它", "other": "其它",
"other_devices": "其它设备", "other_devices": "其它设备",
"other_entities": "其他实体",
"other_variables": "其它变量", "other_variables": "其它变量",
"owned": "我的", "owned": "我的",
"owner": "所有者", "owner": "所有者",
@@ -1519,6 +1529,8 @@
"refreshing_faces": "正在面部重新识别", "refreshing_faces": "正在面部重新识别",
"refreshing_metadata": "正在刷新元数据", "refreshing_metadata": "正在刷新元数据",
"regenerating_thumbnails": "正在重新生成缩略图", "regenerating_thumbnails": "正在重新生成缩略图",
"remote": "远程",
"remote_assets": "远程项目",
"remove": "移除", "remove": "移除",
"remove_assets_album_confirmation": "确定要从图库中移除{count, plural, one {#个项目} other {#个项目}}", "remove_assets_album_confirmation": "确定要从图库中移除{count, plural, one {#个项目} other {#个项目}}",
"remove_assets_shared_link_confirmation": "确定要从共享链接中移除{count, plural, one {#个项目} other {#个项目}}", "remove_assets_shared_link_confirmation": "确定要从共享链接中移除{count, plural, one {#个项目} other {#个项目}}",
@@ -1556,11 +1568,15 @@
"reset_password": "重置密码", "reset_password": "重置密码",
"reset_people_visibility": "重置人物识别", "reset_people_visibility": "重置人物识别",
"reset_pin_code": "重置PIN码", "reset_pin_code": "重置PIN码",
"reset_sqlite": "重置 SQLite 数据库",
"reset_sqlite_confirmation": "您确定要重置 SQLite 数据库吗?您需要注销并重新登录才能重新同步数据",
"reset_sqlite_success": "已成功重置 SQLite 数据库",
"reset_to_default": "恢复默认值", "reset_to_default": "恢复默认值",
"resolve_duplicates": "处理重复项", "resolve_duplicates": "处理重复项",
"resolved_all_duplicates": "处理所有重复项", "resolved_all_duplicates": "处理所有重复项",
"restore": "恢复", "restore": "恢复",
"restore_all": "恢复全部", "restore_all": "恢复全部",
"restore_trash_action_prompt": "从回收站中恢复了 {count} 项",
"restore_user": "恢复用户", "restore_user": "恢复用户",
"restored_asset": "已恢复项目", "restored_asset": "已恢复项目",
"resume": "继续", "resume": "继续",
@@ -1569,6 +1585,7 @@
"role": "选择用户权限", "role": "选择用户权限",
"role_editor": "可编辑", "role_editor": "可编辑",
"role_viewer": "仅查看", "role_viewer": "仅查看",
"running": "正在运行",
"save": "保存", "save": "保存",
"save_to_gallery": "保存到图库", "save_to_gallery": "保存到图库",
"saved_api_key": "已保存的 API 密钥", "saved_api_key": "已保存的 API 密钥",
@@ -1822,6 +1839,7 @@
"storage_quota": "存储配额", "storage_quota": "存储配额",
"storage_usage": "已用:{used}/{available}", "storage_usage": "已用:{used}/{available}",
"submit": "提交", "submit": "提交",
"success": "成功",
"suggestions": "建议", "suggestions": "建议",
"sunrise_on_the_beach": "海滩上的日出", "sunrise_on_the_beach": "海滩上的日出",
"support": "支持", "support": "支持",
@@ -1831,6 +1849,8 @@
"sync": "同步", "sync": "同步",
"sync_albums": "同步相册", "sync_albums": "同步相册",
"sync_albums_manual_subtitle": "将所有上传的视频和照片同步到选定的备份相册", "sync_albums_manual_subtitle": "将所有上传的视频和照片同步到选定的备份相册",
"sync_local": "同步本地",
"sync_remote": "同步远程",
"sync_upload_album_setting_subtitle": "创建照片和视频并上传到 Immich 上的选定相册中", "sync_upload_album_setting_subtitle": "创建照片和视频并上传到 Immich 上的选定相册中",
"tag": "标签", "tag": "标签",
"tag_assets": "标记项目", "tag_assets": "标记项目",
@@ -1841,6 +1861,7 @@
"tag_updated": "已更新标签:{tag}", "tag_updated": "已更新标签:{tag}",
"tagged_assets": "{count, plural, one {# 个项目} other {# 个项目}}被加上标签", "tagged_assets": "{count, plural, one {# 个项目} other {# 个项目}}被加上标签",
"tags": "标签", "tags": "标签",
"tap_to_run_job": "点击运行作业",
"template": "模版", "template": "模版",
"theme": "主题", "theme": "主题",
"theme_selection": "主题选项", "theme_selection": "主题选项",

View File

@@ -1,5 +1,9 @@
{ {
"dart.flutterSdkPath": ".fvm/versions/3.32.6", "dart.flutterSdkPath": ".fvm/versions/3.32.6",
"dart.lineLength": 120,
"[dart]": {
"editor.rulers": [120],
},
"search.exclude": { "search.exclude": {
"**/.fvm": true "**/.fvm": true
}, },

View File

@@ -9,6 +9,9 @@
# packages, and plugins designed to encourage good coding practices. # packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml include: package:flutter_lints/flutter.yaml
formatter:
page_width: 120
linter: linter:
# The lint rules applied to this project can be customized in the # The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml` # section below to disable rules from the `package:flutter_lints/flutter.yaml`

View File

@@ -72,20 +72,6 @@ android {
} }
} }
flavorDimensions "default"
productFlavors {
production {
dimension "default"
applicationId "app.alextran.immich"
}
beta {
dimension "default"
applicationId "app.alextran.immich.beta"
versionNameSuffix "-BETA"
}
}
buildTypes { buildTypes {
debug { debug {
applicationIdSuffix '.debug' applicationIdSuffix '.debug'

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application android:label="Immich Beta" tools:replace="android:label" />
</manifest>

View File

@@ -35,8 +35,8 @@ platform :android do
task: 'bundle', task: 'bundle',
build_type: 'Release', build_type: 'Release',
properties: { properties: {
"android.injected.version.code" => 204, "android.injected.version.code" => 205,
"android.injected.version.name" => "1.135.3", "android.injected.version.name" => "1.136.0",
} }
) )
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab') upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -22,7 +22,7 @@ platform :ios do
path: "./Runner.xcodeproj", path: "./Runner.xcodeproj",
) )
increment_version_number( increment_version_number(
version_number: "1.135.3" version_number: "1.136.0"
) )
increment_build_number( increment_build_number(
build_number: latest_testflight_build_number + 1, build_number: latest_testflight_build_number + 1,

View File

@@ -10,7 +10,7 @@ enum ImmichColorPreset {
lime, lime,
green, green,
cyan, cyan,
slateGray slateGray,
} }
const ImmichColorPreset defaultColorPreset = ImmichColorPreset.indigo; const ImmichColorPreset defaultColorPreset = ImmichColorPreset.indigo;

View File

@@ -7,10 +7,8 @@ const Map<String, Locale> locales = {
'Arabic (ar)': Locale('ar'), 'Arabic (ar)': Locale('ar'),
'Bulgarian (bg)': Locale('bg'), 'Bulgarian (bg)': Locale('bg'),
'Catalan (ca)': Locale('ca'), 'Catalan (ca)': Locale('ca'),
'Chinese Simplified (zh_CN)': 'Chinese Simplified (zh_CN)': Locale.fromSubtags(languageCode: 'zh', scriptCode: 'SIMPLIFIED'),
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'SIMPLIFIED'), 'Chinese Traditional (zh_TW)': Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'),
'Chinese Traditional (zh_TW)':
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'),
'Croatian (hr)': Locale('hr'), 'Croatian (hr)': Locale('hr'),
'Czech (cs)': Locale('cs'), 'Czech (cs)': Locale('cs'),
'Danish (da)': Locale('da'), 'Danish (da)': Locale('da'),
@@ -37,10 +35,8 @@ const Map<String, Locale> locales = {
'Portuguese (pt)': Locale('pt'), 'Portuguese (pt)': Locale('pt'),
'Romanian (ro)': Locale('ro'), 'Romanian (ro)': Locale('ro'),
'Russian (ru)': Locale('ru'), 'Russian (ru)': Locale('ru'),
'Serbian Cyrillic (sr_Cyrl)': 'Serbian Cyrillic (sr_Cyrl)': Locale.fromSubtags(languageCode: 'sr', scriptCode: 'Cyrl'),
Locale.fromSubtags(languageCode: 'sr', scriptCode: 'Cyrl'), 'Serbian Latin (sr_Latn)': Locale.fromSubtags(languageCode: 'sr', scriptCode: 'Latn'),
'Serbian Latin (sr_Latn)':
Locale.fromSubtags(languageCode: 'sr', scriptCode: 'Latn'),
'Slovak (sk)': Locale('sk'), 'Slovak (sk)': Locale('sk'),
'Slovenian (sl)': Locale('sl'), 'Slovenian (sl)': Locale('sl'),
'Spanish (es)': Locale('es'), 'Spanish (es)': Locale('es'),

View File

@@ -53,10 +53,8 @@ sealed class BaseAsset {
return const Duration(); return const Duration();
} }
bool get hasRemote => bool get hasRemote => storage == AssetState.remote || storage == AssetState.merged;
storage == AssetState.remote || storage == AssetState.merged; bool get hasLocal => storage == AssetState.local || storage == AssetState.merged;
bool get hasLocal =>
storage == AssetState.local || storage == AssetState.merged;
bool get isLocalOnly => storage == AssetState.local; bool get isLocalOnly => storage == AssetState.local;
bool get isRemoteOnly => storage == AssetState.remote; bool get isRemoteOnly => storage == AssetState.remote;

View File

@@ -22,8 +22,7 @@ class LocalAsset extends BaseAsset {
}); });
@override @override
AssetState get storage => AssetState get storage => remoteId == null ? AssetState.local : AssetState.merged;
remoteId == null ? AssetState.local : AssetState.merged;
@override @override
String get heroTag => '${id}_${remoteId ?? checksum}'; String get heroTag => '${id}_${remoteId ?? checksum}';
@@ -54,8 +53,7 @@ class LocalAsset extends BaseAsset {
} }
@override @override
int get hashCode => int get hashCode => super.hashCode ^ id.hashCode ^ remoteId.hashCode ^ orientation.hashCode;
super.hashCode ^ id.hashCode ^ remoteId.hashCode ^ orientation.hashCode;
LocalAsset copyWith({ LocalAsset copyWith({
String? id, String? id,

View File

@@ -15,7 +15,6 @@ class RemoteAsset extends BaseAsset {
final AssetVisibility visibility; final AssetVisibility visibility;
final String ownerId; final String ownerId;
final String? stackId; final String? stackId;
final int stackCount;
const RemoteAsset({ const RemoteAsset({
required this.id, required this.id,
@@ -34,12 +33,10 @@ class RemoteAsset extends BaseAsset {
this.visibility = AssetVisibility.timeline, this.visibility = AssetVisibility.timeline,
super.livePhotoVideoId, super.livePhotoVideoId,
this.stackId, this.stackId,
this.stackCount = 0,
}); });
@override @override
AssetState get storage => AssetState get storage => localId == null ? AssetState.remote : AssetState.merged;
localId == null ? AssetState.remote : AssetState.merged;
@override @override
String get heroTag => '${localId ?? checksum}_$id'; String get heroTag => '${localId ?? checksum}_$id';
@@ -61,7 +58,6 @@ class RemoteAsset extends BaseAsset {
thumbHash: ${thumbHash ?? "<NA>"}, thumbHash: ${thumbHash ?? "<NA>"},
visibility: $visibility, visibility: $visibility,
stackId: ${stackId ?? "<NA>"}, stackId: ${stackId ?? "<NA>"},
stackCount: $stackCount,
checksum: $checksum, checksum: $checksum,
livePhotoVideoId: ${livePhotoVideoId ?? "<NA>"}, livePhotoVideoId: ${livePhotoVideoId ?? "<NA>"},
}'''; }''';
@@ -77,8 +73,7 @@ class RemoteAsset extends BaseAsset {
ownerId == other.ownerId && ownerId == other.ownerId &&
thumbHash == other.thumbHash && thumbHash == other.thumbHash &&
visibility == other.visibility && visibility == other.visibility &&
stackId == other.stackId && stackId == other.stackId;
stackCount == other.stackCount;
} }
@override @override
@@ -89,8 +84,7 @@ class RemoteAsset extends BaseAsset {
localId.hashCode ^ localId.hashCode ^
thumbHash.hashCode ^ thumbHash.hashCode ^
visibility.hashCode ^ visibility.hashCode ^
stackId.hashCode ^ stackId.hashCode;
stackCount.hashCode;
RemoteAsset copyWith({ RemoteAsset copyWith({
String? id, String? id,
@@ -109,7 +103,6 @@ class RemoteAsset extends BaseAsset {
AssetVisibility? visibility, AssetVisibility? visibility,
String? livePhotoVideoId, String? livePhotoVideoId,
String? stackId, String? stackId,
int? stackCount,
}) { }) {
return RemoteAsset( return RemoteAsset(
id: id ?? this.id, id: id ?? this.id,
@@ -128,7 +121,6 @@ class RemoteAsset extends BaseAsset {
visibility: visibility ?? this.visibility, visibility: visibility ?? this.visibility,
livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId, livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId,
stackId: stackId ?? this.stackId, stackId: stackId ?? this.stackId,
stackCount: stackCount ?? this.stackCount,
); );
} }
} }

View File

@@ -15,9 +15,7 @@ class DeviceAsset {
bool operator ==(covariant DeviceAsset other) { bool operator ==(covariant DeviceAsset other) {
if (identical(this, other)) return true; if (identical(this, other)) return true;
return other.assetId == assetId && return other.assetId == assetId && other.hash == hash && other.modifiedTime == modifiedTime;
other.hash == hash &&
other.modifiedTime == modifiedTime;
} }
@override @override

View File

@@ -25,8 +25,7 @@ class ExifInfo {
final int? iso; final int? iso;
final double? exposureSeconds; final double? exposureSeconds;
bool get hasCoordinates => bool get hasCoordinates => latitude != null && longitude != null && latitude != 0 && longitude != 0;
latitude != null && longitude != null && latitude != 0 && longitude != 0;
String get exposureTime { String get exposureTime {
if (exposureSeconds == null) { if (exposureSeconds == null) {

View File

@@ -43,12 +43,7 @@ class LogMessage {
@override @override
int get hashCode { int get hashCode {
return message.hashCode ^ return message.hashCode ^ level.hashCode ^ createdAt.hashCode ^ logger.hashCode ^ error.hashCode ^ stack.hashCode;
level.hashCode ^
createdAt.hashCode ^
logger.hashCode ^
error.hashCode ^
stack.hashCode;
} }
@override @override

View File

@@ -39,8 +39,7 @@ class MemoryData {
String toJson() => json.encode(toMap()); String toJson() => json.encode(toMap());
factory MemoryData.fromJson(String source) => factory MemoryData.fromJson(String source) => MemoryData.fromMap(json.decode(source) as Map<String, dynamic>);
MemoryData.fromMap(json.decode(source) as Map<String, dynamic>);
@override @override
String toString() => 'MemoryData(year: $year)'; String toString() => 'MemoryData(year: $year)';

View File

@@ -55,22 +55,17 @@ class PersonDto {
factory PersonDto.fromMap(Map<String, dynamic> map) { factory PersonDto.fromMap(Map<String, dynamic> map) {
return PersonDto( return PersonDto(
id: map['id'] as String, id: map['id'] as String,
birthDate: map['birthDate'] != null birthDate: map['birthDate'] != null ? DateTime.fromMillisecondsSinceEpoch(map['birthDate'] as int) : null,
? DateTime.fromMillisecondsSinceEpoch(map['birthDate'] as int)
: null,
isHidden: map['isHidden'] as bool, isHidden: map['isHidden'] as bool,
name: map['name'] as String, name: map['name'] as String,
thumbnailPath: map['thumbnailPath'] as String, thumbnailPath: map['thumbnailPath'] as String,
updatedAt: map['updatedAt'] != null updatedAt: map['updatedAt'] != null ? DateTime.fromMillisecondsSinceEpoch(map['updatedAt'] as int) : null,
? DateTime.fromMillisecondsSinceEpoch(map['updatedAt'] as int)
: null,
); );
} }
String toJson() => json.encode(toMap()); String toJson() => json.encode(toMap());
factory PersonDto.fromJson(String source) => factory PersonDto.fromJson(String source) => PersonDto.fromMap(json.decode(source) as Map<String, dynamic>);
PersonDto.fromMap(json.decode(source) as Map<String, dynamic>);
@override @override
bool operator ==(covariant PersonDto other) { bool operator ==(covariant PersonDto other) {

View File

@@ -1,6 +1,9 @@
import 'package:immich_mobile/domain/models/store.model.dart'; import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
enum Setting<T> { enum Setting<T> {
// TODO: Remove UserDto after new store in drift
currentUser<UserDto?>(StoreKey.currentUser, null),
tilesPerRow<int>(StoreKey.tilesPerRow, 4), tilesPerRow<int>(StoreKey.tilesPerRow, 4),
groupAssetsBy<int>(StoreKey.groupAssetsBy, 0), groupAssetsBy<int>(StoreKey.groupAssetsBy, 0),
showStorageIndicator<bool>(StoreKey.storageIndicator, true), showStorageIndicator<bool>(StoreKey.storageIndicator, true),

View File

@@ -54,11 +54,7 @@ class Stack {
@override @override
int get hashCode { int get hashCode {
return id.hashCode ^ return id.hashCode ^ createdAt.hashCode ^ updatedAt.hashCode ^ ownerId.hashCode ^ primaryAssetId.hashCode;
createdAt.hashCode ^
updatedAt.hashCode ^
ownerId.hashCode ^
primaryAssetId.hashCode;
} }
} }
@@ -77,9 +73,7 @@ class StackResponse {
bool operator ==(covariant StackResponse other) { bool operator ==(covariant StackResponse other) {
if (identical(this, other)) return true; if (identical(this, other)) return true;
return other.id == id && return other.id == id && other.primaryAssetId == primaryAssetId && other.assetIds == assetIds;
other.primaryAssetId == primaryAssetId &&
other.assetIds == assetIds;
} }
@override @override

View File

@@ -3,6 +3,7 @@ import 'package:immich_mobile/domain/utils/event_stream.dart';
enum GroupAssetsBy { enum GroupAssetsBy {
day, day,
month, month,
auto,
none; none;
} }

View File

@@ -1,9 +1,6 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';
import 'package:immich_mobile/domain/models/user_metadata.model.dart'; import 'package:immich_mobile/domain/models/user_metadata.model.dart';
// TODO: Rename to User once Isar is removed // TODO: Remove UserDto once Isar is removed
class UserDto { class UserDto {
final String id; final String id;
final String email; final String email;
@@ -44,19 +41,19 @@ class UserDto {
@override @override
String toString() { String toString() {
return '''User: { return '''User: {
id: $id, id: $id,
email: $email, email: $email,
name: $name, name: $name,
isAdmin: $isAdmin, isAdmin: $isAdmin,
updatedAt: $updatedAt, updatedAt: $updatedAt,
profileImagePath: ${profileImagePath ?? '<NA>'}, profileImagePath: ${profileImagePath ?? '<NA>'},
avatarColor: $avatarColor, avatarColor: $avatarColor,
memoryEnabled: $memoryEnabled, memoryEnabled: $memoryEnabled,
inTimeline: $inTimeline, inTimeline: $inTimeline,
isPartnerSharedBy: $isPartnerSharedBy, isPartnerSharedBy: $isPartnerSharedBy,
isPartnerSharedWith: $isPartnerSharedWith, isPartnerSharedWith: $isPartnerSharedWith,
quotaUsageInBytes: $quotaUsageInBytes, quotaUsageInBytes: $quotaUsageInBytes,
quotaSizeInBytes: $quotaSizeInBytes, quotaSizeInBytes: $quotaSizeInBytes,
}'''; }''';
} }
@@ -127,87 +124,229 @@ quotaSizeInBytes: $quotaSizeInBytes,
quotaSizeInBytes.hashCode; quotaSizeInBytes.hashCode;
} }
class PartnerUserDto { class User {
final String id; final String id;
final String email;
final String name; final String name;
final bool inTimeline; final String email;
final DateTime? deletedAt;
final AvatarColor? avatarColor;
final String? profileImagePath; const User({
const PartnerUserDto({
required this.id, required this.id,
required this.email,
required this.name, required this.name,
required this.inTimeline, required this.email,
this.profileImagePath, this.deletedAt,
this.avatarColor,
}); });
PartnerUserDto copyWith({ User copyWith({
String? id, String? id,
String? email,
String? name, String? name,
bool? inTimeline, String? email,
String? profileImagePath, DateTime? deletedAt,
AvatarColor? avatarColor,
}) { }) {
return PartnerUserDto( return User(
id: id ?? this.id, id: id ?? this.id,
email: email ?? this.email,
name: name ?? this.name, name: name ?? this.name,
inTimeline: inTimeline ?? this.inTimeline, email: email ?? this.email,
profileImagePath: profileImagePath ?? this.profileImagePath, deletedAt: deletedAt ?? this.deletedAt,
avatarColor: avatarColor ?? this.avatarColor,
); );
} }
Map<String, dynamic> toMap() {
return <String, dynamic>{
'id': id,
'email': email,
'name': name,
'inTimeline': inTimeline,
'profileImagePath': profileImagePath,
};
}
factory PartnerUserDto.fromMap(Map<String, dynamic> map) {
return PartnerUserDto(
id: map['id'] as String,
email: map['email'] as String,
name: map['name'] as String,
inTimeline: map['inTimeline'] as bool,
profileImagePath: map['profileImagePath'] != null
? map['profileImagePath'] as String
: null,
);
}
String toJson() => json.encode(toMap());
factory PartnerUserDto.fromJson(String source) =>
PartnerUserDto.fromMap(json.decode(source) as Map<String, dynamic>);
@override @override
String toString() { String toString() {
return 'PartnerUserDto(id: $id, email: $email, name: $name, inTimeline: $inTimeline, profileImagePath: $profileImagePath)'; return '''User {
id: $id,
name: $name,
email: $email,
deletedAt: ${deletedAt ?? "<NA>"},
avatarColor: ${avatarColor ?? "<NA>"},
}''';
} }
@override @override
bool operator ==(covariant PartnerUserDto other) { bool operator ==(covariant User other) {
if (identical(this, other)) return true; if (identical(this, other)) return true;
return other.id == id && return other.id == id &&
other.email == email &&
other.name == name && other.name == name &&
other.inTimeline == inTimeline && other.email == email &&
other.profileImagePath == profileImagePath; other.deletedAt == deletedAt &&
other.avatarColor == avatarColor;
}
@override
int get hashCode {
return id.hashCode ^ name.hashCode ^ email.hashCode ^ deletedAt.hashCode ^ avatarColor.hashCode;
}
}
class AuthUser {
final String id;
final String name;
final String email;
final DateTime? deletedAt;
final AvatarColor? avatarColor;
final bool isAdmin;
final String oauthId;
final String? pinCode;
final bool hasProfileImage;
final DateTime profileChangedAt;
final int? quotaSizeInBytes;
final int quotaUsageInBytes;
final String? storageLabel;
const AuthUser({
required this.id,
required this.name,
required this.email,
this.deletedAt,
this.avatarColor,
required this.isAdmin,
required this.oauthId,
this.pinCode,
required this.hasProfileImage,
required this.profileChangedAt,
this.quotaSizeInBytes,
required this.quotaUsageInBytes,
this.storageLabel,
});
AuthUser copyWith({
String? id,
String? name,
String? email,
DateTime? deletedAt,
AvatarColor? avatarColor,
bool? isAdmin,
String? oauthId,
String? pinCode,
bool? hasProfileImage,
DateTime? profileChangedAt,
int? quotaSizeInBytes,
int? quotaUsageInBytes,
String? storageLabel,
}) {
return AuthUser(
id: id ?? this.id,
name: name ?? this.name,
email: email ?? this.email,
deletedAt: deletedAt ?? this.deletedAt,
avatarColor: avatarColor ?? this.avatarColor,
isAdmin: isAdmin ?? this.isAdmin,
oauthId: oauthId ?? this.oauthId,
pinCode: pinCode ?? this.pinCode,
hasProfileImage: hasProfileImage ?? this.hasProfileImage,
profileChangedAt: profileChangedAt ?? this.profileChangedAt,
quotaSizeInBytes: quotaSizeInBytes ?? this.quotaSizeInBytes,
quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes,
storageLabel: storageLabel ?? this.storageLabel,
);
}
@override
String toString() {
return '''AuthUser {
id: $id,
name: $name,
email: $email,
deletedAt: ${deletedAt ?? "<NA>"},
avatarColor: ${avatarColor ?? "<NA>"},
isAdmin: $isAdmin,
oauthId: $oauthId,
pinCode: ${pinCode ?? "<NA>"},
hasProfileImage: $hasProfileImage,
profileChangedAt: $profileChangedAt,
quotaSizeInBytes: ${quotaSizeInBytes ?? "<NA>"},
quotaUsageInBytes: $quotaUsageInBytes,
storageLabel: ${storageLabel ?? "<NA>"},
}''';
}
@override
bool operator ==(covariant AuthUser other) {
if (identical(this, other)) return true;
return other.id == id &&
other.name == name &&
other.email == email &&
other.deletedAt == deletedAt &&
other.avatarColor == avatarColor &&
other.isAdmin == isAdmin &&
other.oauthId == oauthId &&
other.pinCode == pinCode &&
other.hasProfileImage == hasProfileImage &&
other.profileChangedAt == profileChangedAt &&
other.quotaSizeInBytes == quotaSizeInBytes &&
other.quotaUsageInBytes == quotaUsageInBytes &&
other.storageLabel == storageLabel;
} }
@override @override
int get hashCode { int get hashCode {
return id.hashCode ^ return id.hashCode ^
email.hashCode ^
name.hashCode ^ name.hashCode ^
inTimeline.hashCode ^ email.hashCode ^
profileImagePath.hashCode; deletedAt.hashCode ^
avatarColor.hashCode ^
isAdmin.hashCode ^
oauthId.hashCode ^
pinCode.hashCode ^
hasProfileImage.hashCode ^
profileChangedAt.hashCode ^
quotaSizeInBytes.hashCode ^
quotaUsageInBytes.hashCode ^
storageLabel.hashCode;
}
}
class PartnerUser {
final String id;
final String email;
final String name;
final bool inTimeline;
const PartnerUser({
required this.id,
required this.email,
required this.name,
required this.inTimeline,
});
PartnerUser copyWith({
String? id,
String? email,
String? name,
bool? inTimeline,
}) {
return PartnerUser(
id: id ?? this.id,
email: email ?? this.email,
name: name ?? this.name,
inTimeline: inTimeline ?? this.inTimeline,
);
}
@override
String toString() {
return '''PartnerUser {
id: $id,
email: $email,
name: $name,
inTimeline: $inTimeline,
}''';
}
@override
bool operator ==(covariant PartnerUser other) {
if (identical(this, other)) return true;
return other.id == id && other.email == email && other.name == name && other.inTimeline == inTimeline;
}
@override
int get hashCode {
return id.hashCode ^ email.hashCode ^ name.hashCode ^ inTimeline.hashCode;
} }
} }

View File

@@ -24,8 +24,7 @@ enum AvatarColor {
const AvatarColor(this.value); const AvatarColor(this.value);
Color toColor({bool isDarkTheme = false}) => switch (this) { Color toColor({bool isDarkTheme = false}) => switch (this) {
AvatarColor.primary => AvatarColor.primary => isDarkTheme ? const Color(0xFFABCBFA) : const Color(0xFF4250AF),
isDarkTheme ? const Color(0xFFABCBFA) : const Color(0xFF4250AF),
AvatarColor.pink => const Color.fromARGB(255, 244, 114, 182), AvatarColor.pink => const Color.fromARGB(255, 244, 114, 182),
AvatarColor.red => const Color.fromARGB(255, 239, 68, 68), AvatarColor.red => const Color.fromARGB(255, 239, 68, 68),
AvatarColor.yellow => const Color.fromARGB(255, 234, 179, 8), AvatarColor.yellow => const Color.fromARGB(255, 234, 179, 8),
@@ -241,14 +240,11 @@ licenseKey: $licenseKey,
bool operator ==(covariant License other) { bool operator ==(covariant License other) {
if (identical(this, other)) return true; if (identical(this, other)) return true;
return activatedAt == other.activatedAt && return activatedAt == other.activatedAt && activationKey == other.activationKey && licenseKey == other.licenseKey;
activationKey == other.activationKey &&
licenseKey == other.licenseKey;
} }
@override @override
int get hashCode => int get hashCode => activatedAt.hashCode ^ activationKey.hashCode ^ licenseKey.hashCode;
activatedAt.hashCode ^ activationKey.hashCode ^ licenseKey.hashCode;
} }
// Model for a user metadata stored in the server // Model for a user metadata stored in the server
@@ -310,10 +306,6 @@ license: ${license ?? "<NA>"},
@override @override
int get hashCode { int get hashCode {
return userId.hashCode ^ return userId.hashCode ^ key.hashCode ^ onboarding.hashCode ^ preferences.hashCode ^ license.hashCode;
key.hashCode ^
onboarding.hashCode ^
preferences.hashCode ^
license.hashCode;
} }
} }

View File

@@ -19,9 +19,7 @@ class AssetService {
Stream<BaseAsset?> watchAsset(BaseAsset asset) { Stream<BaseAsset?> watchAsset(BaseAsset asset) {
final id = asset is LocalAsset ? asset.id : (asset as RemoteAsset).id; final id = asset is LocalAsset ? asset.id : (asset as RemoteAsset).id;
return asset is LocalAsset return asset is LocalAsset ? _localAssetRepository.watchAsset(id) : _remoteAssetRepository.watchAsset(id);
? _localAssetRepository.watchAsset(id)
: _remoteAssetRepository.watchAsset(id);
} }
Future<List<RemoteAsset>> getStack(RemoteAsset asset) async { Future<List<RemoteAsset>> getStack(RemoteAsset asset) async {
@@ -40,8 +38,7 @@ class AssetService {
return null; return null;
} }
final id = final id = asset is LocalAsset ? asset.remoteId! : (asset as RemoteAsset).id;
asset is LocalAsset ? asset.remoteId! : (asset as RemoteAsset).id;
return _remoteAssetRepository.getExif(id); return _remoteAssetRepository.getExif(id);
} }
@@ -56,8 +53,7 @@ class AssetService {
width = exif?.width ?? asset.width?.toDouble(); width = exif?.width ?? asset.width?.toDouble();
height = exif?.height ?? asset.height?.toDouble(); height = exif?.height ?? asset.height?.toDouble();
} else if (asset is LocalAsset) { } else if (asset is LocalAsset) {
isFlipped = _platform.isAndroid && isFlipped = _platform.isAndroid && (asset.orientation == 90 || asset.orientation == 270);
(asset.orientation == 90 || asset.orientation == 270);
width = asset.width?.toDouble(); width = asset.width?.toDouble();
height = asset.height?.toDouble(); height = asset.height?.toDouble();
} else { } else {
@@ -78,10 +74,7 @@ class AssetService {
} }
Future<(int local, int remote)> getAssetCounts() async { Future<(int local, int remote)> getAssetCounts() async {
return ( return (await _localAssetRepository.getCount(), await _remoteAssetRepository.getCount());
await _localAssetRepository.getCount(),
await _remoteAssetRepository.getCount()
);
} }
Future<int> getLocalHashedCount() { Future<int> getLocalHashedCount() {

View File

@@ -41,8 +41,7 @@ class HashService {
); );
for (final album in localAlbums) { for (final album in localAlbums) {
final assetsToHash = final assetsToHash = await _localAlbumRepository.getAssetsToHash(album.id);
await _localAlbumRepository.getAssetsToHash(album.id);
if (assetsToHash.isNotEmpty) { if (assetsToHash.isNotEmpty) {
await _hashAssets(assetsToHash); await _hashAssets(assetsToHash);
} }
@@ -88,8 +87,7 @@ class HashService {
_log.fine("Hashing ${toHash.length} files"); _log.fine("Hashing ${toHash.length} files");
final hashed = <LocalAsset>[]; final hashed = <LocalAsset>[];
final hashes = final hashes = await _nativeSyncApi.hashPaths(toHash.map((e) => e.path).toList());
await _nativeSyncApi.hashPaths(toHash.map((e) => e.path).toList());
assert( assert(
hashes.length == toHash.length, hashes.length == toHash.length,
"Hashes length does not match toHash length: ${hashes.length} != ${toHash.length}", "Hashes length does not match toHash length: ${hashes.length} != ${toHash.length}",

View File

@@ -66,8 +66,7 @@ class LocalSyncService {
// On iOS, we need to full sync albums that are marked as cloud as the delta sync // On iOS, we need to full sync albums that are marked as cloud as the delta sync
// does not include changes for cloud albums. If ignoreIcloudAssets is enabled, // does not include changes for cloud albums. If ignoreIcloudAssets is enabled,
// remove the albums from the local database from the previous sync // remove the albums from the local database from the previous sync
final cloudAlbums = final cloudAlbums = deviceAlbums.where((a) => a.isCloud).toLocalAlbums();
deviceAlbums.where((a) => a.isCloud).toLocalAlbums();
for (final album in cloudAlbums) { for (final album in cloudAlbums) {
final dbAlbum = dbAlbums.firstWhereOrNull((a) => a.id == album.id); final dbAlbum = dbAlbums.firstWhereOrNull((a) => a.id == album.id);
if (dbAlbum == null) { if (dbAlbum == null) {
@@ -95,8 +94,7 @@ class LocalSyncService {
final Stopwatch stopwatch = Stopwatch()..start(); final Stopwatch stopwatch = Stopwatch()..start();
final deviceAlbums = await _nativeSyncApi.getAlbums(); final deviceAlbums = await _nativeSyncApi.getAlbums();
final dbAlbums = final dbAlbums = await _localAlbumRepository.getAll(sortBy: {SortLocalAlbumsBy.id});
await _localAlbumRepository.getAll(sortBy: {SortLocalAlbumsBy.id});
await diffSortedLists( await diffSortedLists(
dbAlbums, dbAlbums,
@@ -120,9 +118,7 @@ class LocalSyncService {
try { try {
_log.fine("Adding device album ${album.name}"); _log.fine("Adding device album ${album.name}");
final assets = album.assetCount > 0 final assets = album.assetCount > 0 ? await _nativeSyncApi.getAssetsForAlbum(album.id) : <PlatformAsset>[];
? await _nativeSyncApi.getAssetsForAlbum(album.id)
: <PlatformAsset>[];
await _localAlbumRepository.upsert( await _localAlbumRepository.upsert(
album, album,
@@ -188,10 +184,8 @@ class LocalSyncService {
return false; return false;
} }
final updatedTime = final updatedTime = (dbAlbum.updatedAt.millisecondsSinceEpoch ~/ 1000) + 1;
(dbAlbum.updatedAt.millisecondsSinceEpoch ~/ 1000) + 1; final newAssetsCount = await _nativeSyncApi.getAssetsCountSince(deviceAlbum.id, updatedTime);
final newAssetsCount =
await _nativeSyncApi.getAssetsCountSince(deviceAlbum.id, updatedTime);
// Early return if no new assets were found // Early return if no new assets were found
if (newAssetsCount == 0) { if (newAssetsCount == 0) {
@@ -230,13 +224,9 @@ class LocalSyncService {
Future<bool> fullDiff(LocalAlbum dbAlbum, LocalAlbum deviceAlbum) async { Future<bool> fullDiff(LocalAlbum dbAlbum, LocalAlbum deviceAlbum) async {
try { try {
final assetsInDevice = deviceAlbum.assetCount > 0 final assetsInDevice = deviceAlbum.assetCount > 0
? await _nativeSyncApi ? await _nativeSyncApi.getAssetsForAlbum(deviceAlbum.id).then((a) => a.toLocalAssets())
.getAssetsForAlbum(deviceAlbum.id)
.then((a) => a.toLocalAssets())
: <LocalAsset>[];
final assetsInDb = dbAlbum.assetCount > 0
? await _localAlbumRepository.getAssets(dbAlbum.id)
: <LocalAsset>[]; : <LocalAsset>[];
final assetsInDb = dbAlbum.assetCount > 0 ? await _localAlbumRepository.getAssets(dbAlbum.id) : <LocalAsset>[];
if (deviceAlbum.assetCount == 0) { if (deviceAlbum.assetCount == 0) {
_log.fine( _log.fine(
@@ -321,9 +311,7 @@ class LocalSyncService {
} }
bool _albumsEqual(LocalAlbum a, LocalAlbum b) { bool _albumsEqual(LocalAlbum a, LocalAlbum b) {
return a.name == b.name && return a.name == b.name && a.assetCount == b.assetCount && a.updatedAt.isAtSameMomentAs(b.updatedAt);
a.assetCount == b.assetCount &&
a.updatedAt.isAtSameMomentAs(b.updatedAt);
} }
} }
@@ -333,9 +321,7 @@ extension on Iterable<PlatformAlbum> {
(e) => LocalAlbum( (e) => LocalAlbum(
id: e.id, id: e.id,
name: e.name, name: e.name,
updatedAt: e.updatedAt == null updatedAt: e.updatedAt == null ? DateTime.now() : DateTime.fromMillisecondsSinceEpoch(e.updatedAt! * 1000),
? DateTime.now()
: DateTime.fromMillisecondsSinceEpoch(e.updatedAt! * 1000),
assetCount: e.assetCount, assetCount: e.assetCount,
), ),
).toList(); ).toList();
@@ -350,12 +336,8 @@ extension on Iterable<PlatformAsset> {
name: e.name, name: e.name,
checksum: null, checksum: null,
type: AssetType.values.elementAtOrNull(e.type) ?? AssetType.other, type: AssetType.values.elementAtOrNull(e.type) ?? AssetType.other,
createdAt: e.createdAt == null createdAt: e.createdAt == null ? DateTime.now() : DateTime.fromMillisecondsSinceEpoch(e.createdAt! * 1000),
? DateTime.now() updatedAt: e.updatedAt == null ? DateTime.now() : DateTime.fromMillisecondsSinceEpoch(e.updatedAt! * 1000),
: DateTime.fromMillisecondsSinceEpoch(e.createdAt! * 1000),
updatedAt: e.updatedAt == null
? DateTime.now()
: DateTime.fromMillisecondsSinceEpoch(e.updatedAt! * 1000),
width: e.width, width: e.width,
height: e.height, height: e.height,
durationInSeconds: e.durationInSeconds, durationInSeconds: e.durationInSeconds,

View File

@@ -56,8 +56,7 @@ class LogService {
}) async { }) async {
final instance = LogService._(logRepository, storeRepository, shouldBuffer); final instance = LogService._(logRepository, storeRepository, shouldBuffer);
await logRepository.truncate(limit: kLogTruncateLimit); await logRepository.truncate(limit: kLogTruncateLimit);
final level = await instance._storeRepository.tryGet(StoreKey.logLevel) ?? final level = await instance._storeRepository.tryGet(StoreKey.logLevel) ?? LogLevel.info.index;
LogLevel.info.index;
Logger.root.level = Level.LEVELS.elementAtOrNull(level) ?? Level.INFO; Logger.root.level = Level.LEVELS.elementAtOrNull(level) ?? Level.INFO;
return instance; return instance;
} }
@@ -146,9 +145,7 @@ class LoggerUnInitializedException implements Exception {
/// Log levels according to dart logging [Level] /// Log levels according to dart logging [Level]
extension LevelDomainToInfraExtension on Level { extension LevelDomainToInfraExtension on Level {
LogLevel toLogLevel() => LogLevel toLogLevel() => LogLevel.values.elementAtOrNull(Level.LEVELS.indexOf(this)) ?? LogLevel.info;
LogLevel.values.elementAtOrNull(Level.LEVELS.indexOf(this)) ??
LogLevel.info;
} }
extension on LogLevel { extension on LogLevel {

View File

@@ -12,21 +12,19 @@ class DriftPartnerService {
this._partnerApiRepository, this._partnerApiRepository,
); );
Future<List<PartnerUserDto>> getSharedWith(String userId) { Future<List<PartnerUser>> getSharedWith(String userId) {
return _driftPartnerRepository.getSharedWith(userId); return _driftPartnerRepository.getSharedWith(userId);
} }
Future<List<PartnerUserDto>> getSharedBy(String userId) { Future<List<PartnerUser>> getSharedBy(String userId) {
return _driftPartnerRepository.getSharedBy(userId); return _driftPartnerRepository.getSharedBy(userId);
} }
Future<List<PartnerUserDto>> getAvailablePartners( Future<List<PartnerUser>> getAvailablePartners(
String currentUserId, String currentUserId,
) async { ) async {
final otherUsers = final otherUsers = await _driftPartnerRepository.getAvailablePartners(currentUserId);
await _driftPartnerRepository.getAvailablePartners(currentUserId); final currentPartners = await _driftPartnerRepository.getSharedBy(currentUserId);
final currentPartners =
await _driftPartnerRepository.getSharedBy(currentUserId);
final available = otherUsers.where((user) { final available = otherUsers.where((user) {
return !currentPartners.any((partner) => partner.id == user.id); return !currentPartners.any((partner) => partner.id == user.id);
}).toList(); }).toList();

View File

@@ -44,8 +44,7 @@ class RemoteAlbumService {
filtered = filtered filtered = filtered
.where( .where(
(album) => (album) =>
album.name.toLowerCase().contains(lowerQuery) || album.name.toLowerCase().contains(lowerQuery) || album.description.toLowerCase().contains(lowerQuery),
album.description.toLowerCase().contains(lowerQuery),
) )
.toList(); .toList();
} }
@@ -53,12 +52,10 @@ class RemoteAlbumService {
if (userId != null) { if (userId != null) {
switch (filterMode) { switch (filterMode) {
case QuickFilterMode.myAlbums: case QuickFilterMode.myAlbums:
filtered = filtered = filtered.where((album) => album.ownerId == userId).toList();
filtered.where((album) => album.ownerId == userId).toList();
break; break;
case QuickFilterMode.sharedWithMe: case QuickFilterMode.sharedWithMe:
filtered = filtered = filtered.where((album) => album.ownerId != userId).toList();
filtered.where((album) => album.ownerId != userId).toList();
break; break;
case QuickFilterMode.all: case QuickFilterMode.all:
break; break;
@@ -111,7 +108,7 @@ class RemoteAlbumService {
return _repository.getDateRange(albumId); return _repository.getDateRange(albumId);
} }
Future<List<UserDto>> getSharedUsers(String albumId) { Future<List<User>> getSharedUsers(String albumId) {
return _repository.getSharedUsers(albumId); return _repository.getSharedUsers(albumId);
} }

View File

@@ -9,16 +9,11 @@ final AppSetting = SettingsService(storeService: StoreService.I);
class SettingsService { class SettingsService {
final StoreService _storeService; final StoreService _storeService;
const SettingsService({required StoreService storeService}) const SettingsService({required StoreService storeService}) : _storeService = storeService;
: _storeService = storeService;
T get<T>(Setting<T> setting) => T get<T>(Setting<T> setting) => _storeService.get(setting.storeKey, setting.defaultValue);
_storeService.get(setting.storeKey, setting.defaultValue);
Future<void> set<T>(Setting<T> setting, T value) => Future<void> set<T>(Setting<T> setting, T value) => _storeService.put(setting.storeKey, value);
_storeService.put(setting.storeKey, value);
Stream<T> watch<T>(Setting<T> setting) => _storeService Stream<T> watch<T>(Setting<T> setting) => _storeService.watch(setting.storeKey).map((v) => v ?? setting.defaultValue);
.watch(setting.storeKey)
.map((v) => v ?? setting.defaultValue);
} }

View File

@@ -12,8 +12,7 @@ class StoreService {
final Map<int, Object?> _cache = {}; final Map<int, Object?> _cache = {};
late final StreamSubscription<StoreDto> _storeUpdateSubscription; late final StreamSubscription<StoreDto> _storeUpdateSubscription;
StoreService._({required IsarStoreRepository storeRepository}) StoreService._({required IsarStoreRepository storeRepository}) : _storeRepository = storeRepository;
: _storeRepository = storeRepository;
// TODO: Temporary typedef to make minimal changes. Remove this and make the presentation layer access store through a provider // TODO: Temporary typedef to make minimal changes. Remove this and make the presentation layer access store through a provider
static StoreService? _instance; static StoreService? _instance;
@@ -48,8 +47,7 @@ class StoreService {
} }
} }
StreamSubscription<StoreDto> _listenForChange() => StreamSubscription<StoreDto> _listenForChange() => _storeRepository.watchAll().listen((event) {
_storeRepository.watchAll().listen((event) {
_cache[event.key.id] = event.value; _cache[event.key.id] = event.value;
}); });

View File

@@ -25,7 +25,7 @@ class SyncStreamService {
bool get isCancelled => _cancelChecker?.call() ?? false; bool get isCancelled => _cancelChecker?.call() ?? false;
Future<void> sync() { Future<void> sync() {
_logger.info("Remote sync request for userr"); _logger.info("Remote sync request for user");
DLog.log("Remote sync request for user"); DLog.log("Remote sync request for user");
// Start the sync stream and handle events // Start the sync stream and handle events
return _syncApiRepository.streamChanges(_handleEvents); return _syncApiRepository.streamChanges(_handleEvents);
@@ -120,6 +120,8 @@ class SyncStreamService {
) async { ) async {
_logger.fine("Processing sync data for $type of length ${data.length}"); _logger.fine("Processing sync data for $type of length ${data.length}");
switch (type) { switch (type) {
case SyncEntityType.authUserV1:
return _syncStreamRepository.updateAuthUsersV1(data.cast());
case SyncEntityType.userV1: case SyncEntityType.userV1:
return _syncStreamRepository.updateUsersV1(data.cast()); return _syncStreamRepository.updateUsersV1(data.cast());
case SyncEntityType.userDeleteV1: case SyncEntityType.userDeleteV1:

View File

@@ -33,11 +33,13 @@ class TimelineFactory {
}) : _timelineRepository = timelineRepository, }) : _timelineRepository = timelineRepository,
_settingsService = settingsService; _settingsService = settingsService;
GroupAssetsBy get groupBy => GroupAssetsBy get groupBy {
GroupAssetsBy.values[_settingsService.get(Setting.groupAssetsBy)]; final group = GroupAssetsBy.values[_settingsService.get(Setting.groupAssetsBy)];
// We do not support auto grouping in the new timeline yet, fallback to day grouping
return group == GroupAssetsBy.auto ? GroupAssetsBy.day : group;
}
TimelineService main(List<String> timelineUsers) => TimelineService main(List<String> timelineUsers) => TimelineService(_timelineRepository.main(timelineUsers, groupBy));
TimelineService(_timelineRepository.main(timelineUsers, groupBy));
TimelineService localAlbum({required String albumId}) => TimelineService localAlbum({required String albumId}) =>
TimelineService(_timelineRepository.localAlbum(albumId, groupBy)); TimelineService(_timelineRepository.localAlbum(albumId, groupBy));
@@ -45,29 +47,21 @@ class TimelineFactory {
TimelineService remoteAlbum({required String albumId}) => TimelineService remoteAlbum({required String albumId}) =>
TimelineService(_timelineRepository.remoteAlbum(albumId, groupBy)); TimelineService(_timelineRepository.remoteAlbum(albumId, groupBy));
TimelineService remoteAssets(String userId) => TimelineService remoteAssets(String userId) => TimelineService(_timelineRepository.remote(userId, groupBy));
TimelineService(_timelineRepository.remote(userId, groupBy));
TimelineService favorite(String userId) => TimelineService favorite(String userId) => TimelineService(_timelineRepository.favorite(userId, groupBy));
TimelineService(_timelineRepository.favorite(userId, groupBy));
TimelineService trash(String userId) => TimelineService trash(String userId) => TimelineService(_timelineRepository.trash(userId, groupBy));
TimelineService(_timelineRepository.trash(userId, groupBy));
TimelineService archive(String userId) => TimelineService archive(String userId) => TimelineService(_timelineRepository.archived(userId, groupBy));
TimelineService(_timelineRepository.archived(userId, groupBy));
TimelineService lockedFolder(String userId) => TimelineService lockedFolder(String userId) => TimelineService(_timelineRepository.locked(userId, groupBy));
TimelineService(_timelineRepository.locked(userId, groupBy));
TimelineService video(String userId) => TimelineService video(String userId) => TimelineService(_timelineRepository.video(userId, groupBy));
TimelineService(_timelineRepository.video(userId, groupBy));
TimelineService place(String place) => TimelineService place(String place) => TimelineService(_timelineRepository.place(place, groupBy));
TimelineService(_timelineRepository.place(place, groupBy));
TimelineService fromAssets(List<BaseAsset> assets) => TimelineService fromAssets(List<BaseAsset> assets) => TimelineService(_timelineRepository.fromAssets(assets));
TimelineService(_timelineRepository.fromAssets(assets));
} }
class TimelineService { class TimelineService {
@@ -94,8 +88,7 @@ class TimelineService {
_bucketSource = bucketSource { _bucketSource = bucketSource {
_bucketSubscription = _bucketSource().listen((buckets) { _bucketSubscription = _bucketSource().listen((buckets) {
_mutex.run(() async { _mutex.run(() async {
final totalAssets = final totalAssets = buckets.fold<int>(0, (acc, bucket) => acc + bucket.assetCount);
buckets.fold<int>(0, (acc, bucket) => acc + bucket.assetCount);
if (totalAssets == 0) { if (totalAssets == 0) {
_bufferOffset = 0; _bufferOffset = 0;
@@ -128,8 +121,7 @@ class TimelineService {
Stream<List<Bucket>> Function() get watchBuckets => _bucketSource; Stream<List<Bucket>> Function() get watchBuckets => _bucketSource;
Future<List<BaseAsset>> loadAssets(int index, int count) => Future<List<BaseAsset>> loadAssets(int index, int count) => _mutex.run(() => _loadAssets(index, count));
_mutex.run(() => _loadAssets(index, count));
Future<List<BaseAsset>> _loadAssets(int index, int count) async { Future<List<BaseAsset>> _loadAssets(int index, int count) async {
if (hasRange(index, count)) { if (hasRange(index, count)) {
@@ -178,11 +170,9 @@ class TimelineService {
} }
// Pre-cache assets around the given index for asset viewer // Pre-cache assets around the given index for asset viewer
Future<void> preCacheAssets(int index) => Future<void> preCacheAssets(int index) => _mutex.run(() => _loadAssets(index, math.min(5, _totalAssets - index)));
_mutex.run(() => _loadAssets(index, math.min(5, _totalAssets - index)));
BaseAsset getRandomAsset() => BaseAsset getRandomAsset() => _buffer.elementAt(math.Random().nextInt(_buffer.length));
_buffer.elementAt(math.Random().nextInt(_buffer.length));
BaseAsset getAsset(int index) { BaseAsset getAsset(int index) {
if (!hasRange(index, 1)) { if (!hasRange(index, 1)) {

View File

@@ -1,8 +1,10 @@
import 'dart:async'; import 'dart:async';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:immich_mobile/domain/models/setting.model.dart';
import 'package:immich_mobile/domain/models/store.model.dart'; import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/domain/services/setting.service.dart';
import 'package:immich_mobile/domain/services/store.service.dart'; import 'package:immich_mobile/domain/services/store.service.dart';
import 'package:immich_mobile/infrastructure/repositories/user.repository.dart'; import 'package:immich_mobile/infrastructure/repositories/user.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/user_api.repository.dart'; import 'package:immich_mobile/infrastructure/repositories/user_api.repository.dart';
@@ -66,3 +68,28 @@ class UserService {
return _isarUserRepository.deleteAll(); return _isarUserRepository.deleteAll();
} }
} }
class DriftUserService {
final DriftUserRepository _userRepository;
final SettingsService _settingsService;
const DriftUserService(
this._userRepository,
this._settingsService,
);
Future<User?> getMyUser() {
// TODO: Remove UserDto after new store
final isarCurrentUser = _settingsService.get(Setting.currentUser);
if (isarCurrentUser == null) {
throw Exception('User must be login');
}
return _userRepository.getById(isarCurrentUser.id);
}
Future<List<User>> getAll() {
return _userRepository.getAll();
}
}

View File

@@ -67,12 +67,10 @@ class BackgroundSyncManager {
// captured by the closure passed to [runInIsolateGentle]. // captured by the closure passed to [runInIsolateGentle].
_deviceAlbumSyncTask = full _deviceAlbumSyncTask = full
? runInIsolateGentle( ? runInIsolateGentle(
computation: (ref) => computation: (ref) => ref.read(localSyncServiceProvider).sync(full: true),
ref.read(localSyncServiceProvider).sync(full: true),
) )
: runInIsolateGentle( : runInIsolateGentle(
computation: (ref) => computation: (ref) => ref.read(localSyncServiceProvider).sync(full: false),
ref.read(localSyncServiceProvider).sync(full: false),
); );
return _deviceAlbumSyncTask!.whenComplete(() { return _deviceAlbumSyncTask!.whenComplete(() {
@@ -139,7 +137,5 @@ Cancelable<void> _handleWsAssetUploadReadyV1Batch(
List<dynamic> batchData, List<dynamic> batchData,
) => ) =>
runInIsolateGentle( runInIsolateGentle(
computation: (ref) => ref computation: (ref) => ref.read(syncStreamServiceProvider).handleWsAssetUploadReadyV1Batch(batchData),
.read(syncStreamServiceProvider)
.handleWsAssetUploadReadyV1Batch(batchData),
); );

View File

@@ -9,8 +9,7 @@ class EventStream {
static final EventStream shared = EventStream._(); static final EventStream shared = EventStream._();
final StreamController<Event> _controller = final StreamController<Event> _controller = StreamController<Event>.broadcast();
StreamController<Event>.broadcast();
void emit(Event event) { void emit(Event event) {
_controller.add(event); _controller.add(event);

View File

@@ -45,9 +45,9 @@ class Album {
bool activityEnabled; bool activityEnabled;
@enumerated @enumerated
SortOrder sortOrder; SortOrder sortOrder;
final IsarLink<User> owner = IsarLink<User>(); final IsarLink<IsarUser> owner = IsarLink<IsarUser>();
final IsarLink<Asset> thumbnail = IsarLink<Asset>(); final IsarLink<Asset> thumbnail = IsarLink<Asset>();
final IsarLinks<User> sharedUsers = IsarLinks<User>(); final IsarLinks<IsarUser> sharedUsers = IsarLinks<IsarUser>();
final IsarLinks<Asset> assets = IsarLinks<Asset>(); final IsarLinks<Asset> assets = IsarLinks<Asset>();
// transient fields // transient fields
@@ -95,13 +95,11 @@ class Album {
// accessible in an object freshly created (not loaded from DB) // accessible in an object freshly created (not loaded from DB)
@ignore @ignore
Iterable<User> get remoteUsers => sharedUsers.isEmpty Iterable<IsarUser> get remoteUsers =>
? (sharedUsers as IsarLinksCommon<User>).addedObjects sharedUsers.isEmpty ? (sharedUsers as IsarLinksCommon<IsarUser>).addedObjects : sharedUsers;
: sharedUsers;
@ignore @ignore
Iterable<Asset> get remoteAssets => Iterable<Asset> get remoteAssets => assets.isEmpty ? (assets as IsarLinksCommon<Asset>).addedObjects : assets;
assets.isEmpty ? (assets as IsarLinksCommon<Asset>).addedObjects : assets;
@override @override
bool operator ==(other) { bool operator ==(other) {
@@ -162,35 +160,29 @@ class Album {
activityEnabled: dto.isActivityEnabled, activityEnabled: dto.isActivityEnabled,
); );
a.remoteAssetCount = dto.assetCount; a.remoteAssetCount = dto.assetCount;
a.owner.value = await db.users.getById(dto.ownerId); a.owner.value = await db.isarUsers.getById(dto.ownerId);
if (dto.order != null) { if (dto.order != null) {
a.sortOrder = a.sortOrder = dto.order == AssetOrder.asc ? SortOrder.asc : SortOrder.desc;
dto.order == AssetOrder.asc ? SortOrder.asc : SortOrder.desc;
} }
if (dto.albumThumbnailAssetId != null) { if (dto.albumThumbnailAssetId != null) {
a.thumbnail.value = await db.assets a.thumbnail.value = await db.assets.where().remoteIdEqualTo(dto.albumThumbnailAssetId).findFirst();
.where()
.remoteIdEqualTo(dto.albumThumbnailAssetId)
.findFirst();
} }
if (dto.albumUsers.isNotEmpty) { if (dto.albumUsers.isNotEmpty) {
final users = await db.users.getAllById( final users = await db.isarUsers.getAllById(
dto.albumUsers.map((e) => e.user.id).toList(growable: false), dto.albumUsers.map((e) => e.user.id).toList(growable: false),
); );
a.sharedUsers.addAll(users.cast()); a.sharedUsers.addAll(users.cast());
} }
if (dto.assets.isNotEmpty) { if (dto.assets.isNotEmpty) {
final assets = final assets = await db.assets.getAllByRemoteId(dto.assets.map((e) => e.id));
await db.assets.getAllByRemoteId(dto.assets.map((e) => e.id));
a.assets.addAll(assets); a.assets.addAll(assets);
} }
return a; return a;
} }
@override @override
String toString() => String toString() => 'remoteId: $remoteId name: $name description: $description';
'remoteId: $remoteId name: $name description: $description';
} }
extension AssetsHelper on IsarCollection<Album> { extension AssetsHelper on IsarCollection<Album> {

View File

@@ -116,7 +116,7 @@ const AlbumSchema = CollectionSchema(
r'owner': LinkSchema( r'owner': LinkSchema(
id: 8272576585804958029, id: 8272576585804958029,
name: r'owner', name: r'owner',
target: r'User', target: r'IsarUser',
single: true, single: true,
), ),
r'thumbnail': LinkSchema( r'thumbnail': LinkSchema(
@@ -128,7 +128,7 @@ const AlbumSchema = CollectionSchema(
r'sharedUsers': LinkSchema( r'sharedUsers': LinkSchema(
id: 8972835302564625434, id: 8972835302564625434,
name: r'sharedUsers', name: r'sharedUsers',
target: r'User', target: r'IsarUser',
single: false, single: false,
), ),
r'assets': LinkSchema( r'assets': LinkSchema(
@@ -275,10 +275,10 @@ List<IsarLinkBase<dynamic>> _albumGetLinks(Album object) {
void _albumAttach(IsarCollection<dynamic> col, Id id, Album object) { void _albumAttach(IsarCollection<dynamic> col, Id id, Album object) {
object.id = id; object.id = id;
object.owner.attach(col, col.isar.collection<User>(), r'owner', id); object.owner.attach(col, col.isar.collection<IsarUser>(), r'owner', id);
object.thumbnail.attach(col, col.isar.collection<Asset>(), r'thumbnail', id); object.thumbnail.attach(col, col.isar.collection<Asset>(), r'thumbnail', id);
object.sharedUsers object.sharedUsers
.attach(col, col.isar.collection<User>(), r'sharedUsers', id); .attach(col, col.isar.collection<IsarUser>(), r'sharedUsers', id);
object.assets.attach(col, col.isar.collection<Asset>(), r'assets', id); object.assets.attach(col, col.isar.collection<Asset>(), r'assets', id);
} }
@@ -1500,7 +1500,8 @@ extension AlbumQueryFilter on QueryBuilder<Album, Album, QFilterCondition> {
extension AlbumQueryObject on QueryBuilder<Album, Album, QFilterCondition> {} extension AlbumQueryObject on QueryBuilder<Album, Album, QFilterCondition> {}
extension AlbumQueryLinks on QueryBuilder<Album, Album, QFilterCondition> { extension AlbumQueryLinks on QueryBuilder<Album, Album, QFilterCondition> {
QueryBuilder<Album, Album, QAfterFilterCondition> owner(FilterQuery<User> q) { QueryBuilder<Album, Album, QAfterFilterCondition> owner(
FilterQuery<IsarUser> q) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.link(q, r'owner'); return query.link(q, r'owner');
}); });
@@ -1526,7 +1527,7 @@ extension AlbumQueryLinks on QueryBuilder<Album, Album, QFilterCondition> {
} }
QueryBuilder<Album, Album, QAfterFilterCondition> sharedUsers( QueryBuilder<Album, Album, QAfterFilterCondition> sharedUsers(
FilterQuery<User> q) { FilterQuery<IsarUser> q) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.link(q, r'sharedUsers'); return query.link(q, r'sharedUsers');
}); });

View File

@@ -4,8 +4,7 @@ import 'dart:io';
import 'package:immich_mobile/constants/enums.dart'; import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/exif.model.dart'; import 'package:immich_mobile/domain/models/exif.model.dart';
import 'package:immich_mobile/extensions/string_extensions.dart'; import 'package:immich_mobile/extensions/string_extensions.dart';
import 'package:immich_mobile/infrastructure/entities/exif.entity.dart' import 'package:immich_mobile/infrastructure/entities/exif.entity.dart' as entity;
as entity;
import 'package:immich_mobile/infrastructure/utils/exif.converter.dart'; import 'package:immich_mobile/infrastructure/utils/exif.converter.dart';
import 'package:immich_mobile/utils/diff.dart'; import 'package:immich_mobile/utils/diff.dart';
import 'package:immich_mobile/utils/hash.dart'; import 'package:immich_mobile/utils/hash.dart';
@@ -32,18 +31,14 @@ class Asset {
width = remote.exifInfo?.exifImageWidth?.toInt(), width = remote.exifInfo?.exifImageWidth?.toInt(),
livePhotoVideoId = remote.livePhotoVideoId, livePhotoVideoId = remote.livePhotoVideoId,
ownerId = fastHash(remote.ownerId), ownerId = fastHash(remote.ownerId),
exifInfo = remote.exifInfo == null exifInfo = remote.exifInfo == null ? null : ExifDtoConverter.fromDto(remote.exifInfo!),
? null
: ExifDtoConverter.fromDto(remote.exifInfo!),
isFavorite = remote.isFavorite, isFavorite = remote.isFavorite,
isArchived = remote.isArchived, isArchived = remote.isArchived,
isTrashed = remote.isTrashed, isTrashed = remote.isTrashed,
isOffline = remote.isOffline, isOffline = remote.isOffline,
// workaround to nullify stackPrimaryAssetId for the parent asset until we refactor the mobile app // workaround to nullify stackPrimaryAssetId for the parent asset until we refactor the mobile app
// stack handling to properly handle it // stack handling to properly handle it
stackPrimaryAssetId = remote.stack?.primaryAssetId == remote.id stackPrimaryAssetId = remote.stack?.primaryAssetId == remote.id ? null : remote.stack?.primaryAssetId,
? null
: remote.stack?.primaryAssetId,
stackCount = remote.stack?.assetCount ?? 0, stackCount = remote.stack?.assetCount ?? 0,
stackId = remote.stack?.id, stackId = remote.stack?.id,
thumbhash = remote.thumbhash, thumbhash = remote.thumbhash,
@@ -108,8 +103,7 @@ class Asset {
throw Exception('Asset $fileName has no local data'); throw Exception('Asset $fileName has no local data');
} }
final updatedLocal = final updatedLocal = _didUpdateLocal ? local : await local.obtainForNewProperties();
_didUpdateLocal ? local : await local.obtainForNewProperties();
if (updatedLocal == null) { if (updatedLocal == null) {
throw Exception('Could not fetch local data for $fileName'); throw Exception('Could not fetch local data for $fileName');
} }
@@ -185,10 +179,7 @@ class Asset {
final orientatedWidth = this.orientatedWidth; final orientatedWidth = this.orientatedWidth;
final orientatedHeight = this.orientatedHeight; final orientatedHeight = this.orientatedHeight;
if (orientatedWidth != null && if (orientatedWidth != null && orientatedHeight != null && orientatedWidth > 0 && orientatedHeight > 0) {
orientatedHeight != null &&
orientatedWidth > 0 &&
orientatedHeight > 0) {
return orientatedWidth.toDouble() / orientatedHeight.toDouble(); return orientatedWidth.toDouble() / orientatedHeight.toDouble();
} }
@@ -389,8 +380,7 @@ class Asset {
// workaround to nullify stackPrimaryAssetId for the parent asset until we refactor the mobile app // workaround to nullify stackPrimaryAssetId for the parent asset until we refactor the mobile app
// stack handling to properly handle it // stack handling to properly handle it
stackId: stackId, stackId: stackId,
stackPrimaryAssetId: stackPrimaryAssetId: stackPrimaryAssetId == remoteId ? null : stackPrimaryAssetId,
stackPrimaryAssetId == remoteId ? null : stackPrimaryAssetId,
stackCount: stackCount, stackCount: stackCount,
isFavorite: isFavorite, isFavorite: isFavorite,
isArchived: isArchived, isArchived: isArchived,
@@ -410,9 +400,7 @@ class Asset {
// workaround to nullify stackPrimaryAssetId for the parent asset until we refactor the mobile app // workaround to nullify stackPrimaryAssetId for the parent asset until we refactor the mobile app
// stack handling to properly handle it // stack handling to properly handle it
stackId: a.stackId, stackId: a.stackId,
stackPrimaryAssetId: a.stackPrimaryAssetId == a.remoteId stackPrimaryAssetId: a.stackPrimaryAssetId == a.remoteId ? null : a.stackPrimaryAssetId,
? null
: a.stackPrimaryAssetId,
stackCount: a.stackCount, stackCount: a.stackCount,
// isFavorite + isArchived are not set by device-only assets // isFavorite + isArchived are not set by device-only assets
isFavorite: a.isFavorite, isFavorite: a.isFavorite,
@@ -428,8 +416,7 @@ class Asset {
localId: localId ?? a.localId, localId: localId ?? a.localId,
width: width ?? a.width, width: width ?? a.width,
height: height ?? a.height, height: height ?? a.height,
exifInfo: exifInfo ?? exifInfo: exifInfo ?? a.exifInfo?.copyWith(assetId: id), // updated to use assetId
a.exifInfo?.copyWith(assetId: id), // updated to use assetId
); );
} }
} }
@@ -491,18 +478,15 @@ class Asset {
Future<void> put(Isar db) async { Future<void> put(Isar db) async {
await db.assets.put(this); await db.assets.put(this);
if (exifInfo != null) { if (exifInfo != null) {
await db.exifInfos await db.exifInfos.put(entity.ExifInfo.fromDto(exifInfo!.copyWith(assetId: id)));
.put(entity.ExifInfo.fromDto(exifInfo!.copyWith(assetId: id)));
} }
} }
static int compareById(Asset a, Asset b) => a.id.compareTo(b.id); static int compareById(Asset a, Asset b) => a.id.compareTo(b.id);
static int compareByLocalId(Asset a, Asset b) => static int compareByLocalId(Asset a, Asset b) => compareToNullable(a.localId, b.localId);
compareToNullable(a.localId, b.localId);
static int compareByChecksum(Asset a, Asset b) => static int compareByChecksum(Asset a, Asset b) => a.checksum.compareTo(b.checksum);
a.checksum.compareTo(b.checksum);
static int compareByOwnerChecksum(Asset a, Asset b) { static int compareByOwnerChecksum(Asset a, Asset b) {
final int ownerIdOrder = a.ownerId.compareTo(b.ownerId); final int ownerIdOrder = a.ownerId.compareTo(b.ownerId);
@@ -589,16 +573,11 @@ enum AssetState {
} }
extension AssetsHelper on IsarCollection<Asset> { extension AssetsHelper on IsarCollection<Asset> {
Future<int> deleteAllByRemoteId(Iterable<String> ids) => Future<int> deleteAllByRemoteId(Iterable<String> ids) => ids.isEmpty ? Future.value(0) : remote(ids).deleteAll();
ids.isEmpty ? Future.value(0) : remote(ids).deleteAll(); Future<int> deleteAllByLocalId(Iterable<String> ids) => ids.isEmpty ? Future.value(0) : local(ids).deleteAll();
Future<int> deleteAllByLocalId(Iterable<String> ids) => Future<List<Asset>> getAllByRemoteId(Iterable<String> ids) => ids.isEmpty ? Future.value([]) : remote(ids).findAll();
ids.isEmpty ? Future.value(0) : local(ids).deleteAll(); Future<List<Asset>> getAllByLocalId(Iterable<String> ids) => ids.isEmpty ? Future.value([]) : local(ids).findAll();
Future<List<Asset>> getAllByRemoteId(Iterable<String> ids) => Future<Asset?> getByRemoteId(String id) => where().remoteIdEqualTo(id).findFirst();
ids.isEmpty ? Future.value([]) : remote(ids).findAll();
Future<List<Asset>> getAllByLocalId(Iterable<String> ids) =>
ids.isEmpty ? Future.value([]) : local(ids).findAll();
Future<Asset?> getByRemoteId(String id) =>
where().remoteIdEqualTo(id).findFirst();
QueryBuilder<Asset, Asset, QAfterWhereClause> remote( QueryBuilder<Asset, Asset, QAfterWhereClause> remote(
Iterable<String> ids, Iterable<String> ids,

View File

@@ -22,15 +22,13 @@ extension LogOnError<T> on AsyncValue<T> {
} }
if (!skip) { if (!skip) {
return onLoading?.call() ?? return onLoading?.call() ?? const Center(child: ImmichLoadingIndicator());
const Center(child: ImmichLoadingIndicator());
} }
} }
if (hasError && !hasValue) { if (hasError && !hasValue) {
_asyncErrorLogger.severe('Could not load value', error, stackTrace); _asyncErrorLogger.severe('Could not load value', error, stackTrace);
return onError?.call(error, stackTrace) ?? return onError?.call(error, stackTrace) ?? ScaffoldErrorBody(errorMsg: error?.toString());
ScaffoldErrorBody(errorMsg: error?.toString());
} }
return onData(requireValue); return onData(requireValue);

View File

@@ -60,6 +60,5 @@ extension ContextHelper on BuildContext {
FocusScopeNode get focusScope => FocusScope.of(this); FocusScopeNode get focusScope => FocusScope.of(this);
// Show SnackBars from the current context // Show SnackBars from the current context
void showSnackBar(SnackBar snackBar) => void showSnackBar(SnackBar snackBar) => ScaffoldMessenger.of(this).showSnackBar(snackBar);
ScaffoldMessenger.of(this).showSnackBar(snackBar);
} }

View File

@@ -57,9 +57,7 @@ extension DateRangeFormatting on DateTime {
final localeString = locale?.toString() ?? 'en_US'; final localeString = locale?.toString() ?? 'en_US';
// Check if it's a single date (same day) // Check if it's a single date (same day)
if (startDate.year == endDate.year && if (startDate.year == endDate.year && startDate.month == endDate.month && startDate.day == endDate.day) {
startDate.month == endDate.month &&
startDate.day == endDate.day) {
if (startDate.year == currentYear) { if (startDate.year == currentYear) {
// Single date of this year: "Aug 28" // Single date of this year: "Aug 28"
return DateFormat.MMMd(localeString).format(startDate); return DateFormat.MMMd(localeString).format(startDate);

View File

@@ -12,9 +12,7 @@ extension DurationExtension on String {
/// Parses and returns the string of format HH:MM:SS as a duration object else null /// Parses and returns the string of format HH:MM:SS as a duration object else null
Duration? toDuration() { Duration? toDuration() {
try { try {
final parts = split(':') final parts = split(':').map((e) => double.parse(e).toInt()).toList(growable: false);
.map((e) => double.parse(e).toInt())
.toList(growable: false);
return Duration(hours: parts[0], minutes: parts[1], seconds: parts[2]); return Duration(hours: parts[0], minutes: parts[1], seconds: parts[2]);
} catch (e) { } catch (e) {
return null; return null;

View File

@@ -2,9 +2,7 @@ import 'package:flutter/material.dart';
extension ImmichColorSchemeExtensions on ColorScheme { extension ImmichColorSchemeExtensions on ColorScheme {
bool get _isDarkMode => brightness == Brightness.dark; bool get _isDarkMode => brightness == Brightness.dark;
Color get onSurfaceSecondary => _isDarkMode Color get onSurfaceSecondary => _isDarkMode ? onSurface.darken(amount: .3) : onSurface.lighten(amount: .3);
? onSurface.darken(amount: .3)
: onSurface.lighten(amount: .3);
} }
extension ColorExtensions on Color { extension ColorExtensions on Color {

View File

@@ -40,8 +40,7 @@ String _translateHelper(
try { try {
final translatedMessage = key.tr(context: context); final translatedMessage = key.tr(context: context);
return args != null return args != null
? MessageFormat(translatedMessage, locale: Intl.defaultLocale ?? 'en') ? MessageFormat(translatedMessage, locale: Intl.defaultLocale ?? 'en').format(args)
.format(args)
: translatedMessage; : translatedMessage;
} catch (e) { } catch (e) {
debugPrint('Translation failed for key "$key". Error: $e'); debugPrint('Translation failed for key "$key". Error: $e');

View File

@@ -8,12 +8,9 @@ class AssetFaceEntity extends Table with DriftDefaultsMixin {
TextColumn get id => text()(); TextColumn get id => text()();
TextColumn get assetId => TextColumn get assetId => text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)();
text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)();
TextColumn get personId => text() TextColumn get personId => text().nullable().references(PersonEntity, #id, onDelete: KeyAction.setNull)();
.nullable()
.references(PersonEntity, #id, onDelete: KeyAction.setNull)();
IntColumn get imageWidth => integer()(); IntColumn get imageWidth => integer()();

View File

@@ -0,0 +1,56 @@
import 'package:drift/drift.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/domain/models/user_metadata.model.dart';
import 'package:immich_mobile/infrastructure/entities/auth_user.entity.drift.dart';
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
class AuthUserEntity extends Table with DriftDefaultsMixin {
const AuthUserEntity();
TextColumn get id => text()();
TextColumn get name => text()();
TextColumn get email => text()();
DateTimeColumn get deletedAt => dateTime().nullable()();
IntColumn get avatarColor => intEnum<AvatarColor>().nullable()();
BoolColumn get isAdmin => boolean().withDefault(const Constant(false))();
TextColumn get oauthId => text().withDefault(const Constant(''))();
TextColumn get pinCode => text().nullable()();
BoolColumn get hasProfileImage => boolean().withDefault(const Constant(false))();
DateTimeColumn get profileChangedAt => dateTime().withDefault(currentDateAndTime)();
IntColumn get quotaSizeInBytes => integer().nullable()();
IntColumn get quotaUsageInBytes => integer().withDefault(const Constant(0))();
TextColumn get storageLabel => text().nullable()();
@override
Set<Column> get primaryKey => {id};
}
extension AuthUserEntityDataDomainEx on AuthUserEntityData {
AuthUser toDto() => AuthUser(
id: id,
name: name,
email: email,
deletedAt: deletedAt,
avatarColor: avatarColor,
isAdmin: isAdmin,
oauthId: oauthId,
pinCode: pinCode,
hasProfileImage: hasProfileImage,
profileChangedAt: profileChangedAt,
quotaSizeInBytes: quotaSizeInBytes,
quotaUsageInBytes: quotaUsageInBytes,
storageLabel: storageLabel,
);
}

View File

@@ -0,0 +1,951 @@
// dart format width=80
// ignore_for_file: type=lint
import 'package:drift/drift.dart' as i0;
import 'package:immich_mobile/infrastructure/entities/auth_user.entity.drift.dart'
as i1;
import 'package:immich_mobile/domain/models/user_metadata.model.dart' as i2;
import 'package:immich_mobile/infrastructure/entities/auth_user.entity.dart'
as i3;
import 'package:drift/src/runtime/query_builder/query_builder.dart' as i4;
typedef $$AuthUserEntityTableCreateCompanionBuilder = i1.AuthUserEntityCompanion
Function({
required String id,
required String name,
required String email,
i0.Value<DateTime?> deletedAt,
i0.Value<i2.AvatarColor?> avatarColor,
i0.Value<bool> isAdmin,
i0.Value<String> oauthId,
i0.Value<String?> pinCode,
i0.Value<bool> hasProfileImage,
i0.Value<DateTime> profileChangedAt,
i0.Value<int?> quotaSizeInBytes,
i0.Value<int> quotaUsageInBytes,
i0.Value<String?> storageLabel,
});
typedef $$AuthUserEntityTableUpdateCompanionBuilder = i1.AuthUserEntityCompanion
Function({
i0.Value<String> id,
i0.Value<String> name,
i0.Value<String> email,
i0.Value<DateTime?> deletedAt,
i0.Value<i2.AvatarColor?> avatarColor,
i0.Value<bool> isAdmin,
i0.Value<String> oauthId,
i0.Value<String?> pinCode,
i0.Value<bool> hasProfileImage,
i0.Value<DateTime> profileChangedAt,
i0.Value<int?> quotaSizeInBytes,
i0.Value<int> quotaUsageInBytes,
i0.Value<String?> storageLabel,
});
class $$AuthUserEntityTableFilterComposer
extends i0.Composer<i0.GeneratedDatabase, i1.$AuthUserEntityTable> {
$$AuthUserEntityTableFilterComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
i0.ColumnFilters<String> get id => $composableBuilder(
column: $table.id, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<String> get name => $composableBuilder(
column: $table.name, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<String> get email => $composableBuilder(
column: $table.email, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<DateTime> get deletedAt => $composableBuilder(
column: $table.deletedAt, builder: (column) => i0.ColumnFilters(column));
i0.ColumnWithTypeConverterFilters<i2.AvatarColor?, i2.AvatarColor, int>
get avatarColor => $composableBuilder(
column: $table.avatarColor,
builder: (column) => i0.ColumnWithTypeConverterFilters(column));
i0.ColumnFilters<bool> get isAdmin => $composableBuilder(
column: $table.isAdmin, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<String> get oauthId => $composableBuilder(
column: $table.oauthId, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<String> get pinCode => $composableBuilder(
column: $table.pinCode, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<bool> get hasProfileImage => $composableBuilder(
column: $table.hasProfileImage,
builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<DateTime> get profileChangedAt => $composableBuilder(
column: $table.profileChangedAt,
builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<int> get quotaSizeInBytes => $composableBuilder(
column: $table.quotaSizeInBytes,
builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<int> get quotaUsageInBytes => $composableBuilder(
column: $table.quotaUsageInBytes,
builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<String> get storageLabel => $composableBuilder(
column: $table.storageLabel,
builder: (column) => i0.ColumnFilters(column));
}
class $$AuthUserEntityTableOrderingComposer
extends i0.Composer<i0.GeneratedDatabase, i1.$AuthUserEntityTable> {
$$AuthUserEntityTableOrderingComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
i0.ColumnOrderings<String> get id => $composableBuilder(
column: $table.id, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<String> get name => $composableBuilder(
column: $table.name, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<String> get email => $composableBuilder(
column: $table.email, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<DateTime> get deletedAt => $composableBuilder(
column: $table.deletedAt,
builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<int> get avatarColor => $composableBuilder(
column: $table.avatarColor,
builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<bool> get isAdmin => $composableBuilder(
column: $table.isAdmin, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<String> get oauthId => $composableBuilder(
column: $table.oauthId, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<String> get pinCode => $composableBuilder(
column: $table.pinCode, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<bool> get hasProfileImage => $composableBuilder(
column: $table.hasProfileImage,
builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<DateTime> get profileChangedAt => $composableBuilder(
column: $table.profileChangedAt,
builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<int> get quotaSizeInBytes => $composableBuilder(
column: $table.quotaSizeInBytes,
builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<int> get quotaUsageInBytes => $composableBuilder(
column: $table.quotaUsageInBytes,
builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<String> get storageLabel => $composableBuilder(
column: $table.storageLabel,
builder: (column) => i0.ColumnOrderings(column));
}
class $$AuthUserEntityTableAnnotationComposer
extends i0.Composer<i0.GeneratedDatabase, i1.$AuthUserEntityTable> {
$$AuthUserEntityTableAnnotationComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
i0.GeneratedColumn<String> get id =>
$composableBuilder(column: $table.id, builder: (column) => column);
i0.GeneratedColumn<String> get name =>
$composableBuilder(column: $table.name, builder: (column) => column);
i0.GeneratedColumn<String> get email =>
$composableBuilder(column: $table.email, builder: (column) => column);
i0.GeneratedColumn<DateTime> get deletedAt =>
$composableBuilder(column: $table.deletedAt, builder: (column) => column);
i0.GeneratedColumnWithTypeConverter<i2.AvatarColor?, int> get avatarColor =>
$composableBuilder(
column: $table.avatarColor, builder: (column) => column);
i0.GeneratedColumn<bool> get isAdmin =>
$composableBuilder(column: $table.isAdmin, builder: (column) => column);
i0.GeneratedColumn<String> get oauthId =>
$composableBuilder(column: $table.oauthId, builder: (column) => column);
i0.GeneratedColumn<String> get pinCode =>
$composableBuilder(column: $table.pinCode, builder: (column) => column);
i0.GeneratedColumn<bool> get hasProfileImage => $composableBuilder(
column: $table.hasProfileImage, builder: (column) => column);
i0.GeneratedColumn<DateTime> get profileChangedAt => $composableBuilder(
column: $table.profileChangedAt, builder: (column) => column);
i0.GeneratedColumn<int> get quotaSizeInBytes => $composableBuilder(
column: $table.quotaSizeInBytes, builder: (column) => column);
i0.GeneratedColumn<int> get quotaUsageInBytes => $composableBuilder(
column: $table.quotaUsageInBytes, builder: (column) => column);
i0.GeneratedColumn<String> get storageLabel => $composableBuilder(
column: $table.storageLabel, builder: (column) => column);
}
class $$AuthUserEntityTableTableManager extends i0.RootTableManager<
i0.GeneratedDatabase,
i1.$AuthUserEntityTable,
i1.AuthUserEntityData,
i1.$$AuthUserEntityTableFilterComposer,
i1.$$AuthUserEntityTableOrderingComposer,
i1.$$AuthUserEntityTableAnnotationComposer,
$$AuthUserEntityTableCreateCompanionBuilder,
$$AuthUserEntityTableUpdateCompanionBuilder,
(
i1.AuthUserEntityData,
i0.BaseReferences<i0.GeneratedDatabase, i1.$AuthUserEntityTable,
i1.AuthUserEntityData>
),
i1.AuthUserEntityData,
i0.PrefetchHooks Function()> {
$$AuthUserEntityTableTableManager(
i0.GeneratedDatabase db, i1.$AuthUserEntityTable table)
: super(i0.TableManagerState(
db: db,
table: table,
createFilteringComposer: () =>
i1.$$AuthUserEntityTableFilterComposer($db: db, $table: table),
createOrderingComposer: () =>
i1.$$AuthUserEntityTableOrderingComposer($db: db, $table: table),
createComputedFieldComposer: () => i1
.$$AuthUserEntityTableAnnotationComposer($db: db, $table: table),
updateCompanionCallback: ({
i0.Value<String> id = const i0.Value.absent(),
i0.Value<String> name = const i0.Value.absent(),
i0.Value<String> email = const i0.Value.absent(),
i0.Value<DateTime?> deletedAt = const i0.Value.absent(),
i0.Value<i2.AvatarColor?> avatarColor = const i0.Value.absent(),
i0.Value<bool> isAdmin = const i0.Value.absent(),
i0.Value<String> oauthId = const i0.Value.absent(),
i0.Value<String?> pinCode = const i0.Value.absent(),
i0.Value<bool> hasProfileImage = const i0.Value.absent(),
i0.Value<DateTime> profileChangedAt = const i0.Value.absent(),
i0.Value<int?> quotaSizeInBytes = const i0.Value.absent(),
i0.Value<int> quotaUsageInBytes = const i0.Value.absent(),
i0.Value<String?> storageLabel = const i0.Value.absent(),
}) =>
i1.AuthUserEntityCompanion(
id: id,
name: name,
email: email,
deletedAt: deletedAt,
avatarColor: avatarColor,
isAdmin: isAdmin,
oauthId: oauthId,
pinCode: pinCode,
hasProfileImage: hasProfileImage,
profileChangedAt: profileChangedAt,
quotaSizeInBytes: quotaSizeInBytes,
quotaUsageInBytes: quotaUsageInBytes,
storageLabel: storageLabel,
),
createCompanionCallback: ({
required String id,
required String name,
required String email,
i0.Value<DateTime?> deletedAt = const i0.Value.absent(),
i0.Value<i2.AvatarColor?> avatarColor = const i0.Value.absent(),
i0.Value<bool> isAdmin = const i0.Value.absent(),
i0.Value<String> oauthId = const i0.Value.absent(),
i0.Value<String?> pinCode = const i0.Value.absent(),
i0.Value<bool> hasProfileImage = const i0.Value.absent(),
i0.Value<DateTime> profileChangedAt = const i0.Value.absent(),
i0.Value<int?> quotaSizeInBytes = const i0.Value.absent(),
i0.Value<int> quotaUsageInBytes = const i0.Value.absent(),
i0.Value<String?> storageLabel = const i0.Value.absent(),
}) =>
i1.AuthUserEntityCompanion.insert(
id: id,
name: name,
email: email,
deletedAt: deletedAt,
avatarColor: avatarColor,
isAdmin: isAdmin,
oauthId: oauthId,
pinCode: pinCode,
hasProfileImage: hasProfileImage,
profileChangedAt: profileChangedAt,
quotaSizeInBytes: quotaSizeInBytes,
quotaUsageInBytes: quotaUsageInBytes,
storageLabel: storageLabel,
),
withReferenceMapper: (p0) => p0
.map((e) => (e.readTable(table), i0.BaseReferences(db, table, e)))
.toList(),
prefetchHooksCallback: null,
));
}
typedef $$AuthUserEntityTableProcessedTableManager = i0.ProcessedTableManager<
i0.GeneratedDatabase,
i1.$AuthUserEntityTable,
i1.AuthUserEntityData,
i1.$$AuthUserEntityTableFilterComposer,
i1.$$AuthUserEntityTableOrderingComposer,
i1.$$AuthUserEntityTableAnnotationComposer,
$$AuthUserEntityTableCreateCompanionBuilder,
$$AuthUserEntityTableUpdateCompanionBuilder,
(
i1.AuthUserEntityData,
i0.BaseReferences<i0.GeneratedDatabase, i1.$AuthUserEntityTable,
i1.AuthUserEntityData>
),
i1.AuthUserEntityData,
i0.PrefetchHooks Function()>;
class $AuthUserEntityTable extends i3.AuthUserEntity
with i0.TableInfo<$AuthUserEntityTable, i1.AuthUserEntityData> {
@override
final i0.GeneratedDatabase attachedDatabase;
final String? _alias;
$AuthUserEntityTable(this.attachedDatabase, [this._alias]);
static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id');
@override
late final i0.GeneratedColumn<String> id = i0.GeneratedColumn<String>(
'id', aliasedName, false,
type: i0.DriftSqlType.string, requiredDuringInsert: true);
static const i0.VerificationMeta _nameMeta =
const i0.VerificationMeta('name');
@override
late final i0.GeneratedColumn<String> name = i0.GeneratedColumn<String>(
'name', aliasedName, false,
type: i0.DriftSqlType.string, requiredDuringInsert: true);
static const i0.VerificationMeta _emailMeta =
const i0.VerificationMeta('email');
@override
late final i0.GeneratedColumn<String> email = i0.GeneratedColumn<String>(
'email', aliasedName, false,
type: i0.DriftSqlType.string, requiredDuringInsert: true);
static const i0.VerificationMeta _deletedAtMeta =
const i0.VerificationMeta('deletedAt');
@override
late final i0.GeneratedColumn<DateTime> deletedAt =
i0.GeneratedColumn<DateTime>('deleted_at', aliasedName, true,
type: i0.DriftSqlType.dateTime, requiredDuringInsert: false);
@override
late final i0.GeneratedColumnWithTypeConverter<i2.AvatarColor?, int>
avatarColor = i0.GeneratedColumn<int>('avatar_color', aliasedName, true,
type: i0.DriftSqlType.int, requiredDuringInsert: false)
.withConverter<i2.AvatarColor?>(
i1.$AuthUserEntityTable.$converteravatarColorn);
static const i0.VerificationMeta _isAdminMeta =
const i0.VerificationMeta('isAdmin');
@override
late final i0.GeneratedColumn<bool> isAdmin = i0.GeneratedColumn<bool>(
'is_admin', aliasedName, false,
type: i0.DriftSqlType.bool,
requiredDuringInsert: false,
defaultConstraints:
i0.GeneratedColumn.constraintIsAlways('CHECK ("is_admin" IN (0, 1))'),
defaultValue: const i4.Constant(false));
static const i0.VerificationMeta _oauthIdMeta =
const i0.VerificationMeta('oauthId');
@override
late final i0.GeneratedColumn<String> oauthId = i0.GeneratedColumn<String>(
'oauth_id', aliasedName, false,
type: i0.DriftSqlType.string,
requiredDuringInsert: false,
defaultValue: const i4.Constant(''));
static const i0.VerificationMeta _pinCodeMeta =
const i0.VerificationMeta('pinCode');
@override
late final i0.GeneratedColumn<String> pinCode = i0.GeneratedColumn<String>(
'pin_code', aliasedName, true,
type: i0.DriftSqlType.string, requiredDuringInsert: false);
static const i0.VerificationMeta _hasProfileImageMeta =
const i0.VerificationMeta('hasProfileImage');
@override
late final i0.GeneratedColumn<bool> hasProfileImage =
i0.GeneratedColumn<bool>('has_profile_image', aliasedName, false,
type: i0.DriftSqlType.bool,
requiredDuringInsert: false,
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
'CHECK ("has_profile_image" IN (0, 1))'),
defaultValue: const i4.Constant(false));
static const i0.VerificationMeta _profileChangedAtMeta =
const i0.VerificationMeta('profileChangedAt');
@override
late final i0.GeneratedColumn<DateTime> profileChangedAt =
i0.GeneratedColumn<DateTime>('profile_changed_at', aliasedName, false,
type: i0.DriftSqlType.dateTime,
requiredDuringInsert: false,
defaultValue: i4.currentDateAndTime);
static const i0.VerificationMeta _quotaSizeInBytesMeta =
const i0.VerificationMeta('quotaSizeInBytes');
@override
late final i0.GeneratedColumn<int> quotaSizeInBytes = i0.GeneratedColumn<int>(
'quota_size_in_bytes', aliasedName, true,
type: i0.DriftSqlType.int, requiredDuringInsert: false);
static const i0.VerificationMeta _quotaUsageInBytesMeta =
const i0.VerificationMeta('quotaUsageInBytes');
@override
late final i0.GeneratedColumn<int> quotaUsageInBytes =
i0.GeneratedColumn<int>('quota_usage_in_bytes', aliasedName, false,
type: i0.DriftSqlType.int,
requiredDuringInsert: false,
defaultValue: const i4.Constant(0));
static const i0.VerificationMeta _storageLabelMeta =
const i0.VerificationMeta('storageLabel');
@override
late final i0.GeneratedColumn<String> storageLabel =
i0.GeneratedColumn<String>('storage_label', aliasedName, true,
type: i0.DriftSqlType.string, requiredDuringInsert: false);
@override
List<i0.GeneratedColumn> get $columns => [
id,
name,
email,
deletedAt,
avatarColor,
isAdmin,
oauthId,
pinCode,
hasProfileImage,
profileChangedAt,
quotaSizeInBytes,
quotaUsageInBytes,
storageLabel
];
@override
String get aliasedName => _alias ?? actualTableName;
@override
String get actualTableName => $name;
static const String $name = 'auth_user_entity';
@override
i0.VerificationContext validateIntegrity(
i0.Insertable<i1.AuthUserEntityData> instance,
{bool isInserting = false}) {
final context = i0.VerificationContext();
final data = instance.toColumns(true);
if (data.containsKey('id')) {
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
} else if (isInserting) {
context.missing(_idMeta);
}
if (data.containsKey('name')) {
context.handle(
_nameMeta, name.isAcceptableOrUnknown(data['name']!, _nameMeta));
} else if (isInserting) {
context.missing(_nameMeta);
}
if (data.containsKey('email')) {
context.handle(
_emailMeta, email.isAcceptableOrUnknown(data['email']!, _emailMeta));
} else if (isInserting) {
context.missing(_emailMeta);
}
if (data.containsKey('deleted_at')) {
context.handle(_deletedAtMeta,
deletedAt.isAcceptableOrUnknown(data['deleted_at']!, _deletedAtMeta));
}
if (data.containsKey('is_admin')) {
context.handle(_isAdminMeta,
isAdmin.isAcceptableOrUnknown(data['is_admin']!, _isAdminMeta));
}
if (data.containsKey('oauth_id')) {
context.handle(_oauthIdMeta,
oauthId.isAcceptableOrUnknown(data['oauth_id']!, _oauthIdMeta));
}
if (data.containsKey('pin_code')) {
context.handle(_pinCodeMeta,
pinCode.isAcceptableOrUnknown(data['pin_code']!, _pinCodeMeta));
}
if (data.containsKey('has_profile_image')) {
context.handle(
_hasProfileImageMeta,
hasProfileImage.isAcceptableOrUnknown(
data['has_profile_image']!, _hasProfileImageMeta));
}
if (data.containsKey('profile_changed_at')) {
context.handle(
_profileChangedAtMeta,
profileChangedAt.isAcceptableOrUnknown(
data['profile_changed_at']!, _profileChangedAtMeta));
}
if (data.containsKey('quota_size_in_bytes')) {
context.handle(
_quotaSizeInBytesMeta,
quotaSizeInBytes.isAcceptableOrUnknown(
data['quota_size_in_bytes']!, _quotaSizeInBytesMeta));
}
if (data.containsKey('quota_usage_in_bytes')) {
context.handle(
_quotaUsageInBytesMeta,
quotaUsageInBytes.isAcceptableOrUnknown(
data['quota_usage_in_bytes']!, _quotaUsageInBytesMeta));
}
if (data.containsKey('storage_label')) {
context.handle(
_storageLabelMeta,
storageLabel.isAcceptableOrUnknown(
data['storage_label']!, _storageLabelMeta));
}
return context;
}
@override
Set<i0.GeneratedColumn> get $primaryKey => {id};
@override
i1.AuthUserEntityData map(Map<String, dynamic> data, {String? tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
return i1.AuthUserEntityData(
id: attachedDatabase.typeMapping
.read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!,
name: attachedDatabase.typeMapping
.read(i0.DriftSqlType.string, data['${effectivePrefix}name'])!,
email: attachedDatabase.typeMapping
.read(i0.DriftSqlType.string, data['${effectivePrefix}email'])!,
deletedAt: attachedDatabase.typeMapping
.read(i0.DriftSqlType.dateTime, data['${effectivePrefix}deleted_at']),
avatarColor: i1.$AuthUserEntityTable.$converteravatarColorn.fromSql(
attachedDatabase.typeMapping.read(
i0.DriftSqlType.int, data['${effectivePrefix}avatar_color'])),
isAdmin: attachedDatabase.typeMapping
.read(i0.DriftSqlType.bool, data['${effectivePrefix}is_admin'])!,
oauthId: attachedDatabase.typeMapping
.read(i0.DriftSqlType.string, data['${effectivePrefix}oauth_id'])!,
pinCode: attachedDatabase.typeMapping
.read(i0.DriftSqlType.string, data['${effectivePrefix}pin_code']),
hasProfileImage: attachedDatabase.typeMapping.read(
i0.DriftSqlType.bool, data['${effectivePrefix}has_profile_image'])!,
profileChangedAt: attachedDatabase.typeMapping.read(
i0.DriftSqlType.dateTime,
data['${effectivePrefix}profile_changed_at'])!,
quotaSizeInBytes: attachedDatabase.typeMapping.read(
i0.DriftSqlType.int, data['${effectivePrefix}quota_size_in_bytes']),
quotaUsageInBytes: attachedDatabase.typeMapping.read(
i0.DriftSqlType.int, data['${effectivePrefix}quota_usage_in_bytes'])!,
storageLabel: attachedDatabase.typeMapping.read(
i0.DriftSqlType.string, data['${effectivePrefix}storage_label']),
);
}
@override
$AuthUserEntityTable createAlias(String alias) {
return $AuthUserEntityTable(attachedDatabase, alias);
}
static i0.JsonTypeConverter2<i2.AvatarColor, int, int> $converteravatarColor =
const i0.EnumIndexConverter<i2.AvatarColor>(i2.AvatarColor.values);
static i0.JsonTypeConverter2<i2.AvatarColor?, int?, int?>
$converteravatarColorn =
i0.JsonTypeConverter2.asNullable($converteravatarColor);
@override
bool get withoutRowId => true;
@override
bool get isStrict => true;
}
class AuthUserEntityData extends i0.DataClass
implements i0.Insertable<i1.AuthUserEntityData> {
final String id;
final String name;
final String email;
final DateTime? deletedAt;
final i2.AvatarColor? avatarColor;
final bool isAdmin;
final String oauthId;
final String? pinCode;
final bool hasProfileImage;
final DateTime profileChangedAt;
final int? quotaSizeInBytes;
final int quotaUsageInBytes;
final String? storageLabel;
const AuthUserEntityData(
{required this.id,
required this.name,
required this.email,
this.deletedAt,
this.avatarColor,
required this.isAdmin,
required this.oauthId,
this.pinCode,
required this.hasProfileImage,
required this.profileChangedAt,
this.quotaSizeInBytes,
required this.quotaUsageInBytes,
this.storageLabel});
@override
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
final map = <String, i0.Expression>{};
map['id'] = i0.Variable<String>(id);
map['name'] = i0.Variable<String>(name);
map['email'] = i0.Variable<String>(email);
if (!nullToAbsent || deletedAt != null) {
map['deleted_at'] = i0.Variable<DateTime>(deletedAt);
}
if (!nullToAbsent || avatarColor != null) {
map['avatar_color'] = i0.Variable<int>(
i1.$AuthUserEntityTable.$converteravatarColorn.toSql(avatarColor));
}
map['is_admin'] = i0.Variable<bool>(isAdmin);
map['oauth_id'] = i0.Variable<String>(oauthId);
if (!nullToAbsent || pinCode != null) {
map['pin_code'] = i0.Variable<String>(pinCode);
}
map['has_profile_image'] = i0.Variable<bool>(hasProfileImage);
map['profile_changed_at'] = i0.Variable<DateTime>(profileChangedAt);
if (!nullToAbsent || quotaSizeInBytes != null) {
map['quota_size_in_bytes'] = i0.Variable<int>(quotaSizeInBytes);
}
map['quota_usage_in_bytes'] = i0.Variable<int>(quotaUsageInBytes);
if (!nullToAbsent || storageLabel != null) {
map['storage_label'] = i0.Variable<String>(storageLabel);
}
return map;
}
factory AuthUserEntityData.fromJson(Map<String, dynamic> json,
{i0.ValueSerializer? serializer}) {
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
return AuthUserEntityData(
id: serializer.fromJson<String>(json['id']),
name: serializer.fromJson<String>(json['name']),
email: serializer.fromJson<String>(json['email']),
deletedAt: serializer.fromJson<DateTime?>(json['deletedAt']),
avatarColor: i1.$AuthUserEntityTable.$converteravatarColorn
.fromJson(serializer.fromJson<int?>(json['avatarColor'])),
isAdmin: serializer.fromJson<bool>(json['isAdmin']),
oauthId: serializer.fromJson<String>(json['oauthId']),
pinCode: serializer.fromJson<String?>(json['pinCode']),
hasProfileImage: serializer.fromJson<bool>(json['hasProfileImage']),
profileChangedAt: serializer.fromJson<DateTime>(json['profileChangedAt']),
quotaSizeInBytes: serializer.fromJson<int?>(json['quotaSizeInBytes']),
quotaUsageInBytes: serializer.fromJson<int>(json['quotaUsageInBytes']),
storageLabel: serializer.fromJson<String?>(json['storageLabel']),
);
}
@override
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'id': serializer.toJson<String>(id),
'name': serializer.toJson<String>(name),
'email': serializer.toJson<String>(email),
'deletedAt': serializer.toJson<DateTime?>(deletedAt),
'avatarColor': serializer.toJson<int?>(
i1.$AuthUserEntityTable.$converteravatarColorn.toJson(avatarColor)),
'isAdmin': serializer.toJson<bool>(isAdmin),
'oauthId': serializer.toJson<String>(oauthId),
'pinCode': serializer.toJson<String?>(pinCode),
'hasProfileImage': serializer.toJson<bool>(hasProfileImage),
'profileChangedAt': serializer.toJson<DateTime>(profileChangedAt),
'quotaSizeInBytes': serializer.toJson<int?>(quotaSizeInBytes),
'quotaUsageInBytes': serializer.toJson<int>(quotaUsageInBytes),
'storageLabel': serializer.toJson<String?>(storageLabel),
};
}
i1.AuthUserEntityData copyWith(
{String? id,
String? name,
String? email,
i0.Value<DateTime?> deletedAt = const i0.Value.absent(),
i0.Value<i2.AvatarColor?> avatarColor = const i0.Value.absent(),
bool? isAdmin,
String? oauthId,
i0.Value<String?> pinCode = const i0.Value.absent(),
bool? hasProfileImage,
DateTime? profileChangedAt,
i0.Value<int?> quotaSizeInBytes = const i0.Value.absent(),
int? quotaUsageInBytes,
i0.Value<String?> storageLabel = const i0.Value.absent()}) =>
i1.AuthUserEntityData(
id: id ?? this.id,
name: name ?? this.name,
email: email ?? this.email,
deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt,
avatarColor: avatarColor.present ? avatarColor.value : this.avatarColor,
isAdmin: isAdmin ?? this.isAdmin,
oauthId: oauthId ?? this.oauthId,
pinCode: pinCode.present ? pinCode.value : this.pinCode,
hasProfileImage: hasProfileImage ?? this.hasProfileImage,
profileChangedAt: profileChangedAt ?? this.profileChangedAt,
quotaSizeInBytes: quotaSizeInBytes.present
? quotaSizeInBytes.value
: this.quotaSizeInBytes,
quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes,
storageLabel:
storageLabel.present ? storageLabel.value : this.storageLabel,
);
AuthUserEntityData copyWithCompanion(i1.AuthUserEntityCompanion data) {
return AuthUserEntityData(
id: data.id.present ? data.id.value : this.id,
name: data.name.present ? data.name.value : this.name,
email: data.email.present ? data.email.value : this.email,
deletedAt: data.deletedAt.present ? data.deletedAt.value : this.deletedAt,
avatarColor:
data.avatarColor.present ? data.avatarColor.value : this.avatarColor,
isAdmin: data.isAdmin.present ? data.isAdmin.value : this.isAdmin,
oauthId: data.oauthId.present ? data.oauthId.value : this.oauthId,
pinCode: data.pinCode.present ? data.pinCode.value : this.pinCode,
hasProfileImage: data.hasProfileImage.present
? data.hasProfileImage.value
: this.hasProfileImage,
profileChangedAt: data.profileChangedAt.present
? data.profileChangedAt.value
: this.profileChangedAt,
quotaSizeInBytes: data.quotaSizeInBytes.present
? data.quotaSizeInBytes.value
: this.quotaSizeInBytes,
quotaUsageInBytes: data.quotaUsageInBytes.present
? data.quotaUsageInBytes.value
: this.quotaUsageInBytes,
storageLabel: data.storageLabel.present
? data.storageLabel.value
: this.storageLabel,
);
}
@override
String toString() {
return (StringBuffer('AuthUserEntityData(')
..write('id: $id, ')
..write('name: $name, ')
..write('email: $email, ')
..write('deletedAt: $deletedAt, ')
..write('avatarColor: $avatarColor, ')
..write('isAdmin: $isAdmin, ')
..write('oauthId: $oauthId, ')
..write('pinCode: $pinCode, ')
..write('hasProfileImage: $hasProfileImage, ')
..write('profileChangedAt: $profileChangedAt, ')
..write('quotaSizeInBytes: $quotaSizeInBytes, ')
..write('quotaUsageInBytes: $quotaUsageInBytes, ')
..write('storageLabel: $storageLabel')
..write(')'))
.toString();
}
@override
int get hashCode => Object.hash(
id,
name,
email,
deletedAt,
avatarColor,
isAdmin,
oauthId,
pinCode,
hasProfileImage,
profileChangedAt,
quotaSizeInBytes,
quotaUsageInBytes,
storageLabel);
@override
bool operator ==(Object other) =>
identical(this, other) ||
(other is i1.AuthUserEntityData &&
other.id == this.id &&
other.name == this.name &&
other.email == this.email &&
other.deletedAt == this.deletedAt &&
other.avatarColor == this.avatarColor &&
other.isAdmin == this.isAdmin &&
other.oauthId == this.oauthId &&
other.pinCode == this.pinCode &&
other.hasProfileImage == this.hasProfileImage &&
other.profileChangedAt == this.profileChangedAt &&
other.quotaSizeInBytes == this.quotaSizeInBytes &&
other.quotaUsageInBytes == this.quotaUsageInBytes &&
other.storageLabel == this.storageLabel);
}
class AuthUserEntityCompanion
extends i0.UpdateCompanion<i1.AuthUserEntityData> {
final i0.Value<String> id;
final i0.Value<String> name;
final i0.Value<String> email;
final i0.Value<DateTime?> deletedAt;
final i0.Value<i2.AvatarColor?> avatarColor;
final i0.Value<bool> isAdmin;
final i0.Value<String> oauthId;
final i0.Value<String?> pinCode;
final i0.Value<bool> hasProfileImage;
final i0.Value<DateTime> profileChangedAt;
final i0.Value<int?> quotaSizeInBytes;
final i0.Value<int> quotaUsageInBytes;
final i0.Value<String?> storageLabel;
const AuthUserEntityCompanion({
this.id = const i0.Value.absent(),
this.name = const i0.Value.absent(),
this.email = const i0.Value.absent(),
this.deletedAt = const i0.Value.absent(),
this.avatarColor = const i0.Value.absent(),
this.isAdmin = const i0.Value.absent(),
this.oauthId = const i0.Value.absent(),
this.pinCode = const i0.Value.absent(),
this.hasProfileImage = const i0.Value.absent(),
this.profileChangedAt = const i0.Value.absent(),
this.quotaSizeInBytes = const i0.Value.absent(),
this.quotaUsageInBytes = const i0.Value.absent(),
this.storageLabel = const i0.Value.absent(),
});
AuthUserEntityCompanion.insert({
required String id,
required String name,
required String email,
this.deletedAt = const i0.Value.absent(),
this.avatarColor = const i0.Value.absent(),
this.isAdmin = const i0.Value.absent(),
this.oauthId = const i0.Value.absent(),
this.pinCode = const i0.Value.absent(),
this.hasProfileImage = const i0.Value.absent(),
this.profileChangedAt = const i0.Value.absent(),
this.quotaSizeInBytes = const i0.Value.absent(),
this.quotaUsageInBytes = const i0.Value.absent(),
this.storageLabel = const i0.Value.absent(),
}) : id = i0.Value(id),
name = i0.Value(name),
email = i0.Value(email);
static i0.Insertable<i1.AuthUserEntityData> custom({
i0.Expression<String>? id,
i0.Expression<String>? name,
i0.Expression<String>? email,
i0.Expression<DateTime>? deletedAt,
i0.Expression<int>? avatarColor,
i0.Expression<bool>? isAdmin,
i0.Expression<String>? oauthId,
i0.Expression<String>? pinCode,
i0.Expression<bool>? hasProfileImage,
i0.Expression<DateTime>? profileChangedAt,
i0.Expression<int>? quotaSizeInBytes,
i0.Expression<int>? quotaUsageInBytes,
i0.Expression<String>? storageLabel,
}) {
return i0.RawValuesInsertable({
if (id != null) 'id': id,
if (name != null) 'name': name,
if (email != null) 'email': email,
if (deletedAt != null) 'deleted_at': deletedAt,
if (avatarColor != null) 'avatar_color': avatarColor,
if (isAdmin != null) 'is_admin': isAdmin,
if (oauthId != null) 'oauth_id': oauthId,
if (pinCode != null) 'pin_code': pinCode,
if (hasProfileImage != null) 'has_profile_image': hasProfileImage,
if (profileChangedAt != null) 'profile_changed_at': profileChangedAt,
if (quotaSizeInBytes != null) 'quota_size_in_bytes': quotaSizeInBytes,
if (quotaUsageInBytes != null) 'quota_usage_in_bytes': quotaUsageInBytes,
if (storageLabel != null) 'storage_label': storageLabel,
});
}
i1.AuthUserEntityCompanion copyWith(
{i0.Value<String>? id,
i0.Value<String>? name,
i0.Value<String>? email,
i0.Value<DateTime?>? deletedAt,
i0.Value<i2.AvatarColor?>? avatarColor,
i0.Value<bool>? isAdmin,
i0.Value<String>? oauthId,
i0.Value<String?>? pinCode,
i0.Value<bool>? hasProfileImage,
i0.Value<DateTime>? profileChangedAt,
i0.Value<int?>? quotaSizeInBytes,
i0.Value<int>? quotaUsageInBytes,
i0.Value<String?>? storageLabel}) {
return i1.AuthUserEntityCompanion(
id: id ?? this.id,
name: name ?? this.name,
email: email ?? this.email,
deletedAt: deletedAt ?? this.deletedAt,
avatarColor: avatarColor ?? this.avatarColor,
isAdmin: isAdmin ?? this.isAdmin,
oauthId: oauthId ?? this.oauthId,
pinCode: pinCode ?? this.pinCode,
hasProfileImage: hasProfileImage ?? this.hasProfileImage,
profileChangedAt: profileChangedAt ?? this.profileChangedAt,
quotaSizeInBytes: quotaSizeInBytes ?? this.quotaSizeInBytes,
quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes,
storageLabel: storageLabel ?? this.storageLabel,
);
}
@override
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
final map = <String, i0.Expression>{};
if (id.present) {
map['id'] = i0.Variable<String>(id.value);
}
if (name.present) {
map['name'] = i0.Variable<String>(name.value);
}
if (email.present) {
map['email'] = i0.Variable<String>(email.value);
}
if (deletedAt.present) {
map['deleted_at'] = i0.Variable<DateTime>(deletedAt.value);
}
if (avatarColor.present) {
map['avatar_color'] = i0.Variable<int>(i1
.$AuthUserEntityTable.$converteravatarColorn
.toSql(avatarColor.value));
}
if (isAdmin.present) {
map['is_admin'] = i0.Variable<bool>(isAdmin.value);
}
if (oauthId.present) {
map['oauth_id'] = i0.Variable<String>(oauthId.value);
}
if (pinCode.present) {
map['pin_code'] = i0.Variable<String>(pinCode.value);
}
if (hasProfileImage.present) {
map['has_profile_image'] = i0.Variable<bool>(hasProfileImage.value);
}
if (profileChangedAt.present) {
map['profile_changed_at'] = i0.Variable<DateTime>(profileChangedAt.value);
}
if (quotaSizeInBytes.present) {
map['quota_size_in_bytes'] = i0.Variable<int>(quotaSizeInBytes.value);
}
if (quotaUsageInBytes.present) {
map['quota_usage_in_bytes'] = i0.Variable<int>(quotaUsageInBytes.value);
}
if (storageLabel.present) {
map['storage_label'] = i0.Variable<String>(storageLabel.value);
}
return map;
}
@override
String toString() {
return (StringBuffer('AuthUserEntityCompanion(')
..write('id: $id, ')
..write('name: $name, ')
..write('email: $email, ')
..write('deletedAt: $deletedAt, ')
..write('avatarColor: $avatarColor, ')
..write('isAdmin: $isAdmin, ')
..write('oauthId: $oauthId, ')
..write('pinCode: $pinCode, ')
..write('hasProfileImage: $hasProfileImage, ')
..write('profileChangedAt: $profileChangedAt, ')
..write('quotaSizeInBytes: $quotaSizeInBytes, ')
..write('quotaUsageInBytes: $quotaUsageInBytes, ')
..write('storageLabel: $storageLabel')
..write(')'))
.toString();
}
}

View File

@@ -98,8 +98,7 @@ class ExifInfo {
class RemoteExifEntity extends Table with DriftDefaultsMixin { class RemoteExifEntity extends Table with DriftDefaultsMixin {
const RemoteExifEntity(); const RemoteExifEntity();
TextColumn get assetId => TextColumn get assetId => text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)();
text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)();
TextColumn get city => text().nullable()(); TextColumn get city => text().nullable()();

View File

@@ -9,8 +9,7 @@ class LocalAlbumEntity extends Table with DriftDefaultsMixin {
TextColumn get name => text()(); TextColumn get name => text()();
DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)(); DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
IntColumn get backupSelection => intEnum<BackupSelection>()(); IntColumn get backupSelection => intEnum<BackupSelection>()();
BoolColumn get isIosSharedAlbum => BoolColumn get isIosSharedAlbum => boolean().withDefault(const Constant(false))();
boolean().withDefault(const Constant(false))();
// Used for mark & sweep // Used for mark & sweep
BoolColumn get marker_ => boolean().nullable()(); BoolColumn get marker_ => boolean().nullable()();

View File

@@ -6,11 +6,9 @@ import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
class LocalAlbumAssetEntity extends Table with DriftDefaultsMixin { class LocalAlbumAssetEntity extends Table with DriftDefaultsMixin {
const LocalAlbumAssetEntity(); const LocalAlbumAssetEntity();
TextColumn get assetId => TextColumn get assetId => text().references(LocalAssetEntity, #id, onDelete: KeyAction.cascade)();
text().references(LocalAssetEntity, #id, onDelete: KeyAction.cascade)();
TextColumn get albumId => TextColumn get albumId => text().references(LocalAlbumEntity, #id, onDelete: KeyAction.cascade)();
text().references(LocalAlbumEntity, #id, onDelete: KeyAction.cascade)();
@override @override
Set<Column> get primaryKey => {assetId, albumId}; Set<Column> get primaryKey => {assetId, albumId};

View File

@@ -14,8 +14,7 @@ class MemoryEntity extends Table with DriftDefaultsMixin {
DateTimeColumn get deletedAt => dateTime().nullable()(); DateTimeColumn get deletedAt => dateTime().nullable()();
TextColumn get ownerId => TextColumn get ownerId => text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
IntColumn get type => intEnum<MemoryTypeEnum>()(); IntColumn get type => intEnum<MemoryTypeEnum>()();

View File

@@ -6,11 +6,9 @@ import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
class MemoryAssetEntity extends Table with DriftDefaultsMixin { class MemoryAssetEntity extends Table with DriftDefaultsMixin {
const MemoryAssetEntity(); const MemoryAssetEntity();
TextColumn get assetId => TextColumn get assetId => text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)();
text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)();
TextColumn get memoryId => TextColumn get memoryId => text().references(MemoryEntity, #id, onDelete: KeyAction.cascade)();
text().references(MemoryEntity, #id, onDelete: KeyAction.cascade)();
@override @override
Set<Column> get primaryKey => {assetId, memoryId}; Set<Column> get primaryKey => {assetId, memoryId};

View File

@@ -1,76 +1,68 @@
import 'remote_asset.entity.dart'; import 'remote_asset.entity.dart';
import 'local_asset.entity.dart';
import 'stack.entity.dart'; import 'stack.entity.dart';
import 'local_asset.entity.dart';
import 'local_album.entity.dart';
import 'local_album_asset.entity.dart';
mergedAsset: SELECT * FROM mergedAsset:
( SELECT
SELECT rae.id as remote_id,
rae.id as remote_id, (SELECT lae.id FROM local_asset_entity lae WHERE lae.checksum = rae.checksum LIMIT 1) as local_id,
lae.id as local_id, rae.name,
rae.name, rae."type",
rae."type", rae.created_at as created_at,
rae.created_at, rae.updated_at,
rae.updated_at, rae.width,
rae.width, rae.height,
rae.height, rae.duration_in_seconds,
rae.duration_in_seconds, rae.is_favorite,
rae.is_favorite, rae.thumb_hash,
rae.thumb_hash, rae.checksum,
rae.checksum, rae.owner_id,
rae.owner_id, rae.live_photo_video_id,
rae.live_photo_video_id, 0 as orientation,
0 as orientation, rae.stack_id
rae.stack_id, FROM
COALESCE(stack_count.total_count, 0) AS stack_count remote_asset_entity rae
FROM LEFT JOIN
remote_asset_entity rae stack_entity se ON rae.stack_id = se.id
LEFT JOIN WHERE
local_asset_entity lae ON rae.checksum = lae.checksum rae.deleted_at IS NULL
LEFT JOIN AND rae.visibility = 0 -- timeline visibility
stack_entity se ON rae.stack_id = se.id AND rae.owner_id in ?
LEFT JOIN AND (
(SELECT rae.stack_id IS NULL
stack_id, OR rae.id = se.primary_asset_id
COUNT(*) AS total_count )
FROM remote_asset_entity
WHERE deleted_at IS NULL UNION ALL
AND visibility = 0
AND stack_id IS NOT NULL SELECT
GROUP BY stack_id NULL as remote_id,
) AS stack_count ON rae.stack_id = stack_count.stack_id lae.id as local_id,
WHERE lae.name,
rae.deleted_at IS NULL lae."type",
AND rae.visibility = 0 lae.created_at as created_at,
AND rae.owner_id in ? lae.updated_at,
AND ( lae.width,
rae.stack_id IS NULL lae.height,
OR rae.id = se.primary_asset_id lae.duration_in_seconds,
) lae.is_favorite,
UNION ALL NULL as thumb_hash,
SELECT lae.checksum,
NULL as remote_id, NULL as owner_id,
lae.id as local_id, NULL as live_photo_video_id,
lae.name, lae.orientation,
lae."type", NULL as stack_id
lae.created_at, FROM
lae.updated_at, local_asset_entity lae
lae.width, WHERE NOT EXISTS (
lae.height, SELECT 1 FROM remote_asset_entity rae WHERE rae.checksum = lae.checksum
lae.duration_in_seconds, )
lae.is_favorite, AND EXISTS (
NULL as thumb_hash, SELECT 1 FROM local_album_asset_entity laa
lae.checksum, INNER JOIN local_album_entity la on laa.album_id = la.id
NULL as owner_id, WHERE laa.asset_id = lae.id AND la.backup_selection = 0 -- selected
NULL as live_photo_video_id,
lae.orientation,
NULL as stack_id,
0 AS stack_count
FROM
local_asset_entity lae
LEFT JOIN
remote_asset_entity rae ON rae.checksum = lae.checksum
WHERE
rae.id IS NULL
) )
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT $limit; LIMIT $limit;
@@ -85,17 +77,14 @@ SELECT
FROM FROM
( (
SELECT SELECT
rae.name,
rae.created_at rae.created_at
FROM FROM
remote_asset_entity rae remote_asset_entity rae
LEFT JOIN
local_asset_entity lae ON rae.checksum = lae.checksum
LEFT JOIN LEFT JOIN
stack_entity se ON rae.stack_id = se.id stack_entity se ON rae.stack_id = se.id
WHERE WHERE
rae.deleted_at IS NULL rae.deleted_at IS NULL
AND rae.visibility = 0 AND rae.visibility = 0 -- timeline visibility
AND rae.owner_id in ? AND rae.owner_id in ?
AND ( AND (
rae.stack_id IS NULL rae.stack_id IS NULL
@@ -103,14 +92,18 @@ FROM
) )
UNION ALL UNION ALL
SELECT SELECT
lae.name,
lae.created_at lae.created_at
FROM FROM
local_asset_entity lae local_asset_entity lae
LEFT JOIN LEFT JOIN
remote_asset_entity rae ON rae.checksum = lae.checksum remote_asset_entity rae ON rae.checksum = lae.checksum
LEFT JOIN
local_album_asset_entity laa ON laa.asset_id = lae.id
LEFT JOIN
local_album_entity la ON la.id = laa.album_id
WHERE WHERE
rae.id IS NULL rae.id IS NULL
AND la.backup_selection = 0 -- selected
) )
GROUP BY bucket_date GROUP BY bucket_date
ORDER BY bucket_date DESC; ORDER BY bucket_date DESC;

View File

@@ -3,24 +3,29 @@
import 'package:drift/drift.dart' as i0; import 'package:drift/drift.dart' as i0;
import 'package:drift/internal/modular.dart' as i1; import 'package:drift/internal/modular.dart' as i1;
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart' as i2; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart' as i2;
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart'
as i3;
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart'
as i3;
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart'
as i4; as i4;
import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart'
as i5; as i5;
import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.drift.dart'
as i6;
import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart'
as i7;
class MergedAssetDrift extends i1.ModularAccessor { class MergedAssetDrift extends i1.ModularAccessor {
MergedAssetDrift(i0.GeneratedDatabase db) : super(db); MergedAssetDrift(i0.GeneratedDatabase db) : super(db);
i0.Selectable<MergedAssetResult> mergedAsset(List<String> var1, i0.Selectable<MergedAssetResult> mergedAsset(List<String> var1,
{required i0.Limit limit}) { {required MergedAsset$limit limit}) {
var $arrayStartIndex = 1; var $arrayStartIndex = 1;
final expandedvar1 = $expandVar($arrayStartIndex, var1.length); final expandedvar1 = $expandVar($arrayStartIndex, var1.length);
$arrayStartIndex += var1.length; $arrayStartIndex += var1.length;
final generatedlimit = $write(limit, startIndex: $arrayStartIndex); final generatedlimit = $write(limit(alias(this.localAssetEntity, 'lae')),
startIndex: $arrayStartIndex);
$arrayStartIndex += generatedlimit.amountOfVariables; $arrayStartIndex += generatedlimit.amountOfVariables;
return customSelect( return customSelect(
'SELECT * FROM (SELECT rae.id AS remote_id, lae.id AS local_id, rae.name, rae.type, rae.created_at, rae.updated_at, rae.width, rae.height, rae.duration_in_seconds, rae.is_favorite, rae.thumb_hash, rae.checksum, rae.owner_id, rae.live_photo_video_id, 0 AS orientation, rae.stack_id, COALESCE(stack_count.total_count, 0) AS stack_count FROM remote_asset_entity AS rae LEFT JOIN local_asset_entity AS lae ON rae.checksum = lae.checksum LEFT JOIN stack_entity AS se ON rae.stack_id = se.id LEFT JOIN (SELECT stack_id, COUNT(*) AS total_count FROM remote_asset_entity WHERE deleted_at IS NULL AND visibility = 0 AND stack_id IS NOT NULL GROUP BY stack_id) AS stack_count ON rae.stack_id = stack_count.stack_id WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandedvar1) AND(rae.stack_id IS NULL OR rae.id = se.primary_asset_id)UNION ALL SELECT NULL AS remote_id, lae.id AS local_id, lae.name, lae.type, lae.created_at, lae.updated_at, lae.width, lae.height, lae.duration_in_seconds, lae.is_favorite, NULL AS thumb_hash, lae.checksum, NULL AS owner_id, NULL AS live_photo_video_id, lae.orientation, NULL AS stack_id, 0 AS stack_count FROM local_asset_entity AS lae LEFT JOIN remote_asset_entity AS rae ON rae.checksum = lae.checksum WHERE rae.id IS NULL) ORDER BY created_at DESC ${generatedlimit.sql}', 'SELECT rae.id AS remote_id, (SELECT lae.id FROM local_asset_entity AS lae WHERE lae.checksum = rae.checksum LIMIT 1) AS local_id, rae.name, rae.type, rae.created_at AS created_at, rae.updated_at, rae.width, rae.height, rae.duration_in_seconds, rae.is_favorite, rae.thumb_hash, rae.checksum, rae.owner_id, rae.live_photo_video_id, 0 AS orientation, rae.stack_id FROM remote_asset_entity AS rae LEFT JOIN stack_entity AS se ON rae.stack_id = se.id WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandedvar1) AND(rae.stack_id IS NULL OR rae.id = se.primary_asset_id)UNION ALL SELECT NULL AS remote_id, lae.id AS local_id, lae.name, lae.type, lae.created_at AS created_at, lae.updated_at, lae.width, lae.height, lae.duration_in_seconds, lae.is_favorite, NULL AS thumb_hash, lae.checksum, NULL AS owner_id, NULL AS live_photo_video_id, lae.orientation, NULL AS stack_id FROM local_asset_entity AS lae WHERE NOT EXISTS (SELECT 1 FROM remote_asset_entity AS rae WHERE rae.checksum = lae.checksum) AND EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 0) ORDER BY created_at DESC ${generatedlimit.sql}',
variables: [ variables: [
for (var $ in var1) i0.Variable<String>($), for (var $ in var1) i0.Variable<String>($),
...generatedlimit.introducedVariables ...generatedlimit.introducedVariables
@@ -29,12 +34,14 @@ class MergedAssetDrift extends i1.ModularAccessor {
remoteAssetEntity, remoteAssetEntity,
localAssetEntity, localAssetEntity,
stackEntity, stackEntity,
localAlbumAssetEntity,
localAlbumEntity,
...generatedlimit.watchedTables, ...generatedlimit.watchedTables,
}).map((i0.QueryRow row) => MergedAssetResult( }).map((i0.QueryRow row) => MergedAssetResult(
remoteId: row.readNullable<String>('remote_id'), remoteId: row.readNullable<String>('remote_id'),
localId: row.readNullable<String>('local_id'), localId: row.readNullable<String>('local_id'),
name: row.read<String>('name'), name: row.read<String>('name'),
type: i3.$RemoteAssetEntityTable.$convertertype type: i4.$RemoteAssetEntityTable.$convertertype
.fromSql(row.read<int>('type')), .fromSql(row.read<int>('type')),
createdAt: row.read<DateTime>('created_at'), createdAt: row.read<DateTime>('created_at'),
updatedAt: row.read<DateTime>('updated_at'), updatedAt: row.read<DateTime>('updated_at'),
@@ -48,7 +55,6 @@ class MergedAssetDrift extends i1.ModularAccessor {
livePhotoVideoId: row.readNullable<String>('live_photo_video_id'), livePhotoVideoId: row.readNullable<String>('live_photo_video_id'),
orientation: row.read<int>('orientation'), orientation: row.read<int>('orientation'),
stackId: row.readNullable<String>('stack_id'), stackId: row.readNullable<String>('stack_id'),
stackCount: row.read<int>('stack_count'),
)); ));
} }
@@ -58,30 +64,39 @@ class MergedAssetDrift extends i1.ModularAccessor {
final expandedvar2 = $expandVar($arrayStartIndex, var2.length); final expandedvar2 = $expandVar($arrayStartIndex, var2.length);
$arrayStartIndex += var2.length; $arrayStartIndex += var2.length;
return customSelect( return customSelect(
'SELECT COUNT(*) AS asset_count, CASE WHEN ?1 = 0 THEN STRFTIME(\'%Y-%m-%d\', created_at, \'localtime\') WHEN ?1 = 1 THEN STRFTIME(\'%Y-%m\', created_at, \'localtime\') END AS bucket_date FROM (SELECT rae.name, rae.created_at FROM remote_asset_entity AS rae LEFT JOIN local_asset_entity AS lae ON rae.checksum = lae.checksum LEFT JOIN stack_entity AS se ON rae.stack_id = se.id WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandedvar2) AND(rae.stack_id IS NULL OR rae.id = se.primary_asset_id)UNION ALL SELECT lae.name, lae.created_at FROM local_asset_entity AS lae LEFT JOIN remote_asset_entity AS rae ON rae.checksum = lae.checksum WHERE rae.id IS NULL) GROUP BY bucket_date ORDER BY bucket_date DESC', 'SELECT COUNT(*) AS asset_count, CASE WHEN ?1 = 0 THEN STRFTIME(\'%Y-%m-%d\', created_at, \'localtime\') WHEN ?1 = 1 THEN STRFTIME(\'%Y-%m\', created_at, \'localtime\') END AS bucket_date FROM (SELECT rae.created_at FROM remote_asset_entity AS rae LEFT JOIN stack_entity AS se ON rae.stack_id = se.id WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandedvar2) AND(rae.stack_id IS NULL OR rae.id = se.primary_asset_id)UNION ALL SELECT lae.created_at FROM local_asset_entity AS lae LEFT JOIN remote_asset_entity AS rae ON rae.checksum = lae.checksum LEFT JOIN local_album_asset_entity AS laa ON laa.asset_id = lae.id LEFT JOIN local_album_entity AS la ON la.id = laa.album_id WHERE rae.id IS NULL AND la.backup_selection = 0) GROUP BY bucket_date ORDER BY bucket_date DESC',
variables: [ variables: [
i0.Variable<int>(groupBy), i0.Variable<int>(groupBy),
for (var $ in var2) i0.Variable<String>($) for (var $ in var2) i0.Variable<String>($)
], ],
readsFrom: { readsFrom: {
remoteAssetEntity, remoteAssetEntity,
localAssetEntity,
stackEntity, stackEntity,
localAssetEntity,
localAlbumAssetEntity,
localAlbumEntity,
}).map((i0.QueryRow row) => MergedBucketResult( }).map((i0.QueryRow row) => MergedBucketResult(
assetCount: row.read<int>('asset_count'), assetCount: row.read<int>('asset_count'),
bucketDate: row.read<String>('bucket_date'), bucketDate: row.read<String>('bucket_date'),
)); ));
} }
i3.$RemoteAssetEntityTable get remoteAssetEntity => i4.$RemoteAssetEntityTable get remoteAssetEntity =>
i1.ReadDatabaseContainer(attachedDatabase) i1.ReadDatabaseContainer(attachedDatabase)
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity'); .resultSet<i4.$RemoteAssetEntityTable>('remote_asset_entity');
i4.$LocalAssetEntityTable get localAssetEntity =>
i1.ReadDatabaseContainer(attachedDatabase)
.resultSet<i4.$LocalAssetEntityTable>('local_asset_entity');
i5.$StackEntityTable get stackEntity => i5.$StackEntityTable get stackEntity =>
i1.ReadDatabaseContainer(attachedDatabase) i1.ReadDatabaseContainer(attachedDatabase)
.resultSet<i5.$StackEntityTable>('stack_entity'); .resultSet<i5.$StackEntityTable>('stack_entity');
i3.$LocalAssetEntityTable get localAssetEntity =>
i1.ReadDatabaseContainer(attachedDatabase)
.resultSet<i3.$LocalAssetEntityTable>('local_asset_entity');
i6.$LocalAlbumAssetEntityTable get localAlbumAssetEntity =>
i1.ReadDatabaseContainer(attachedDatabase)
.resultSet<i6.$LocalAlbumAssetEntityTable>(
'local_album_asset_entity');
i7.$LocalAlbumEntityTable get localAlbumEntity =>
i1.ReadDatabaseContainer(attachedDatabase)
.resultSet<i7.$LocalAlbumEntityTable>('local_album_entity');
} }
class MergedAssetResult { class MergedAssetResult {
@@ -101,7 +116,6 @@ class MergedAssetResult {
final String? livePhotoVideoId; final String? livePhotoVideoId;
final int orientation; final int orientation;
final String? stackId; final String? stackId;
final int stackCount;
MergedAssetResult({ MergedAssetResult({
this.remoteId, this.remoteId,
this.localId, this.localId,
@@ -119,10 +133,11 @@ class MergedAssetResult {
this.livePhotoVideoId, this.livePhotoVideoId,
required this.orientation, required this.orientation,
this.stackId, this.stackId,
required this.stackCount,
}); });
} }
typedef MergedAsset$limit = i0.Limit Function(i3.$LocalAssetEntityTable lae);
class MergedBucketResult { class MergedBucketResult {
final int assetCount; final int assetCount;
final String bucketDate; final String bucketDate;

View File

@@ -5,11 +5,9 @@ import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
class PartnerEntity extends Table with DriftDefaultsMixin { class PartnerEntity extends Table with DriftDefaultsMixin {
const PartnerEntity(); const PartnerEntity();
TextColumn get sharedById => TextColumn get sharedById => text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
TextColumn get sharedWithId => TextColumn get sharedWithId => text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
BoolColumn get inTimeline => boolean().withDefault(const Constant(false))(); BoolColumn get inTimeline => boolean().withDefault(const Constant(false))();

View File

@@ -11,8 +11,7 @@ class PersonEntity extends Table with DriftDefaultsMixin {
DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)(); DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
TextColumn get ownerId => TextColumn get ownerId => text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
TextColumn get name => text()(); TextColumn get name => text()();

View File

@@ -17,15 +17,12 @@ class RemoteAlbumEntity extends Table with DriftDefaultsMixin {
DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)(); DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
TextColumn get ownerId => TextColumn get ownerId => text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
TextColumn get thumbnailAssetId => text() TextColumn get thumbnailAssetId =>
.references(RemoteAssetEntity, #id, onDelete: KeyAction.setNull) text().references(RemoteAssetEntity, #id, onDelete: KeyAction.setNull).nullable()();
.nullable()();
BoolColumn get isActivityEnabled => BoolColumn get isActivityEnabled => boolean().withDefault(const Constant(true))();
boolean().withDefault(const Constant(true))();
IntColumn get order => intEnum<AlbumAssetOrder>()(); IntColumn get order => intEnum<AlbumAssetOrder>()();

View File

@@ -6,11 +6,9 @@ import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
class RemoteAlbumAssetEntity extends Table with DriftDefaultsMixin { class RemoteAlbumAssetEntity extends Table with DriftDefaultsMixin {
const RemoteAlbumAssetEntity(); const RemoteAlbumAssetEntity();
TextColumn get assetId => TextColumn get assetId => text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)();
text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)();
TextColumn get albumId => TextColumn get albumId => text().references(RemoteAlbumEntity, #id, onDelete: KeyAction.cascade)();
text().references(RemoteAlbumEntity, #id, onDelete: KeyAction.cascade)();
@override @override
Set<Column> get primaryKey => {assetId, albumId}; Set<Column> get primaryKey => {assetId, albumId};

View File

@@ -7,11 +7,9 @@ import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
class RemoteAlbumUserEntity extends Table with DriftDefaultsMixin { class RemoteAlbumUserEntity extends Table with DriftDefaultsMixin {
const RemoteAlbumUserEntity(); const RemoteAlbumUserEntity();
TextColumn get albumId => TextColumn get albumId => text().references(RemoteAlbumEntity, #id, onDelete: KeyAction.cascade)();
text().references(RemoteAlbumEntity, #id, onDelete: KeyAction.cascade)();
TextColumn get userId => TextColumn get userId => text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
IntColumn get role => intEnum<AlbumUserRole>()(); IntColumn get role => intEnum<AlbumUserRole>()();

View File

@@ -11,8 +11,7 @@ import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
unique: true, unique: true,
) )
@TableIndex(name: 'idx_remote_asset_checksum', columns: {#checksum}) @TableIndex(name: 'idx_remote_asset_checksum', columns: {#checksum})
class RemoteAssetEntity extends Table class RemoteAssetEntity extends Table with DriftDefaultsMixin, AssetEntityMixin {
with DriftDefaultsMixin, AssetEntityMixin {
const RemoteAssetEntity(); const RemoteAssetEntity();
TextColumn get id => text()(); TextColumn get id => text()();
@@ -21,8 +20,7 @@ class RemoteAssetEntity extends Table
BoolColumn get isFavorite => boolean().withDefault(const Constant(false))(); BoolColumn get isFavorite => boolean().withDefault(const Constant(false))();
TextColumn get ownerId => TextColumn get ownerId => text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
DateTimeColumn get localDateTime => dateTime().nullable()(); DateTimeColumn get localDateTime => dateTime().nullable()();

View File

@@ -11,8 +11,7 @@ class StackEntity extends Table with DriftDefaultsMixin {
DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)(); DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
TextColumn get ownerId => TextColumn get ownerId => text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
TextColumn get primaryAssetId => text()(); TextColumn get primaryAssetId => text()();

View File

@@ -1,14 +1,16 @@
import 'package:drift/drift.dart' hide Index; import 'package:drift/drift.dart' hide Index;
import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/domain/models/user_metadata.model.dart'; import 'package:immich_mobile/domain/models/user_metadata.model.dart';
import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart';
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart'; import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
import 'package:immich_mobile/utils/hash.dart'; import 'package:immich_mobile/utils/hash.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
part 'user.entity.g.dart'; part 'user.entity.g.dart';
// TODO: Remove User once Isar is removed
@Collection(inheritance: false) @Collection(inheritance: false)
class User { class IsarUser {
Id get isarId => fastHash(id); Id get isarId => fastHash(id);
@Index(unique: true, replace: false, type: IndexType.hash) @Index(unique: true, replace: false, type: IndexType.hash)
final String id; final String id;
@@ -26,7 +28,7 @@ class User {
final int quotaUsageInBytes; final int quotaUsageInBytes;
final int quotaSizeInBytes; final int quotaSizeInBytes;
const User({ const IsarUser({
required this.id, required this.id,
required this.updatedAt, required this.updatedAt,
required this.email, required this.email,
@@ -42,7 +44,7 @@ class User {
this.quotaSizeInBytes = 0, this.quotaSizeInBytes = 0,
}); });
static User fromDto(UserDto dto) => User( static IsarUser fromDto(UserDto dto) => IsarUser(
id: dto.id, id: dto.id,
updatedAt: dto.updatedAt, updatedAt: dto.updatedAt,
email: dto.email, email: dto.email,
@@ -79,15 +81,25 @@ class UserEntity extends Table with DriftDefaultsMixin {
const UserEntity(); const UserEntity();
TextColumn get id => text()(); TextColumn get id => text()();
TextColumn get name => text()(); TextColumn get name => text()();
BoolColumn get isAdmin => boolean().withDefault(const Constant(false))();
TextColumn get email => text()(); TextColumn get email => text()();
TextColumn get profileImagePath => text().nullable()();
DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)(); DateTimeColumn get deletedAt => dateTime().nullable()();
// Quota
IntColumn get quotaSizeInBytes => integer().nullable()(); IntColumn get avatarColor => intEnum<AvatarColor>().nullable()();
IntColumn get quotaUsageInBytes => integer().withDefault(const Constant(0))();
@override @override
Set<Column> get primaryKey => {id}; Set<Column> get primaryKey => {id};
} }
extension UserEntityDataDomainEx on UserEntityData {
User toDto() => User(
id: id,
name: name,
email: email,
deletedAt: deletedAt,
avatarColor: avatarColor,
);
}

View File

@@ -3,30 +3,24 @@
import 'package:drift/drift.dart' as i0; import 'package:drift/drift.dart' as i0;
import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart'
as i1; as i1;
import 'package:immich_mobile/infrastructure/entities/user.entity.dart' as i2; import 'package:immich_mobile/domain/models/user_metadata.model.dart' as i2;
import 'package:drift/src/runtime/query_builder/query_builder.dart' as i3; import 'package:immich_mobile/infrastructure/entities/user.entity.dart' as i3;
typedef $$UserEntityTableCreateCompanionBuilder = i1.UserEntityCompanion typedef $$UserEntityTableCreateCompanionBuilder = i1.UserEntityCompanion
Function({ Function({
required String id, required String id,
required String name, required String name,
i0.Value<bool> isAdmin,
required String email, required String email,
i0.Value<String?> profileImagePath, i0.Value<DateTime?> deletedAt,
i0.Value<DateTime> updatedAt, i0.Value<i2.AvatarColor?> avatarColor,
i0.Value<int?> quotaSizeInBytes,
i0.Value<int> quotaUsageInBytes,
}); });
typedef $$UserEntityTableUpdateCompanionBuilder = i1.UserEntityCompanion typedef $$UserEntityTableUpdateCompanionBuilder = i1.UserEntityCompanion
Function({ Function({
i0.Value<String> id, i0.Value<String> id,
i0.Value<String> name, i0.Value<String> name,
i0.Value<bool> isAdmin,
i0.Value<String> email, i0.Value<String> email,
i0.Value<String?> profileImagePath, i0.Value<DateTime?> deletedAt,
i0.Value<DateTime> updatedAt, i0.Value<i2.AvatarColor?> avatarColor,
i0.Value<int?> quotaSizeInBytes,
i0.Value<int> quotaUsageInBytes,
}); });
class $$UserEntityTableFilterComposer class $$UserEntityTableFilterComposer
@@ -44,26 +38,16 @@ class $$UserEntityTableFilterComposer
i0.ColumnFilters<String> get name => $composableBuilder( i0.ColumnFilters<String> get name => $composableBuilder(
column: $table.name, builder: (column) => i0.ColumnFilters(column)); column: $table.name, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<bool> get isAdmin => $composableBuilder(
column: $table.isAdmin, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<String> get email => $composableBuilder( i0.ColumnFilters<String> get email => $composableBuilder(
column: $table.email, builder: (column) => i0.ColumnFilters(column)); column: $table.email, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<String> get profileImagePath => $composableBuilder( i0.ColumnFilters<DateTime> get deletedAt => $composableBuilder(
column: $table.profileImagePath, column: $table.deletedAt, builder: (column) => i0.ColumnFilters(column));
builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<DateTime> get updatedAt => $composableBuilder( i0.ColumnWithTypeConverterFilters<i2.AvatarColor?, i2.AvatarColor, int>
column: $table.updatedAt, builder: (column) => i0.ColumnFilters(column)); get avatarColor => $composableBuilder(
column: $table.avatarColor,
i0.ColumnFilters<int> get quotaSizeInBytes => $composableBuilder( builder: (column) => i0.ColumnWithTypeConverterFilters(column));
column: $table.quotaSizeInBytes,
builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<int> get quotaUsageInBytes => $composableBuilder(
column: $table.quotaUsageInBytes,
builder: (column) => i0.ColumnFilters(column));
} }
class $$UserEntityTableOrderingComposer class $$UserEntityTableOrderingComposer
@@ -81,26 +65,15 @@ class $$UserEntityTableOrderingComposer
i0.ColumnOrderings<String> get name => $composableBuilder( i0.ColumnOrderings<String> get name => $composableBuilder(
column: $table.name, builder: (column) => i0.ColumnOrderings(column)); column: $table.name, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<bool> get isAdmin => $composableBuilder(
column: $table.isAdmin, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<String> get email => $composableBuilder( i0.ColumnOrderings<String> get email => $composableBuilder(
column: $table.email, builder: (column) => i0.ColumnOrderings(column)); column: $table.email, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<String> get profileImagePath => $composableBuilder( i0.ColumnOrderings<DateTime> get deletedAt => $composableBuilder(
column: $table.profileImagePath, column: $table.deletedAt,
builder: (column) => i0.ColumnOrderings(column)); builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<DateTime> get updatedAt => $composableBuilder( i0.ColumnOrderings<int> get avatarColor => $composableBuilder(
column: $table.updatedAt, column: $table.avatarColor,
builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<int> get quotaSizeInBytes => $composableBuilder(
column: $table.quotaSizeInBytes,
builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<int> get quotaUsageInBytes => $composableBuilder(
column: $table.quotaUsageInBytes,
builder: (column) => i0.ColumnOrderings(column)); builder: (column) => i0.ColumnOrderings(column));
} }
@@ -119,23 +92,15 @@ class $$UserEntityTableAnnotationComposer
i0.GeneratedColumn<String> get name => i0.GeneratedColumn<String> get name =>
$composableBuilder(column: $table.name, builder: (column) => column); $composableBuilder(column: $table.name, builder: (column) => column);
i0.GeneratedColumn<bool> get isAdmin =>
$composableBuilder(column: $table.isAdmin, builder: (column) => column);
i0.GeneratedColumn<String> get email => i0.GeneratedColumn<String> get email =>
$composableBuilder(column: $table.email, builder: (column) => column); $composableBuilder(column: $table.email, builder: (column) => column);
i0.GeneratedColumn<String> get profileImagePath => $composableBuilder( i0.GeneratedColumn<DateTime> get deletedAt =>
column: $table.profileImagePath, builder: (column) => column); $composableBuilder(column: $table.deletedAt, builder: (column) => column);
i0.GeneratedColumn<DateTime> get updatedAt => i0.GeneratedColumnWithTypeConverter<i2.AvatarColor?, int> get avatarColor =>
$composableBuilder(column: $table.updatedAt, builder: (column) => column); $composableBuilder(
column: $table.avatarColor, builder: (column) => column);
i0.GeneratedColumn<int> get quotaSizeInBytes => $composableBuilder(
column: $table.quotaSizeInBytes, builder: (column) => column);
i0.GeneratedColumn<int> get quotaUsageInBytes => $composableBuilder(
column: $table.quotaUsageInBytes, builder: (column) => column);
} }
class $$UserEntityTableTableManager extends i0.RootTableManager< class $$UserEntityTableTableManager extends i0.RootTableManager<
@@ -168,42 +133,30 @@ class $$UserEntityTableTableManager extends i0.RootTableManager<
updateCompanionCallback: ({ updateCompanionCallback: ({
i0.Value<String> id = const i0.Value.absent(), i0.Value<String> id = const i0.Value.absent(),
i0.Value<String> name = const i0.Value.absent(), i0.Value<String> name = const i0.Value.absent(),
i0.Value<bool> isAdmin = const i0.Value.absent(),
i0.Value<String> email = const i0.Value.absent(), i0.Value<String> email = const i0.Value.absent(),
i0.Value<String?> profileImagePath = const i0.Value.absent(), i0.Value<DateTime?> deletedAt = const i0.Value.absent(),
i0.Value<DateTime> updatedAt = const i0.Value.absent(), i0.Value<i2.AvatarColor?> avatarColor = const i0.Value.absent(),
i0.Value<int?> quotaSizeInBytes = const i0.Value.absent(),
i0.Value<int> quotaUsageInBytes = const i0.Value.absent(),
}) => }) =>
i1.UserEntityCompanion( i1.UserEntityCompanion(
id: id, id: id,
name: name, name: name,
isAdmin: isAdmin,
email: email, email: email,
profileImagePath: profileImagePath, deletedAt: deletedAt,
updatedAt: updatedAt, avatarColor: avatarColor,
quotaSizeInBytes: quotaSizeInBytes,
quotaUsageInBytes: quotaUsageInBytes,
), ),
createCompanionCallback: ({ createCompanionCallback: ({
required String id, required String id,
required String name, required String name,
i0.Value<bool> isAdmin = const i0.Value.absent(),
required String email, required String email,
i0.Value<String?> profileImagePath = const i0.Value.absent(), i0.Value<DateTime?> deletedAt = const i0.Value.absent(),
i0.Value<DateTime> updatedAt = const i0.Value.absent(), i0.Value<i2.AvatarColor?> avatarColor = const i0.Value.absent(),
i0.Value<int?> quotaSizeInBytes = const i0.Value.absent(),
i0.Value<int> quotaUsageInBytes = const i0.Value.absent(),
}) => }) =>
i1.UserEntityCompanion.insert( i1.UserEntityCompanion.insert(
id: id, id: id,
name: name, name: name,
isAdmin: isAdmin,
email: email, email: email,
profileImagePath: profileImagePath, deletedAt: deletedAt,
updatedAt: updatedAt, avatarColor: avatarColor,
quotaSizeInBytes: quotaSizeInBytes,
quotaUsageInBytes: quotaUsageInBytes,
), ),
withReferenceMapper: (p0) => p0 withReferenceMapper: (p0) => p0
.map((e) => (e.readTable(table), i0.BaseReferences(db, table, e))) .map((e) => (e.readTable(table), i0.BaseReferences(db, table, e)))
@@ -229,7 +182,7 @@ typedef $$UserEntityTableProcessedTableManager = i0.ProcessedTableManager<
i1.UserEntityData, i1.UserEntityData,
i0.PrefetchHooks Function()>; i0.PrefetchHooks Function()>;
class $UserEntityTable extends i2.UserEntity class $UserEntityTable extends i3.UserEntity
with i0.TableInfo<$UserEntityTable, i1.UserEntityData> { with i0.TableInfo<$UserEntityTable, i1.UserEntityData> {
@override @override
final i0.GeneratedDatabase attachedDatabase; final i0.GeneratedDatabase attachedDatabase;
@@ -246,61 +199,27 @@ class $UserEntityTable extends i2.UserEntity
late final i0.GeneratedColumn<String> name = i0.GeneratedColumn<String>( late final i0.GeneratedColumn<String> name = i0.GeneratedColumn<String>(
'name', aliasedName, false, 'name', aliasedName, false,
type: i0.DriftSqlType.string, requiredDuringInsert: true); type: i0.DriftSqlType.string, requiredDuringInsert: true);
static const i0.VerificationMeta _isAdminMeta =
const i0.VerificationMeta('isAdmin');
@override
late final i0.GeneratedColumn<bool> isAdmin = i0.GeneratedColumn<bool>(
'is_admin', aliasedName, false,
type: i0.DriftSqlType.bool,
requiredDuringInsert: false,
defaultConstraints:
i0.GeneratedColumn.constraintIsAlways('CHECK ("is_admin" IN (0, 1))'),
defaultValue: const i3.Constant(false));
static const i0.VerificationMeta _emailMeta = static const i0.VerificationMeta _emailMeta =
const i0.VerificationMeta('email'); const i0.VerificationMeta('email');
@override @override
late final i0.GeneratedColumn<String> email = i0.GeneratedColumn<String>( late final i0.GeneratedColumn<String> email = i0.GeneratedColumn<String>(
'email', aliasedName, false, 'email', aliasedName, false,
type: i0.DriftSqlType.string, requiredDuringInsert: true); type: i0.DriftSqlType.string, requiredDuringInsert: true);
static const i0.VerificationMeta _profileImagePathMeta = static const i0.VerificationMeta _deletedAtMeta =
const i0.VerificationMeta('profileImagePath'); const i0.VerificationMeta('deletedAt');
@override @override
late final i0.GeneratedColumn<String> profileImagePath = late final i0.GeneratedColumn<DateTime> deletedAt =
i0.GeneratedColumn<String>('profile_image_path', aliasedName, true, i0.GeneratedColumn<DateTime>('deleted_at', aliasedName, true,
type: i0.DriftSqlType.string, requiredDuringInsert: false); type: i0.DriftSqlType.dateTime, requiredDuringInsert: false);
static const i0.VerificationMeta _updatedAtMeta =
const i0.VerificationMeta('updatedAt');
@override @override
late final i0.GeneratedColumn<DateTime> updatedAt = late final i0.GeneratedColumnWithTypeConverter<i2.AvatarColor?, int>
i0.GeneratedColumn<DateTime>('updated_at', aliasedName, false, avatarColor = i0.GeneratedColumn<int>('avatar_color', aliasedName, true,
type: i0.DriftSqlType.dateTime, type: i0.DriftSqlType.int, requiredDuringInsert: false)
requiredDuringInsert: false, .withConverter<i2.AvatarColor?>(
defaultValue: i3.currentDateAndTime); i1.$UserEntityTable.$converteravatarColorn);
static const i0.VerificationMeta _quotaSizeInBytesMeta =
const i0.VerificationMeta('quotaSizeInBytes');
@override @override
late final i0.GeneratedColumn<int> quotaSizeInBytes = i0.GeneratedColumn<int>( List<i0.GeneratedColumn> get $columns =>
'quota_size_in_bytes', aliasedName, true, [id, name, email, deletedAt, avatarColor];
type: i0.DriftSqlType.int, requiredDuringInsert: false);
static const i0.VerificationMeta _quotaUsageInBytesMeta =
const i0.VerificationMeta('quotaUsageInBytes');
@override
late final i0.GeneratedColumn<int> quotaUsageInBytes =
i0.GeneratedColumn<int>('quota_usage_in_bytes', aliasedName, false,
type: i0.DriftSqlType.int,
requiredDuringInsert: false,
defaultValue: const i3.Constant(0));
@override
List<i0.GeneratedColumn> get $columns => [
id,
name,
isAdmin,
email,
profileImagePath,
updatedAt,
quotaSizeInBytes,
quotaUsageInBytes
];
@override @override
String get aliasedName => _alias ?? actualTableName; String get aliasedName => _alias ?? actualTableName;
@override @override
@@ -323,37 +242,15 @@ class $UserEntityTable extends i2.UserEntity
} else if (isInserting) { } else if (isInserting) {
context.missing(_nameMeta); context.missing(_nameMeta);
} }
if (data.containsKey('is_admin')) {
context.handle(_isAdminMeta,
isAdmin.isAcceptableOrUnknown(data['is_admin']!, _isAdminMeta));
}
if (data.containsKey('email')) { if (data.containsKey('email')) {
context.handle( context.handle(
_emailMeta, email.isAcceptableOrUnknown(data['email']!, _emailMeta)); _emailMeta, email.isAcceptableOrUnknown(data['email']!, _emailMeta));
} else if (isInserting) { } else if (isInserting) {
context.missing(_emailMeta); context.missing(_emailMeta);
} }
if (data.containsKey('profile_image_path')) { if (data.containsKey('deleted_at')) {
context.handle( context.handle(_deletedAtMeta,
_profileImagePathMeta, deletedAt.isAcceptableOrUnknown(data['deleted_at']!, _deletedAtMeta));
profileImagePath.isAcceptableOrUnknown(
data['profile_image_path']!, _profileImagePathMeta));
}
if (data.containsKey('updated_at')) {
context.handle(_updatedAtMeta,
updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta));
}
if (data.containsKey('quota_size_in_bytes')) {
context.handle(
_quotaSizeInBytesMeta,
quotaSizeInBytes.isAcceptableOrUnknown(
data['quota_size_in_bytes']!, _quotaSizeInBytesMeta));
}
if (data.containsKey('quota_usage_in_bytes')) {
context.handle(
_quotaUsageInBytesMeta,
quotaUsageInBytes.isAcceptableOrUnknown(
data['quota_usage_in_bytes']!, _quotaUsageInBytesMeta));
} }
return context; return context;
} }
@@ -368,18 +265,13 @@ class $UserEntityTable extends i2.UserEntity
.read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!, .read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!,
name: attachedDatabase.typeMapping name: attachedDatabase.typeMapping
.read(i0.DriftSqlType.string, data['${effectivePrefix}name'])!, .read(i0.DriftSqlType.string, data['${effectivePrefix}name'])!,
isAdmin: attachedDatabase.typeMapping
.read(i0.DriftSqlType.bool, data['${effectivePrefix}is_admin'])!,
email: attachedDatabase.typeMapping email: attachedDatabase.typeMapping
.read(i0.DriftSqlType.string, data['${effectivePrefix}email'])!, .read(i0.DriftSqlType.string, data['${effectivePrefix}email'])!,
profileImagePath: attachedDatabase.typeMapping.read( deletedAt: attachedDatabase.typeMapping
i0.DriftSqlType.string, data['${effectivePrefix}profile_image_path']), .read(i0.DriftSqlType.dateTime, data['${effectivePrefix}deleted_at']),
updatedAt: attachedDatabase.typeMapping.read( avatarColor: i1.$UserEntityTable.$converteravatarColorn.fromSql(
i0.DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, attachedDatabase.typeMapping.read(
quotaSizeInBytes: attachedDatabase.typeMapping.read( i0.DriftSqlType.int, data['${effectivePrefix}avatar_color'])),
i0.DriftSqlType.int, data['${effectivePrefix}quota_size_in_bytes']),
quotaUsageInBytes: attachedDatabase.typeMapping.read(
i0.DriftSqlType.int, data['${effectivePrefix}quota_usage_in_bytes'])!,
); );
} }
@@ -388,6 +280,11 @@ class $UserEntityTable extends i2.UserEntity
return $UserEntityTable(attachedDatabase, alias); return $UserEntityTable(attachedDatabase, alias);
} }
static i0.JsonTypeConverter2<i2.AvatarColor, int, int> $converteravatarColor =
const i0.EnumIndexConverter<i2.AvatarColor>(i2.AvatarColor.values);
static i0.JsonTypeConverter2<i2.AvatarColor?, int?, int?>
$converteravatarColorn =
i0.JsonTypeConverter2.asNullable($converteravatarColor);
@override @override
bool get withoutRowId => true; bool get withoutRowId => true;
@override @override
@@ -398,36 +295,28 @@ class UserEntityData extends i0.DataClass
implements i0.Insertable<i1.UserEntityData> { implements i0.Insertable<i1.UserEntityData> {
final String id; final String id;
final String name; final String name;
final bool isAdmin;
final String email; final String email;
final String? profileImagePath; final DateTime? deletedAt;
final DateTime updatedAt; final i2.AvatarColor? avatarColor;
final int? quotaSizeInBytes;
final int quotaUsageInBytes;
const UserEntityData( const UserEntityData(
{required this.id, {required this.id,
required this.name, required this.name,
required this.isAdmin,
required this.email, required this.email,
this.profileImagePath, this.deletedAt,
required this.updatedAt, this.avatarColor});
this.quotaSizeInBytes,
required this.quotaUsageInBytes});
@override @override
Map<String, i0.Expression> toColumns(bool nullToAbsent) { Map<String, i0.Expression> toColumns(bool nullToAbsent) {
final map = <String, i0.Expression>{}; final map = <String, i0.Expression>{};
map['id'] = i0.Variable<String>(id); map['id'] = i0.Variable<String>(id);
map['name'] = i0.Variable<String>(name); map['name'] = i0.Variable<String>(name);
map['is_admin'] = i0.Variable<bool>(isAdmin);
map['email'] = i0.Variable<String>(email); map['email'] = i0.Variable<String>(email);
if (!nullToAbsent || profileImagePath != null) { if (!nullToAbsent || deletedAt != null) {
map['profile_image_path'] = i0.Variable<String>(profileImagePath); map['deleted_at'] = i0.Variable<DateTime>(deletedAt);
} }
map['updated_at'] = i0.Variable<DateTime>(updatedAt); if (!nullToAbsent || avatarColor != null) {
if (!nullToAbsent || quotaSizeInBytes != null) { map['avatar_color'] = i0.Variable<int>(
map['quota_size_in_bytes'] = i0.Variable<int>(quotaSizeInBytes); i1.$UserEntityTable.$converteravatarColorn.toSql(avatarColor));
} }
map['quota_usage_in_bytes'] = i0.Variable<int>(quotaUsageInBytes);
return map; return map;
} }
@@ -437,12 +326,10 @@ class UserEntityData extends i0.DataClass
return UserEntityData( return UserEntityData(
id: serializer.fromJson<String>(json['id']), id: serializer.fromJson<String>(json['id']),
name: serializer.fromJson<String>(json['name']), name: serializer.fromJson<String>(json['name']),
isAdmin: serializer.fromJson<bool>(json['isAdmin']),
email: serializer.fromJson<String>(json['email']), email: serializer.fromJson<String>(json['email']),
profileImagePath: serializer.fromJson<String?>(json['profileImagePath']), deletedAt: serializer.fromJson<DateTime?>(json['deletedAt']),
updatedAt: serializer.fromJson<DateTime>(json['updatedAt']), avatarColor: i1.$UserEntityTable.$converteravatarColorn
quotaSizeInBytes: serializer.fromJson<int?>(json['quotaSizeInBytes']), .fromJson(serializer.fromJson<int?>(json['avatarColor'])),
quotaUsageInBytes: serializer.fromJson<int>(json['quotaUsageInBytes']),
); );
} }
@override @override
@@ -451,54 +338,34 @@ class UserEntityData extends i0.DataClass
return <String, dynamic>{ return <String, dynamic>{
'id': serializer.toJson<String>(id), 'id': serializer.toJson<String>(id),
'name': serializer.toJson<String>(name), 'name': serializer.toJson<String>(name),
'isAdmin': serializer.toJson<bool>(isAdmin),
'email': serializer.toJson<String>(email), 'email': serializer.toJson<String>(email),
'profileImagePath': serializer.toJson<String?>(profileImagePath), 'deletedAt': serializer.toJson<DateTime?>(deletedAt),
'updatedAt': serializer.toJson<DateTime>(updatedAt), 'avatarColor': serializer.toJson<int?>(
'quotaSizeInBytes': serializer.toJson<int?>(quotaSizeInBytes), i1.$UserEntityTable.$converteravatarColorn.toJson(avatarColor)),
'quotaUsageInBytes': serializer.toJson<int>(quotaUsageInBytes),
}; };
} }
i1.UserEntityData copyWith( i1.UserEntityData copyWith(
{String? id, {String? id,
String? name, String? name,
bool? isAdmin,
String? email, String? email,
i0.Value<String?> profileImagePath = const i0.Value.absent(), i0.Value<DateTime?> deletedAt = const i0.Value.absent(),
DateTime? updatedAt, i0.Value<i2.AvatarColor?> avatarColor = const i0.Value.absent()}) =>
i0.Value<int?> quotaSizeInBytes = const i0.Value.absent(),
int? quotaUsageInBytes}) =>
i1.UserEntityData( i1.UserEntityData(
id: id ?? this.id, id: id ?? this.id,
name: name ?? this.name, name: name ?? this.name,
isAdmin: isAdmin ?? this.isAdmin,
email: email ?? this.email, email: email ?? this.email,
profileImagePath: profileImagePath.present deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt,
? profileImagePath.value avatarColor: avatarColor.present ? avatarColor.value : this.avatarColor,
: this.profileImagePath,
updatedAt: updatedAt ?? this.updatedAt,
quotaSizeInBytes: quotaSizeInBytes.present
? quotaSizeInBytes.value
: this.quotaSizeInBytes,
quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes,
); );
UserEntityData copyWithCompanion(i1.UserEntityCompanion data) { UserEntityData copyWithCompanion(i1.UserEntityCompanion data) {
return UserEntityData( return UserEntityData(
id: data.id.present ? data.id.value : this.id, id: data.id.present ? data.id.value : this.id,
name: data.name.present ? data.name.value : this.name, name: data.name.present ? data.name.value : this.name,
isAdmin: data.isAdmin.present ? data.isAdmin.value : this.isAdmin,
email: data.email.present ? data.email.value : this.email, email: data.email.present ? data.email.value : this.email,
profileImagePath: data.profileImagePath.present deletedAt: data.deletedAt.present ? data.deletedAt.value : this.deletedAt,
? data.profileImagePath.value avatarColor:
: this.profileImagePath, data.avatarColor.present ? data.avatarColor.value : this.avatarColor,
updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt,
quotaSizeInBytes: data.quotaSizeInBytes.present
? data.quotaSizeInBytes.value
: this.quotaSizeInBytes,
quotaUsageInBytes: data.quotaUsageInBytes.present
? data.quotaUsageInBytes.value
: this.quotaUsageInBytes,
); );
} }
@@ -507,104 +374,76 @@ class UserEntityData extends i0.DataClass
return (StringBuffer('UserEntityData(') return (StringBuffer('UserEntityData(')
..write('id: $id, ') ..write('id: $id, ')
..write('name: $name, ') ..write('name: $name, ')
..write('isAdmin: $isAdmin, ')
..write('email: $email, ') ..write('email: $email, ')
..write('profileImagePath: $profileImagePath, ') ..write('deletedAt: $deletedAt, ')
..write('updatedAt: $updatedAt, ') ..write('avatarColor: $avatarColor')
..write('quotaSizeInBytes: $quotaSizeInBytes, ')
..write('quotaUsageInBytes: $quotaUsageInBytes')
..write(')')) ..write(')'))
.toString(); .toString();
} }
@override @override
int get hashCode => Object.hash(id, name, isAdmin, email, profileImagePath, int get hashCode => Object.hash(id, name, email, deletedAt, avatarColor);
updatedAt, quotaSizeInBytes, quotaUsageInBytes);
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
(other is i1.UserEntityData && (other is i1.UserEntityData &&
other.id == this.id && other.id == this.id &&
other.name == this.name && other.name == this.name &&
other.isAdmin == this.isAdmin &&
other.email == this.email && other.email == this.email &&
other.profileImagePath == this.profileImagePath && other.deletedAt == this.deletedAt &&
other.updatedAt == this.updatedAt && other.avatarColor == this.avatarColor);
other.quotaSizeInBytes == this.quotaSizeInBytes &&
other.quotaUsageInBytes == this.quotaUsageInBytes);
} }
class UserEntityCompanion extends i0.UpdateCompanion<i1.UserEntityData> { class UserEntityCompanion extends i0.UpdateCompanion<i1.UserEntityData> {
final i0.Value<String> id; final i0.Value<String> id;
final i0.Value<String> name; final i0.Value<String> name;
final i0.Value<bool> isAdmin;
final i0.Value<String> email; final i0.Value<String> email;
final i0.Value<String?> profileImagePath; final i0.Value<DateTime?> deletedAt;
final i0.Value<DateTime> updatedAt; final i0.Value<i2.AvatarColor?> avatarColor;
final i0.Value<int?> quotaSizeInBytes;
final i0.Value<int> quotaUsageInBytes;
const UserEntityCompanion({ const UserEntityCompanion({
this.id = const i0.Value.absent(), this.id = const i0.Value.absent(),
this.name = const i0.Value.absent(), this.name = const i0.Value.absent(),
this.isAdmin = const i0.Value.absent(),
this.email = const i0.Value.absent(), this.email = const i0.Value.absent(),
this.profileImagePath = const i0.Value.absent(), this.deletedAt = const i0.Value.absent(),
this.updatedAt = const i0.Value.absent(), this.avatarColor = const i0.Value.absent(),
this.quotaSizeInBytes = const i0.Value.absent(),
this.quotaUsageInBytes = const i0.Value.absent(),
}); });
UserEntityCompanion.insert({ UserEntityCompanion.insert({
required String id, required String id,
required String name, required String name,
this.isAdmin = const i0.Value.absent(),
required String email, required String email,
this.profileImagePath = const i0.Value.absent(), this.deletedAt = const i0.Value.absent(),
this.updatedAt = const i0.Value.absent(), this.avatarColor = const i0.Value.absent(),
this.quotaSizeInBytes = const i0.Value.absent(),
this.quotaUsageInBytes = const i0.Value.absent(),
}) : id = i0.Value(id), }) : id = i0.Value(id),
name = i0.Value(name), name = i0.Value(name),
email = i0.Value(email); email = i0.Value(email);
static i0.Insertable<i1.UserEntityData> custom({ static i0.Insertable<i1.UserEntityData> custom({
i0.Expression<String>? id, i0.Expression<String>? id,
i0.Expression<String>? name, i0.Expression<String>? name,
i0.Expression<bool>? isAdmin,
i0.Expression<String>? email, i0.Expression<String>? email,
i0.Expression<String>? profileImagePath, i0.Expression<DateTime>? deletedAt,
i0.Expression<DateTime>? updatedAt, i0.Expression<int>? avatarColor,
i0.Expression<int>? quotaSizeInBytes,
i0.Expression<int>? quotaUsageInBytes,
}) { }) {
return i0.RawValuesInsertable({ return i0.RawValuesInsertable({
if (id != null) 'id': id, if (id != null) 'id': id,
if (name != null) 'name': name, if (name != null) 'name': name,
if (isAdmin != null) 'is_admin': isAdmin,
if (email != null) 'email': email, if (email != null) 'email': email,
if (profileImagePath != null) 'profile_image_path': profileImagePath, if (deletedAt != null) 'deleted_at': deletedAt,
if (updatedAt != null) 'updated_at': updatedAt, if (avatarColor != null) 'avatar_color': avatarColor,
if (quotaSizeInBytes != null) 'quota_size_in_bytes': quotaSizeInBytes,
if (quotaUsageInBytes != null) 'quota_usage_in_bytes': quotaUsageInBytes,
}); });
} }
i1.UserEntityCompanion copyWith( i1.UserEntityCompanion copyWith(
{i0.Value<String>? id, {i0.Value<String>? id,
i0.Value<String>? name, i0.Value<String>? name,
i0.Value<bool>? isAdmin,
i0.Value<String>? email, i0.Value<String>? email,
i0.Value<String?>? profileImagePath, i0.Value<DateTime?>? deletedAt,
i0.Value<DateTime>? updatedAt, i0.Value<i2.AvatarColor?>? avatarColor}) {
i0.Value<int?>? quotaSizeInBytes,
i0.Value<int>? quotaUsageInBytes}) {
return i1.UserEntityCompanion( return i1.UserEntityCompanion(
id: id ?? this.id, id: id ?? this.id,
name: name ?? this.name, name: name ?? this.name,
isAdmin: isAdmin ?? this.isAdmin,
email: email ?? this.email, email: email ?? this.email,
profileImagePath: profileImagePath ?? this.profileImagePath, deletedAt: deletedAt ?? this.deletedAt,
updatedAt: updatedAt ?? this.updatedAt, avatarColor: avatarColor ?? this.avatarColor,
quotaSizeInBytes: quotaSizeInBytes ?? this.quotaSizeInBytes,
quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes,
); );
} }
@@ -617,23 +456,15 @@ class UserEntityCompanion extends i0.UpdateCompanion<i1.UserEntityData> {
if (name.present) { if (name.present) {
map['name'] = i0.Variable<String>(name.value); map['name'] = i0.Variable<String>(name.value);
} }
if (isAdmin.present) {
map['is_admin'] = i0.Variable<bool>(isAdmin.value);
}
if (email.present) { if (email.present) {
map['email'] = i0.Variable<String>(email.value); map['email'] = i0.Variable<String>(email.value);
} }
if (profileImagePath.present) { if (deletedAt.present) {
map['profile_image_path'] = i0.Variable<String>(profileImagePath.value); map['deleted_at'] = i0.Variable<DateTime>(deletedAt.value);
} }
if (updatedAt.present) { if (avatarColor.present) {
map['updated_at'] = i0.Variable<DateTime>(updatedAt.value); map['avatar_color'] = i0.Variable<int>(
} i1.$UserEntityTable.$converteravatarColorn.toSql(avatarColor.value));
if (quotaSizeInBytes.present) {
map['quota_size_in_bytes'] = i0.Variable<int>(quotaSizeInBytes.value);
}
if (quotaUsageInBytes.present) {
map['quota_usage_in_bytes'] = i0.Variable<int>(quotaUsageInBytes.value);
} }
return map; return map;
} }
@@ -643,12 +474,9 @@ class UserEntityCompanion extends i0.UpdateCompanion<i1.UserEntityData> {
return (StringBuffer('UserEntityCompanion(') return (StringBuffer('UserEntityCompanion(')
..write('id: $id, ') ..write('id: $id, ')
..write('name: $name, ') ..write('name: $name, ')
..write('isAdmin: $isAdmin, ')
..write('email: $email, ') ..write('email: $email, ')
..write('profileImagePath: $profileImagePath, ') ..write('deletedAt: $deletedAt, ')
..write('updatedAt: $updatedAt, ') ..write('avatarColor: $avatarColor')
..write('quotaSizeInBytes: $quotaSizeInBytes, ')
..write('quotaUsageInBytes: $quotaUsageInBytes')
..write(')')) ..write(')'))
.toString(); .toString();
} }

File diff suppressed because it is too large Load Diff

View File

@@ -6,8 +6,7 @@ import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
class UserMetadataEntity extends Table with DriftDefaultsMixin { class UserMetadataEntity extends Table with DriftDefaultsMixin {
const UserMetadataEntity(); const UserMetadataEntity();
TextColumn get userId => TextColumn get userId => text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
IntColumn get key => intEnum<UserMetadataKey>()(); IntColumn get key => intEnum<UserMetadataKey>()();
@@ -17,7 +16,6 @@ class UserMetadataEntity extends Table with DriftDefaultsMixin {
Set<Column> get primaryKey => {userId, key}; Set<Column> get primaryKey => {userId, key};
} }
final JsonTypeConverter2<Map<String, Object?>, Uint8List, Object?> final JsonTypeConverter2<Map<String, Object?>, Uint8List, Object?> userMetadataConverter = TypeConverter.jsonb(
userMetadataConverter = TypeConverter.jsonb(
fromJson: (json) => json as Map<String, Object?>, fromJson: (json) => json as Map<String, Object?>,
); );

View File

@@ -8,10 +8,7 @@ class DriftAssetFaceRepository extends DriftDatabaseRepository {
const DriftAssetFaceRepository(this._db) : super(_db); const DriftAssetFaceRepository(this._db) : super(_db);
Future<List<AssetFace>> getAll() { Future<List<AssetFace>> getAll() {
return _db.assetFaceEntity return _db.assetFaceEntity.select().map((assetFace) => assetFace.toDto()).get();
.select()
.map((assetFace) => assetFace.toDto())
.get();
} }
} }

View File

@@ -25,8 +25,7 @@ class DriftBackupRepository extends DriftDatabaseRepository {
), ),
]) ])
..where( ..where(
_db.localAlbumEntity.backupSelection _db.localAlbumEntity.backupSelection.equalsValue(BackupSelection.excluded),
.equalsValue(BackupSelection.excluded),
); );
} }
@@ -41,16 +40,14 @@ class DriftBackupRepository extends DriftDatabaseRepository {
), ),
]) ])
..where( ..where(
_db.localAlbumEntity.backupSelection _db.localAlbumEntity.backupSelection.equalsValue(BackupSelection.selected) &
.equalsValue(BackupSelection.selected) & _db.localAlbumAssetEntity.assetId.isNotInQuery(_getExcludedSubquery()),
_db.localAlbumAssetEntity.assetId
.isNotInQuery(_getExcludedSubquery()),
); );
return query.get().then((rows) => rows.length); return query.get().then((rows) => rows.length);
} }
Future<int> getRemainderCount() async { Future<int> getRemainderCount(String userId) async {
final query = _db.localAlbumAssetEntity.selectOnly(distinct: true) final query = _db.localAlbumAssetEntity.selectOnly(distinct: true)
..addColumns([_db.localAlbumAssetEntity.assetId]) ..addColumns([_db.localAlbumAssetEntity.assetId])
..join([ ..join([
@@ -66,23 +63,20 @@ class DriftBackupRepository extends DriftDatabaseRepository {
), ),
leftOuterJoin( leftOuterJoin(
_db.remoteAssetEntity, _db.remoteAssetEntity,
_db.localAssetEntity.checksum _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum),
.equalsExp(_db.remoteAssetEntity.checksum),
useColumns: false, useColumns: false,
), ),
]) ])
..where( ..where(
_db.localAlbumEntity.backupSelection _db.localAlbumEntity.backupSelection.equalsValue(BackupSelection.selected) &
.equalsValue(BackupSelection.selected) & (_db.remoteAssetEntity.id.isNull() | _db.remoteAssetEntity.ownerId.equals(userId).not()) &
_db.remoteAssetEntity.id.isNull() & _db.localAlbumAssetEntity.assetId.isNotInQuery(_getExcludedSubquery()),
_db.localAlbumAssetEntity.assetId
.isNotInQuery(_getExcludedSubquery()),
); );
return query.get().then((rows) => rows.length); return query.get().then((rows) => rows.length);
} }
Future<int> getBackupCount() async { Future<int> getBackupCount(String userId) async {
final query = _db.localAlbumAssetEntity.selectOnly(distinct: true) final query = _db.localAlbumAssetEntity.selectOnly(distinct: true)
..addColumns( ..addColumns(
[_db.localAlbumAssetEntity.assetId], [_db.localAlbumAssetEntity.assetId],
@@ -100,28 +94,25 @@ class DriftBackupRepository extends DriftDatabaseRepository {
), ),
innerJoin( innerJoin(
_db.remoteAssetEntity, _db.remoteAssetEntity,
_db.localAssetEntity.checksum _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum),
.equalsExp(_db.remoteAssetEntity.checksum),
useColumns: false, useColumns: false,
), ),
]) ])
..where( ..where(
_db.localAlbumEntity.backupSelection _db.localAlbumEntity.backupSelection.equalsValue(BackupSelection.selected) &
.equalsValue(BackupSelection.selected) &
_db.remoteAssetEntity.id.isNotNull() & _db.remoteAssetEntity.id.isNotNull() &
_db.localAlbumAssetEntity.assetId _db.remoteAssetEntity.ownerId.equals(userId) &
.isNotInQuery(_getExcludedSubquery()), _db.localAlbumAssetEntity.assetId.isNotInQuery(_getExcludedSubquery()),
); );
return query.get().then((rows) => rows.length); return query.get().then((rows) => rows.length);
} }
Future<List<LocalAsset>> getCandidates() async { Future<List<LocalAsset>> getCandidates(String userId) async {
final selectedAlbumIds = _db.localAlbumEntity.selectOnly(distinct: true) final selectedAlbumIds = _db.localAlbumEntity.selectOnly(distinct: true)
..addColumns([_db.localAlbumEntity.id]) ..addColumns([_db.localAlbumEntity.id])
..where( ..where(
_db.localAlbumEntity.backupSelection _db.localAlbumEntity.backupSelection.equalsValue(BackupSelection.selected),
.equalsValue(BackupSelection.selected),
); );
final query = _db.localAssetEntity.select() final query = _db.localAssetEntity.select()
@@ -131,8 +122,7 @@ class DriftBackupRepository extends DriftDatabaseRepository {
_db.localAlbumAssetEntity.selectOnly() _db.localAlbumAssetEntity.selectOnly()
..addColumns([_db.localAlbumAssetEntity.assetId]) ..addColumns([_db.localAlbumAssetEntity.assetId])
..where( ..where(
_db.localAlbumAssetEntity.albumId _db.localAlbumAssetEntity.albumId.isInQuery(selectedAlbumIds) &
.isInQuery(selectedAlbumIds) &
_db.localAlbumAssetEntity.assetId.equalsExp(lae.id), _db.localAlbumAssetEntity.assetId.equalsExp(lae.id),
), ),
) & ) &
@@ -141,6 +131,7 @@ class DriftBackupRepository extends DriftDatabaseRepository {
..addColumns([_db.remoteAssetEntity.checksum]) ..addColumns([_db.remoteAssetEntity.checksum])
..where( ..where(
_db.remoteAssetEntity.checksum.equalsExp(lae.checksum) & _db.remoteAssetEntity.checksum.equalsExp(lae.checksum) &
_db.remoteAssetEntity.ownerId.equals(userId) &
lae.checksum.isNotNull(), lae.checksum.isNotNull(),
), ),
) & ) &

View File

@@ -4,6 +4,7 @@ import 'package:drift/drift.dart';
import 'package:drift_flutter/drift_flutter.dart'; import 'package:drift_flutter/drift_flutter.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:immich_mobile/domain/interfaces/db.interface.dart'; import 'package:immich_mobile/domain/interfaces/db.interface.dart';
import 'package:immich_mobile/infrastructure/entities/auth_user.entity.dart';
import 'package:immich_mobile/infrastructure/entities/exif.entity.dart'; import 'package:immich_mobile/infrastructure/entities/exif.entity.dart';
import 'package:immich_mobile/infrastructure/entities/asset_face.entity.dart'; import 'package:immich_mobile/infrastructure/entities/asset_face.entity.dart';
import 'package:immich_mobile/infrastructure/entities/local_album.entity.dart'; import 'package:immich_mobile/infrastructure/entities/local_album.entity.dart';
@@ -43,6 +44,7 @@ class IsarDatabaseRepository implements IDatabaseRepository {
@DriftDatabase( @DriftDatabase(
tables: [ tables: [
UserEntity, UserEntity,
AuthUserEntity,
UserMetadataEntity, UserMetadataEntity,
PartnerEntity, PartnerEntity,
LocalAlbumEntity, LocalAlbumEntity,
@@ -74,7 +76,7 @@ class Drift extends $Drift implements IDatabaseRepository {
); );
@override @override
int get schemaVersion => 4; int get schemaVersion => 5;
@override @override
MigrationStrategy get migration => MigrationStrategy( MigrationStrategy get migration => MigrationStrategy(
@@ -97,16 +99,23 @@ class Drift extends $Drift implements IDatabaseRepository {
await m.alterTable(TableMigration(v3.stackEntity)); await m.alterTable(TableMigration(v3.stackEntity));
}, },
from3To4: (m, v4) async { from3To4: (m, v4) async {
// Thumbnail path column got removed from person_entity
await m.alterTable(TableMigration(v4.personEntity)); await m.alterTable(TableMigration(v4.personEntity));
// asset_face_entity is added
await m.create(v4.assetFaceEntity); await m.create(v4.assetFaceEntity);
}, },
from4To5: (m, v5) async {
// Some column got moved from user_entity to auth_user_entity
await m.alterTable(TableMigration(v5.userEntity));
// auth_user_entity is added
await m.create(v5.authUserEntity);
},
), ),
); );
if (kDebugMode) { if (kDebugMode) {
// Fail if the migration broke foreign keys // Fail if the migration broke foreign keys
final wrongFKs = final wrongFKs = await customSelect('PRAGMA foreign_key_check').get();
await customSelect('PRAGMA foreign_key_check').get();
assert(wrongFKs.isEmpty, '${wrongFKs.map((e) => e.data)}'); assert(wrongFKs.isEmpty, '${wrongFKs.map((e) => e.data)}');
} }
@@ -125,6 +134,5 @@ class DriftDatabaseRepository implements IDatabaseRepository {
const DriftDatabaseRepository(this._db); const DriftDatabaseRepository(this._db);
@override @override
Future<T> transaction<T>(Future<T> Function() callback) => Future<T> transaction<T>(Future<T> Function() callback) => _db.transaction(callback);
_db.transaction(callback);
} }

View File

@@ -5,37 +5,39 @@ import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart'
as i1; as i1;
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart'
as i2; as i2;
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart'
as i3;
import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart'
as i3;
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart'
as i4; as i4;
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.drift.dart'
as i5;
import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart'
as i6;
import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart'
as i7; as i5;
import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.drift.dart'
as i6;
import 'package:immich_mobile/infrastructure/entities/auth_user.entity.drift.dart'
as i7;
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.drift.dart'
as i8; as i8;
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart'
as i9; as i9;
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart'
as i10; as i10;
import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart'
as i11; as i11;
import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.drift.dart'
as i12; as i12;
import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.drift.dart'
as i13; as i13;
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart'
as i14; as i14;
import 'package:immich_mobile/infrastructure/entities/person.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.drift.dart'
as i15; as i15;
import 'package:immich_mobile/infrastructure/entities/asset_face.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/person.entity.drift.dart'
as i16; as i16;
import 'package:immich_mobile/infrastructure/entities/merged_asset.drift.dart' import 'package:immich_mobile/infrastructure/entities/asset_face.entity.drift.dart'
as i17; as i17;
import 'package:drift/internal/modular.dart' as i18; import 'package:immich_mobile/infrastructure/entities/merged_asset.drift.dart'
as i18;
import 'package:drift/internal/modular.dart' as i19;
abstract class $Drift extends i0.GeneratedDatabase { abstract class $Drift extends i0.GeneratedDatabase {
$Drift(i0.QueryExecutor e) : super(e); $Drift(i0.QueryExecutor e) : super(e);
@@ -43,33 +45,35 @@ abstract class $Drift extends i0.GeneratedDatabase {
late final i1.$UserEntityTable userEntity = i1.$UserEntityTable(this); late final i1.$UserEntityTable userEntity = i1.$UserEntityTable(this);
late final i2.$RemoteAssetEntityTable remoteAssetEntity = late final i2.$RemoteAssetEntityTable remoteAssetEntity =
i2.$RemoteAssetEntityTable(this); i2.$RemoteAssetEntityTable(this);
late final i3.$LocalAssetEntityTable localAssetEntity = late final i3.$StackEntityTable stackEntity = i3.$StackEntityTable(this);
i3.$LocalAssetEntityTable(this); late final i4.$LocalAssetEntityTable localAssetEntity =
late final i4.$StackEntityTable stackEntity = i4.$StackEntityTable(this); i4.$LocalAssetEntityTable(this);
late final i5.$UserMetadataEntityTable userMetadataEntity = late final i5.$LocalAlbumEntityTable localAlbumEntity =
i5.$UserMetadataEntityTable(this); i5.$LocalAlbumEntityTable(this);
late final i6.$PartnerEntityTable partnerEntity = late final i6.$LocalAlbumAssetEntityTable localAlbumAssetEntity =
i6.$PartnerEntityTable(this); i6.$LocalAlbumAssetEntityTable(this);
late final i7.$LocalAlbumEntityTable localAlbumEntity = late final i7.$AuthUserEntityTable authUserEntity =
i7.$LocalAlbumEntityTable(this); i7.$AuthUserEntityTable(this);
late final i8.$LocalAlbumAssetEntityTable localAlbumAssetEntity = late final i8.$UserMetadataEntityTable userMetadataEntity =
i8.$LocalAlbumAssetEntityTable(this); i8.$UserMetadataEntityTable(this);
late final i9.$RemoteExifEntityTable remoteExifEntity = late final i9.$PartnerEntityTable partnerEntity =
i9.$RemoteExifEntityTable(this); i9.$PartnerEntityTable(this);
late final i10.$RemoteAlbumEntityTable remoteAlbumEntity = late final i10.$RemoteExifEntityTable remoteExifEntity =
i10.$RemoteAlbumEntityTable(this); i10.$RemoteExifEntityTable(this);
late final i11.$RemoteAlbumAssetEntityTable remoteAlbumAssetEntity = late final i11.$RemoteAlbumEntityTable remoteAlbumEntity =
i11.$RemoteAlbumAssetEntityTable(this); i11.$RemoteAlbumEntityTable(this);
late final i12.$RemoteAlbumUserEntityTable remoteAlbumUserEntity = late final i12.$RemoteAlbumAssetEntityTable remoteAlbumAssetEntity =
i12.$RemoteAlbumUserEntityTable(this); i12.$RemoteAlbumAssetEntityTable(this);
late final i13.$MemoryEntityTable memoryEntity = i13.$MemoryEntityTable(this); late final i13.$RemoteAlbumUserEntityTable remoteAlbumUserEntity =
late final i14.$MemoryAssetEntityTable memoryAssetEntity = i13.$RemoteAlbumUserEntityTable(this);
i14.$MemoryAssetEntityTable(this); late final i14.$MemoryEntityTable memoryEntity = i14.$MemoryEntityTable(this);
late final i15.$PersonEntityTable personEntity = i15.$PersonEntityTable(this); late final i15.$MemoryAssetEntityTable memoryAssetEntity =
late final i16.$AssetFaceEntityTable assetFaceEntity = i15.$MemoryAssetEntityTable(this);
i16.$AssetFaceEntityTable(this); late final i16.$PersonEntityTable personEntity = i16.$PersonEntityTable(this);
i17.MergedAssetDrift get mergedAssetDrift => i18.ReadDatabaseContainer(this) late final i17.$AssetFaceEntityTable assetFaceEntity =
.accessor<i17.MergedAssetDrift>(i17.MergedAssetDrift.new); i17.$AssetFaceEntityTable(this);
i18.MergedAssetDrift get mergedAssetDrift => i19.ReadDatabaseContainer(this)
.accessor<i18.MergedAssetDrift>(i18.MergedAssetDrift.new);
@override @override
Iterable<i0.TableInfo<i0.Table, Object?>> get allTables => Iterable<i0.TableInfo<i0.Table, Object?>> get allTables =>
allSchemaEntities.whereType<i0.TableInfo<i0.Table, Object?>>(); allSchemaEntities.whereType<i0.TableInfo<i0.Table, Object?>>();
@@ -77,15 +81,16 @@ abstract class $Drift extends i0.GeneratedDatabase {
List<i0.DatabaseSchemaEntity> get allSchemaEntities => [ List<i0.DatabaseSchemaEntity> get allSchemaEntities => [
userEntity, userEntity,
remoteAssetEntity, remoteAssetEntity,
localAssetEntity,
stackEntity, stackEntity,
i3.idxLocalAssetChecksum, localAssetEntity,
i2.uQRemoteAssetOwnerChecksum,
i2.idxRemoteAssetChecksum,
userMetadataEntity,
partnerEntity,
localAlbumEntity, localAlbumEntity,
localAlbumAssetEntity, localAlbumAssetEntity,
i4.idxLocalAssetChecksum,
i2.uQRemoteAssetOwnerChecksum,
i2.idxRemoteAssetChecksum,
authUserEntity,
userMetadataEntity,
partnerEntity,
remoteExifEntity, remoteExifEntity,
remoteAlbumEntity, remoteAlbumEntity,
remoteAlbumAssetEntity, remoteAlbumAssetEntity,
@@ -113,6 +118,22 @@ abstract class $Drift extends i0.GeneratedDatabase {
i0.TableUpdate('stack_entity', kind: i0.UpdateKind.delete), i0.TableUpdate('stack_entity', kind: i0.UpdateKind.delete),
], ],
), ),
i0.WritePropagation(
on: i0.TableUpdateQuery.onTableName('local_asset_entity',
limitUpdateKind: i0.UpdateKind.delete),
result: [
i0.TableUpdate('local_album_asset_entity',
kind: i0.UpdateKind.delete),
],
),
i0.WritePropagation(
on: i0.TableUpdateQuery.onTableName('local_album_entity',
limitUpdateKind: i0.UpdateKind.delete),
result: [
i0.TableUpdate('local_album_asset_entity',
kind: i0.UpdateKind.delete),
],
),
i0.WritePropagation( i0.WritePropagation(
on: i0.TableUpdateQuery.onTableName('user_entity', on: i0.TableUpdateQuery.onTableName('user_entity',
limitUpdateKind: i0.UpdateKind.delete), limitUpdateKind: i0.UpdateKind.delete),
@@ -135,22 +156,6 @@ abstract class $Drift extends i0.GeneratedDatabase {
i0.TableUpdate('partner_entity', kind: i0.UpdateKind.delete), i0.TableUpdate('partner_entity', kind: i0.UpdateKind.delete),
], ],
), ),
i0.WritePropagation(
on: i0.TableUpdateQuery.onTableName('local_asset_entity',
limitUpdateKind: i0.UpdateKind.delete),
result: [
i0.TableUpdate('local_album_asset_entity',
kind: i0.UpdateKind.delete),
],
),
i0.WritePropagation(
on: i0.TableUpdateQuery.onTableName('local_album_entity',
limitUpdateKind: i0.UpdateKind.delete),
result: [
i0.TableUpdate('local_album_asset_entity',
kind: i0.UpdateKind.delete),
],
),
i0.WritePropagation( i0.WritePropagation(
on: i0.TableUpdateQuery.onTableName('remote_asset_entity', on: i0.TableUpdateQuery.onTableName('remote_asset_entity',
limitUpdateKind: i0.UpdateKind.delete), limitUpdateKind: i0.UpdateKind.delete),
@@ -260,33 +265,35 @@ class $DriftManager {
i1.$$UserEntityTableTableManager(_db, _db.userEntity); i1.$$UserEntityTableTableManager(_db, _db.userEntity);
i2.$$RemoteAssetEntityTableTableManager get remoteAssetEntity => i2.$$RemoteAssetEntityTableTableManager get remoteAssetEntity =>
i2.$$RemoteAssetEntityTableTableManager(_db, _db.remoteAssetEntity); i2.$$RemoteAssetEntityTableTableManager(_db, _db.remoteAssetEntity);
i3.$$LocalAssetEntityTableTableManager get localAssetEntity => i3.$$StackEntityTableTableManager get stackEntity =>
i3.$$LocalAssetEntityTableTableManager(_db, _db.localAssetEntity); i3.$$StackEntityTableTableManager(_db, _db.stackEntity);
i4.$$StackEntityTableTableManager get stackEntity => i4.$$LocalAssetEntityTableTableManager get localAssetEntity =>
i4.$$StackEntityTableTableManager(_db, _db.stackEntity); i4.$$LocalAssetEntityTableTableManager(_db, _db.localAssetEntity);
i5.$$UserMetadataEntityTableTableManager get userMetadataEntity => i5.$$LocalAlbumEntityTableTableManager get localAlbumEntity =>
i5.$$UserMetadataEntityTableTableManager(_db, _db.userMetadataEntity); i5.$$LocalAlbumEntityTableTableManager(_db, _db.localAlbumEntity);
i6.$$PartnerEntityTableTableManager get partnerEntity => i6.$$LocalAlbumAssetEntityTableTableManager get localAlbumAssetEntity => i6
i6.$$PartnerEntityTableTableManager(_db, _db.partnerEntity);
i7.$$LocalAlbumEntityTableTableManager get localAlbumEntity =>
i7.$$LocalAlbumEntityTableTableManager(_db, _db.localAlbumEntity);
i8.$$LocalAlbumAssetEntityTableTableManager get localAlbumAssetEntity => i8
.$$LocalAlbumAssetEntityTableTableManager(_db, _db.localAlbumAssetEntity); .$$LocalAlbumAssetEntityTableTableManager(_db, _db.localAlbumAssetEntity);
i9.$$RemoteExifEntityTableTableManager get remoteExifEntity => i7.$$AuthUserEntityTableTableManager get authUserEntity =>
i9.$$RemoteExifEntityTableTableManager(_db, _db.remoteExifEntity); i7.$$AuthUserEntityTableTableManager(_db, _db.authUserEntity);
i10.$$RemoteAlbumEntityTableTableManager get remoteAlbumEntity => i8.$$UserMetadataEntityTableTableManager get userMetadataEntity =>
i10.$$RemoteAlbumEntityTableTableManager(_db, _db.remoteAlbumEntity); i8.$$UserMetadataEntityTableTableManager(_db, _db.userMetadataEntity);
i11.$$RemoteAlbumAssetEntityTableTableManager get remoteAlbumAssetEntity => i9.$$PartnerEntityTableTableManager get partnerEntity =>
i11.$$RemoteAlbumAssetEntityTableTableManager( i9.$$PartnerEntityTableTableManager(_db, _db.partnerEntity);
i10.$$RemoteExifEntityTableTableManager get remoteExifEntity =>
i10.$$RemoteExifEntityTableTableManager(_db, _db.remoteExifEntity);
i11.$$RemoteAlbumEntityTableTableManager get remoteAlbumEntity =>
i11.$$RemoteAlbumEntityTableTableManager(_db, _db.remoteAlbumEntity);
i12.$$RemoteAlbumAssetEntityTableTableManager get remoteAlbumAssetEntity =>
i12.$$RemoteAlbumAssetEntityTableTableManager(
_db, _db.remoteAlbumAssetEntity); _db, _db.remoteAlbumAssetEntity);
i12.$$RemoteAlbumUserEntityTableTableManager get remoteAlbumUserEntity => i12 i13.$$RemoteAlbumUserEntityTableTableManager get remoteAlbumUserEntity => i13
.$$RemoteAlbumUserEntityTableTableManager(_db, _db.remoteAlbumUserEntity); .$$RemoteAlbumUserEntityTableTableManager(_db, _db.remoteAlbumUserEntity);
i13.$$MemoryEntityTableTableManager get memoryEntity => i14.$$MemoryEntityTableTableManager get memoryEntity =>
i13.$$MemoryEntityTableTableManager(_db, _db.memoryEntity); i14.$$MemoryEntityTableTableManager(_db, _db.memoryEntity);
i14.$$MemoryAssetEntityTableTableManager get memoryAssetEntity => i15.$$MemoryAssetEntityTableTableManager get memoryAssetEntity =>
i14.$$MemoryAssetEntityTableTableManager(_db, _db.memoryAssetEntity); i15.$$MemoryAssetEntityTableTableManager(_db, _db.memoryAssetEntity);
i15.$$PersonEntityTableTableManager get personEntity => i16.$$PersonEntityTableTableManager get personEntity =>
i15.$$PersonEntityTableTableManager(_db, _db.personEntity); i16.$$PersonEntityTableTableManager(_db, _db.personEntity);
i16.$$AssetFaceEntityTableTableManager get assetFaceEntity => i17.$$AssetFaceEntityTableTableManager get assetFaceEntity =>
i16.$$AssetFaceEntityTableTableManager(_db, _db.assetFaceEntity); i17.$$AssetFaceEntityTableTableManager(_db, _db.assetFaceEntity);
} }

View File

@@ -1273,15 +1273,15 @@ final class Schema4 extends i0.VersionedSchema {
late final List<i1.DatabaseSchemaEntity> entities = [ late final List<i1.DatabaseSchemaEntity> entities = [
userEntity, userEntity,
remoteAssetEntity, remoteAssetEntity,
localAssetEntity,
stackEntity, stackEntity,
localAssetEntity,
localAlbumEntity,
localAlbumAssetEntity,
idxLocalAssetChecksum, idxLocalAssetChecksum,
uQRemoteAssetOwnerChecksum, uQRemoteAssetOwnerChecksum,
idxRemoteAssetChecksum, idxRemoteAssetChecksum,
userMetadataEntity, userMetadataEntity,
partnerEntity, partnerEntity,
localAlbumEntity,
localAlbumAssetEntity,
remoteExifEntity, remoteExifEntity,
remoteAlbumEntity, remoteAlbumEntity,
remoteAlbumAssetEntity, remoteAlbumAssetEntity,
@@ -1342,6 +1342,24 @@ final class Schema4 extends i0.VersionedSchema {
attachedDatabase: database, attachedDatabase: database,
), ),
alias: null); alias: null);
late final Shape3 stackEntity = Shape3(
source: i0.VersionedTable(
entityName: 'stack_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(id)',
],
columns: [
_column_0,
_column_9,
_column_5,
_column_15,
_column_75,
],
attachedDatabase: database,
),
alias: null);
late final Shape2 localAssetEntity = Shape2( late final Shape2 localAssetEntity = Shape2(
source: i0.VersionedTable( source: i0.VersionedTable(
entityName: 'local_asset_entity', entityName: 'local_asset_entity',
@@ -1366,9 +1384,9 @@ final class Schema4 extends i0.VersionedSchema {
attachedDatabase: database, attachedDatabase: database,
), ),
alias: null); alias: null);
late final Shape3 stackEntity = Shape3( late final Shape6 localAlbumEntity = Shape6(
source: i0.VersionedTable( source: i0.VersionedTable(
entityName: 'stack_entity', entityName: 'local_album_entity',
withoutRowId: true, withoutRowId: true,
isStrict: true, isStrict: true,
tableConstraints: [ tableConstraints: [
@@ -1376,10 +1394,26 @@ final class Schema4 extends i0.VersionedSchema {
], ],
columns: [ columns: [
_column_0, _column_0,
_column_9, _column_1,
_column_5, _column_5,
_column_15, _column_31,
_column_75, _column_32,
_column_33,
],
attachedDatabase: database,
),
alias: null);
late final Shape7 localAlbumAssetEntity = Shape7(
source: i0.VersionedTable(
entityName: 'local_album_asset_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(asset_id, album_id)',
],
columns: [
_column_34,
_column_35,
], ],
attachedDatabase: database, attachedDatabase: database,
), ),
@@ -1423,40 +1457,6 @@ final class Schema4 extends i0.VersionedSchema {
attachedDatabase: database, attachedDatabase: database,
), ),
alias: null); alias: null);
late final Shape6 localAlbumEntity = Shape6(
source: i0.VersionedTable(
entityName: 'local_album_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(id)',
],
columns: [
_column_0,
_column_1,
_column_5,
_column_31,
_column_32,
_column_33,
],
attachedDatabase: database,
),
alias: null);
late final Shape7 localAlbumAssetEntity = Shape7(
source: i0.VersionedTable(
entityName: 'local_album_asset_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(asset_id, album_id)',
],
columns: [
_column_34,
_column_35,
],
attachedDatabase: database,
),
alias: null);
late final Shape8 remoteExifEntity = Shape8( late final Shape8 remoteExifEntity = Shape8(
source: i0.VersionedTable( source: i0.VersionedTable(
entityName: 'remote_exif_entity', entityName: 'remote_exif_entity',
@@ -1707,10 +1707,470 @@ i1.GeneratedColumn<int> _column_82(String aliasedName) =>
i1.GeneratedColumn<String> _column_83(String aliasedName) => i1.GeneratedColumn<String> _column_83(String aliasedName) =>
i1.GeneratedColumn<String>('source_type', aliasedName, false, i1.GeneratedColumn<String>('source_type', aliasedName, false,
type: i1.DriftSqlType.string); type: i1.DriftSqlType.string);
final class Schema5 extends i0.VersionedSchema {
Schema5({required super.database}) : super(version: 5);
@override
late final List<i1.DatabaseSchemaEntity> entities = [
userEntity,
remoteAssetEntity,
stackEntity,
localAssetEntity,
localAlbumEntity,
localAlbumAssetEntity,
idxLocalAssetChecksum,
uQRemoteAssetOwnerChecksum,
idxRemoteAssetChecksum,
authUserEntity,
userMetadataEntity,
partnerEntity,
remoteExifEntity,
remoteAlbumEntity,
remoteAlbumAssetEntity,
remoteAlbumUserEntity,
memoryEntity,
memoryAssetEntity,
personEntity,
assetFaceEntity,
];
late final Shape16 userEntity = Shape16(
source: i0.VersionedTable(
entityName: 'user_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(id)',
],
columns: [
_column_0,
_column_1,
_column_3,
_column_18,
_column_84,
],
attachedDatabase: database,
),
alias: null);
late final Shape1 remoteAssetEntity = Shape1(
source: i0.VersionedTable(
entityName: 'remote_asset_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(id)',
],
columns: [
_column_1,
_column_8,
_column_9,
_column_5,
_column_10,
_column_11,
_column_12,
_column_0,
_column_13,
_column_14,
_column_15,
_column_16,
_column_17,
_column_18,
_column_19,
_column_20,
_column_21,
],
attachedDatabase: database,
),
alias: null);
late final Shape3 stackEntity = Shape3(
source: i0.VersionedTable(
entityName: 'stack_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(id)',
],
columns: [
_column_0,
_column_9,
_column_5,
_column_15,
_column_75,
],
attachedDatabase: database,
),
alias: null);
late final Shape2 localAssetEntity = Shape2(
source: i0.VersionedTable(
entityName: 'local_asset_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(id)',
],
columns: [
_column_1,
_column_8,
_column_9,
_column_5,
_column_10,
_column_11,
_column_12,
_column_0,
_column_22,
_column_14,
_column_23,
],
attachedDatabase: database,
),
alias: null);
late final Shape6 localAlbumEntity = Shape6(
source: i0.VersionedTable(
entityName: 'local_album_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(id)',
],
columns: [
_column_0,
_column_1,
_column_5,
_column_31,
_column_32,
_column_33,
],
attachedDatabase: database,
),
alias: null);
late final Shape7 localAlbumAssetEntity = Shape7(
source: i0.VersionedTable(
entityName: 'local_album_asset_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(asset_id, album_id)',
],
columns: [
_column_34,
_column_35,
],
attachedDatabase: database,
),
alias: null);
final i1.Index idxLocalAssetChecksum = i1.Index('idx_local_asset_checksum',
'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)');
final i1.Index uQRemoteAssetOwnerChecksum = i1.Index(
'UQ_remote_asset_owner_checksum',
'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)');
final i1.Index idxRemoteAssetChecksum = i1.Index('idx_remote_asset_checksum',
'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)');
late final Shape17 authUserEntity = Shape17(
source: i0.VersionedTable(
entityName: 'auth_user_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(id)',
],
columns: [
_column_0,
_column_1,
_column_3,
_column_18,
_column_84,
_column_2,
_column_85,
_column_86,
_column_87,
_column_88,
_column_6,
_column_7,
_column_89,
],
attachedDatabase: database,
),
alias: null);
late final Shape4 userMetadataEntity = Shape4(
source: i0.VersionedTable(
entityName: 'user_metadata_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(user_id, "key")',
],
columns: [
_column_25,
_column_26,
_column_27,
],
attachedDatabase: database,
),
alias: null);
late final Shape5 partnerEntity = Shape5(
source: i0.VersionedTable(
entityName: 'partner_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(shared_by_id, shared_with_id)',
],
columns: [
_column_28,
_column_29,
_column_30,
],
attachedDatabase: database,
),
alias: null);
late final Shape8 remoteExifEntity = Shape8(
source: i0.VersionedTable(
entityName: 'remote_exif_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(asset_id)',
],
columns: [
_column_36,
_column_37,
_column_38,
_column_39,
_column_40,
_column_41,
_column_11,
_column_10,
_column_42,
_column_43,
_column_44,
_column_45,
_column_46,
_column_47,
_column_48,
_column_49,
_column_50,
_column_51,
_column_52,
_column_53,
_column_54,
_column_55,
],
attachedDatabase: database,
),
alias: null);
late final Shape9 remoteAlbumEntity = Shape9(
source: i0.VersionedTable(
entityName: 'remote_album_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(id)',
],
columns: [
_column_0,
_column_1,
_column_56,
_column_9,
_column_5,
_column_15,
_column_57,
_column_58,
_column_59,
],
attachedDatabase: database,
),
alias: null);
late final Shape7 remoteAlbumAssetEntity = Shape7(
source: i0.VersionedTable(
entityName: 'remote_album_asset_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(asset_id, album_id)',
],
columns: [
_column_36,
_column_60,
],
attachedDatabase: database,
),
alias: null);
late final Shape10 remoteAlbumUserEntity = Shape10(
source: i0.VersionedTable(
entityName: 'remote_album_user_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(album_id, user_id)',
],
columns: [
_column_60,
_column_25,
_column_61,
],
attachedDatabase: database,
),
alias: null);
late final Shape11 memoryEntity = Shape11(
source: i0.VersionedTable(
entityName: 'memory_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(id)',
],
columns: [
_column_0,
_column_9,
_column_5,
_column_18,
_column_15,
_column_8,
_column_62,
_column_63,
_column_64,
_column_65,
_column_66,
_column_67,
],
attachedDatabase: database,
),
alias: null);
late final Shape12 memoryAssetEntity = Shape12(
source: i0.VersionedTable(
entityName: 'memory_asset_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(asset_id, memory_id)',
],
columns: [
_column_36,
_column_68,
],
attachedDatabase: database,
),
alias: null);
late final Shape14 personEntity = Shape14(
source: i0.VersionedTable(
entityName: 'person_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(id)',
],
columns: [
_column_0,
_column_9,
_column_5,
_column_15,
_column_1,
_column_69,
_column_71,
_column_72,
_column_73,
_column_74,
],
attachedDatabase: database,
),
alias: null);
late final Shape15 assetFaceEntity = Shape15(
source: i0.VersionedTable(
entityName: 'asset_face_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: [
'PRIMARY KEY(id)',
],
columns: [
_column_0,
_column_36,
_column_76,
_column_77,
_column_78,
_column_79,
_column_80,
_column_81,
_column_82,
_column_83,
],
attachedDatabase: database,
),
alias: null);
}
class Shape16 extends i0.VersionedTable {
Shape16({required super.source, required super.alias}) : super.aliased();
i1.GeneratedColumn<String> get id =>
columnsByName['id']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<String> get name =>
columnsByName['name']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<String> get email =>
columnsByName['email']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<DateTime> get deletedAt =>
columnsByName['deleted_at']! as i1.GeneratedColumn<DateTime>;
i1.GeneratedColumn<int> get avatarColor =>
columnsByName['avatar_color']! as i1.GeneratedColumn<int>;
}
i1.GeneratedColumn<int> _column_84(String aliasedName) =>
i1.GeneratedColumn<int>('avatar_color', aliasedName, true,
type: i1.DriftSqlType.int);
class Shape17 extends i0.VersionedTable {
Shape17({required super.source, required super.alias}) : super.aliased();
i1.GeneratedColumn<String> get id =>
columnsByName['id']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<String> get name =>
columnsByName['name']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<String> get email =>
columnsByName['email']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<DateTime> get deletedAt =>
columnsByName['deleted_at']! as i1.GeneratedColumn<DateTime>;
i1.GeneratedColumn<int> get avatarColor =>
columnsByName['avatar_color']! as i1.GeneratedColumn<int>;
i1.GeneratedColumn<bool> get isAdmin =>
columnsByName['is_admin']! as i1.GeneratedColumn<bool>;
i1.GeneratedColumn<String> get oauthId =>
columnsByName['oauth_id']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<String> get pinCode =>
columnsByName['pin_code']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<bool> get hasProfileImage =>
columnsByName['has_profile_image']! as i1.GeneratedColumn<bool>;
i1.GeneratedColumn<DateTime> get profileChangedAt =>
columnsByName['profile_changed_at']! as i1.GeneratedColumn<DateTime>;
i1.GeneratedColumn<int> get quotaSizeInBytes =>
columnsByName['quota_size_in_bytes']! as i1.GeneratedColumn<int>;
i1.GeneratedColumn<int> get quotaUsageInBytes =>
columnsByName['quota_usage_in_bytes']! as i1.GeneratedColumn<int>;
i1.GeneratedColumn<String> get storageLabel =>
columnsByName['storage_label']! as i1.GeneratedColumn<String>;
}
i1.GeneratedColumn<String> _column_85(String aliasedName) =>
i1.GeneratedColumn<String>('oauth_id', aliasedName, false,
type: i1.DriftSqlType.string,
defaultValue: const CustomExpression('\'\''));
i1.GeneratedColumn<String> _column_86(String aliasedName) =>
i1.GeneratedColumn<String>('pin_code', aliasedName, true,
type: i1.DriftSqlType.string);
i1.GeneratedColumn<bool> _column_87(String aliasedName) =>
i1.GeneratedColumn<bool>('has_profile_image', aliasedName, false,
type: i1.DriftSqlType.bool,
defaultConstraints: i1.GeneratedColumn.constraintIsAlways(
'CHECK ("has_profile_image" IN (0, 1))'),
defaultValue: const CustomExpression('0'));
i1.GeneratedColumn<DateTime> _column_88(String aliasedName) =>
i1.GeneratedColumn<DateTime>('profile_changed_at', aliasedName, false,
type: i1.DriftSqlType.dateTime,
defaultValue: const CustomExpression('CURRENT_TIMESTAMP'));
i1.GeneratedColumn<String> _column_89(String aliasedName) =>
i1.GeneratedColumn<String>('storage_label', aliasedName, true,
type: i1.DriftSqlType.string);
i0.MigrationStepWithVersion migrationSteps({ i0.MigrationStepWithVersion migrationSteps({
required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2, required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3, required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
required Future<void> Function(i1.Migrator m, Schema4 schema) from3To4, required Future<void> Function(i1.Migrator m, Schema4 schema) from3To4,
required Future<void> Function(i1.Migrator m, Schema5 schema) from4To5,
}) { }) {
return (currentVersion, database) async { return (currentVersion, database) async {
switch (currentVersion) { switch (currentVersion) {
@@ -1729,6 +2189,11 @@ i0.MigrationStepWithVersion migrationSteps({
final migrator = i1.Migrator(database, schema); final migrator = i1.Migrator(database, schema);
await from3To4(migrator, schema); await from3To4(migrator, schema);
return 4; return 4;
case 4:
final schema = Schema5(database: database);
final migrator = i1.Migrator(database, schema);
await from4To5(migrator, schema);
return 5;
default: default:
throw ArgumentError.value('Unknown migration from $currentVersion'); throw ArgumentError.value('Unknown migration from $currentVersion');
} }
@@ -1739,10 +2204,12 @@ i1.OnUpgrade stepByStep({
required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2, required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3, required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
required Future<void> Function(i1.Migrator m, Schema4 schema) from3To4, required Future<void> Function(i1.Migrator m, Schema4 schema) from3To4,
required Future<void> Function(i1.Migrator m, Schema5 schema) from4To5,
}) => }) =>
i0.VersionedSchema.stepByStepHelper( i0.VersionedSchema.stepByStepHelper(
step: migrationSteps( step: migrationSteps(
from1To2: from1To2, from1To2: from1To2,
from2To3: from2To3, from2To3: from2To3,
from3To4: from3To4, from3To4: from3To4,
from4To5: from4To5,
)); ));

View File

@@ -24,8 +24,7 @@ class IsarDeviceAssetRepository extends IsarDatabaseRepository {
Future<bool> updateAll(List<DeviceAsset> assetHash) { Future<bool> updateAll(List<DeviceAsset> assetHash) {
return transaction(() async { return transaction(() async {
await _db.deviceAssetEntitys await _db.deviceAssetEntitys.putAll(assetHash.map(DeviceAssetEntity.fromDto).toList());
.putAll(assetHash.map(DeviceAssetEntity.fromDto).toList());
return true; return true;
}); });
} }

View File

@@ -1,6 +1,5 @@
import 'package:immich_mobile/domain/models/exif.model.dart'; import 'package:immich_mobile/domain/models/exif.model.dart';
import 'package:immich_mobile/infrastructure/entities/exif.entity.dart' import 'package:immich_mobile/infrastructure/entities/exif.entity.dart' as entity;
as entity;
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart'; import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';

View File

@@ -8,13 +8,7 @@ import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
import 'package:immich_mobile/utils/database.utils.dart'; import 'package:immich_mobile/utils/database.utils.dart';
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
enum SortLocalAlbumsBy { enum SortLocalAlbumsBy { id, backupSelection, isIosSharedAlbum, name, assetCount }
id,
backupSelection,
isIosSharedAlbum,
name,
assetCount
}
class DriftLocalAlbumRepository extends DriftDatabaseRepository { class DriftLocalAlbumRepository extends DriftDatabaseRepository {
final Drift _db; final Drift _db;
@@ -43,12 +37,9 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
orderings.add( orderings.add(
switch (sort) { switch (sort) {
SortLocalAlbumsBy.id => OrderingTerm.asc(_db.localAlbumEntity.id), SortLocalAlbumsBy.id => OrderingTerm.asc(_db.localAlbumEntity.id),
SortLocalAlbumsBy.backupSelection => SortLocalAlbumsBy.backupSelection => OrderingTerm.asc(_db.localAlbumEntity.backupSelection),
OrderingTerm.asc(_db.localAlbumEntity.backupSelection), SortLocalAlbumsBy.isIosSharedAlbum => OrderingTerm.asc(_db.localAlbumEntity.isIosSharedAlbum),
SortLocalAlbumsBy.isIosSharedAlbum => SortLocalAlbumsBy.name => OrderingTerm.asc(_db.localAlbumEntity.name),
OrderingTerm.asc(_db.localAlbumEntity.isIosSharedAlbum),
SortLocalAlbumsBy.name =>
OrderingTerm.asc(_db.localAlbumEntity.name),
SortLocalAlbumsBy.assetCount => OrderingTerm.desc(assetCount), SortLocalAlbumsBy.assetCount => OrderingTerm.desc(assetCount),
}, },
); );
@@ -58,9 +49,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
return query return query
.map( .map(
(row) => row (row) => row.readTable(_db.localAlbumEntity).toDto(assetCount: row.read(assetCount) ?? 0),
.readTable(_db.localAlbumEntity)
.toDto(assetCount: row.read(assetCount) ?? 0),
) )
.get(); .get();
} }
@@ -69,15 +58,11 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
// Remove all assets that are only in this particular album // Remove all assets that are only in this particular album
// We cannot remove all assets in the album because they might be in other albums in iOS // We cannot remove all assets in the album because they might be in other albums in iOS
// That is not the case on Android since asset <-> album has one:one mapping // That is not the case on Android since asset <-> album has one:one mapping
final assetsToDelete = _platform.isIOS final assetsToDelete = _platform.isIOS ? await _getUniqueAssetsInAlbum(albumId) : await getAssetIds(albumId);
? await _getUniqueAssetsInAlbum(albumId)
: await getAssetIds(albumId);
await _deleteAssets(assetsToDelete); await _deleteAssets(assetsToDelete);
// All the other assets that are still associated will be unlinked automatically on-cascade // All the other assets that are still associated will be unlinked automatically on-cascade
await _db.managers.localAlbumEntity await _db.managers.localAlbumEntity.filter((a) => a.id.equals(albumId)).delete();
.filter((a) => a.id.equals(albumId))
.delete();
}); });
Future<void> syncDeletes( Future<void> syncDeletes(
@@ -95,13 +80,11 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
..join([ ..join([
innerJoin( innerJoin(
_db.localAlbumEntity, _db.localAlbumEntity,
_db.localAlbumAssetEntity.albumId _db.localAlbumAssetEntity.albumId.equalsExp(_db.localAlbumEntity.id),
.equalsExp(_db.localAlbumEntity.id),
), ),
]); ]);
subQuery.where( subQuery.where(
_db.localAlbumEntity.id.equals(albumId) & _db.localAlbumEntity.id.equals(albumId) & _db.localAlbumAssetEntity.assetId.isNotIn(assetIdsToKeep),
_db.localAlbumAssetEntity.assetId.isNotIn(assetIdsToKeep),
); );
return localAsset.id.isInQuery(subQuery); return localAsset.id.isInQuery(subQuery);
}); });
@@ -122,8 +105,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
); );
return _db.transaction(() async { return _db.transaction(() async {
await _db.localAlbumEntity await _db.localAlbumEntity.insertOne(companion, onConflict: DoUpdate((_) => companion));
.insertOne(companion, onConflict: DoUpdate((_) => companion));
if (toUpsert.isNotEmpty) { if (toUpsert.isNotEmpty) {
await _upsertAssets(toUpsert); await _upsertAssets(toUpsert);
await _db.localAlbumAssetEntity.insertAll( await _db.localAlbumAssetEntity.insertAll(
@@ -142,9 +124,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
Future<void> updateAll(Iterable<LocalAlbum> albums) { Future<void> updateAll(Iterable<LocalAlbum> albums) {
return _db.transaction(() async { return _db.transaction(() async {
await _db.localAlbumEntity await _db.localAlbumEntity.update().write(const LocalAlbumEntityCompanion(marker_: Value(true)));
.update()
.write(const LocalAlbumEntityCompanion(marker_: Value(true)));
await _db.batch((batch) { await _db.batch((batch) {
for (final album in albums) { for (final album in albums) {
@@ -184,8 +164,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
..join([ ..join([
innerJoin( innerJoin(
_db.localAlbumEntity, _db.localAlbumEntity,
_db.localAlbumAssetEntity.albumId _db.localAlbumAssetEntity.albumId.equalsExp(_db.localAlbumEntity.id),
.equalsExp(_db.localAlbumEntity.id),
), ),
]); ]);
subQuery.where(_db.localAlbumEntity.marker_.isNotNull()); subQuery.where(_db.localAlbumEntity.marker_.isNotNull());
@@ -209,18 +188,14 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
) )
..where(_db.localAlbumAssetEntity.albumId.equals(albumId)) ..where(_db.localAlbumAssetEntity.albumId.equals(albumId))
..orderBy([OrderingTerm.asc(_db.localAssetEntity.id)]); ..orderBy([OrderingTerm.asc(_db.localAssetEntity.id)]);
return query return query.map((row) => row.readTable(_db.localAssetEntity).toDto()).get();
.map((row) => row.readTable(_db.localAssetEntity).toDto())
.get();
} }
Future<List<String>> getAssetIds(String albumId) { Future<List<String>> getAssetIds(String albumId) {
final query = _db.localAlbumAssetEntity.selectOnly() final query = _db.localAlbumAssetEntity.selectOnly()
..addColumns([_db.localAlbumAssetEntity.assetId]) ..addColumns([_db.localAlbumAssetEntity.assetId])
..where(_db.localAlbumAssetEntity.albumId.equals(albumId)); ..where(_db.localAlbumAssetEntity.albumId.equals(albumId));
return query return query.map((row) => row.read(_db.localAlbumAssetEntity.assetId)!).get();
.map((row) => row.read(_db.localAlbumAssetEntity.assetId)!)
.get();
} }
Future<void> processDelta({ Future<void> processDelta({
@@ -240,9 +215,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
assetAlbums.cast<String, List<Object?>>().forEach((assetId, albumIds) { assetAlbums.cast<String, List<Object?>>().forEach((assetId, albumIds) {
batch.deleteWhere( batch.deleteWhere(
_db.localAlbumAssetEntity, _db.localAlbumAssetEntity,
(f) => (f) => f.albumId.isNotIn(albumIds.cast<String?>().nonNulls) & f.assetId.equals(assetId),
f.albumId.isNotIn(albumIds.cast<String?>().nonNulls) &
f.assetId.equals(assetId),
); );
}); });
}); });
@@ -273,14 +246,11 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
], ],
) )
..where( ..where(
_db.localAlbumAssetEntity.albumId.equals(albumId) & _db.localAlbumAssetEntity.albumId.equals(albumId) & _db.localAssetEntity.checksum.isNull(),
_db.localAssetEntity.checksum.isNull(),
) )
..orderBy([OrderingTerm.asc(_db.localAssetEntity.id)]); ..orderBy([OrderingTerm.asc(_db.localAssetEntity.id)]);
return query return query.map((row) => row.readTable(_db.localAssetEntity).toDto()).get();
.map((row) => row.readTable(_db.localAssetEntity).toDto())
.get();
} }
Future<void> _upsertAssets(Iterable<LocalAsset> localAssets) { Future<void> _upsertAssets(Iterable<LocalAsset> localAssets) {
@@ -364,8 +334,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
..addColumns([assetId]) ..addColumns([assetId])
..groupBy( ..groupBy(
[assetId], [assetId],
having: _db.localAlbumAssetEntity.albumId.count().equals(1) & having: _db.localAlbumAssetEntity.albumId.count().equals(1) & _db.localAlbumAssetEntity.albumId.equals(albumId),
_db.localAlbumAssetEntity.albumId.equals(albumId),
); );
return query.map((row) => row.read(assetId)!).get(); return query.map((row) => row.read(assetId)!).get();
@@ -392,9 +361,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
..orderBy([OrderingTerm.asc(_db.localAssetEntity.id)]) ..orderBy([OrderingTerm.asc(_db.localAssetEntity.id)])
..limit(1); ..limit(1);
final results = await query final results = await query.map((row) => row.readTable(_db.localAssetEntity).toDto()).get();
.map((row) => row.readTable(_db.localAssetEntity).toDto())
.get();
return results.isNotEmpty ? results.first : null; return results.isNotEmpty ? results.first : null;
} }

View File

@@ -10,9 +10,7 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository {
const DriftLocalAssetRepository(this._db) : super(_db); const DriftLocalAssetRepository(this._db) : super(_db);
Stream<LocalAsset?> watchAsset(String id) { Stream<LocalAsset?> watchAsset(String id) {
final query = _db.localAssetEntity final query = _db.localAssetEntity.select().addColumns([_db.remoteAssetEntity.id]).join([
.select()
.addColumns([_db.remoteAssetEntity.id]).join([
leftOuterJoin( leftOuterJoin(
_db.remoteAssetEntity, _db.remoteAssetEntity,
_db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum), _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum),
@@ -58,8 +56,7 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository {
} }
Future<LocalAsset?> getById(String id) { Future<LocalAsset?> getById(String id) {
final query = _db.localAssetEntity.select() final query = _db.localAssetEntity.select()..where((lae) => lae.id.equals(id));
..where((lae) => lae.id.equals(id));
return query.map((row) => row.toDto()).getSingleOrNull(); return query.map((row) => row.toDto()).getSingleOrNull();
} }
@@ -69,8 +66,6 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository {
} }
Future<int> getHashedCount() { Future<int> getHashedCount() {
return _db.managers.localAssetEntity return _db.managers.localAssetEntity.filter((e) => e.checksum.isNull().not()).count();
.filter((e) => e.checksum.isNull().not())
.count();
} }
} }

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