diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 6bb853b994..e8fc6cbafc 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,24 +1,21 @@ name: Report a bug -description: Let us know if something's not working the way you expected. +description: For regressions only (things that were working earlier) labels: [] body: - type: markdown attributes: value: | - Before opening a new bug report, please ensure - 1. you are on the latest version (it might've already been fixed), - 2. you've searched for existing issues (please add your observations as a comment there instead of creating a duplicate). - - If you are self hosting, please create a community [Q&A](https://github.com/ente-io/ente/discussions/categories/q-a) instead. + Before opening a new issue, **please** ensure + 1. You are on the latest version, + 2. You've searched for existing issues, + 3. It was working earlier (otherwise use [this](https://github.com/ente-io/ente/discussions/categories/enhancements)) + 4. It is not about self hosting (otherwise use [this](https://github.com/ente-io/ente/discussions/categories/q-a)) - type: textarea attributes: label: Description description: > - Please describe the bug. If possible, also include the steps to - reproduce the behaviour, and the expected behaviour (sometimes - bugs are just expectation mismatches, in which case this would be - a good fit for [feature - requests](https://github.com/ente-io/ente/discussions/categories/feature-requests)). + Describe the bug and steps to reproduce the behaviour, and how it + differs from the previously working behaviour. validations: required: true - type: input @@ -30,15 +27,12 @@ body: attributes: label: Last working version description: > - The version where the feature was last known to be working. It is - fine if you don't remember the exact version (mention roughly - then), but if there just isn't a last known working version, then - it is likely that what is being reported is not an issue but a - feature request. The difference between the two categories is not - just semantic - feature requests use GitHub discussions and so can - be [upvoted by the - community](https://github.com/ente-io/ente/discussions/categories/feature-requests) - (issues can't be). + The version where things were last known to be working. It is fine + if you don't remember the exact version (mention roughly then), + but **if there just isn't a last working version, then please file + it as an + [enhancement](https://github.com/ente-io/ente/discussions/categories/enhancements))** + (where the community upvotes can be used to help prioritize). placeholder: e.g. v1.2.3 - type: dropdown attributes: diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 4fae579410..cc9ab42e35 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: true contact_links: - - name: Feature requests and questions + - name: Enhacements, feature requests, feedback and questions url: https://github.com/ente-io/ente/discussions about: Please use Discussions for everything apart from the above. diff --git a/.github/workflows/auth-release.yml b/.github/workflows/auth-release.yml index 9a251fe0d4..97d079a681 100644 --- a/.github/workflows/auth-release.yml +++ b/.github/workflows/auth-release.yml @@ -141,6 +141,7 @@ jobs: build-windows: runs-on: windows-latest + environment: "auth-win-build" defaults: run: @@ -174,14 +175,22 @@ jobs: - name: Retain Windows EXE and DLLs run: cp -r build/windows/x64/runner/Release ente-${{ github.ref_name }}-windows - - name: Code sign Windows installer and EXE - uses: dlemstra/code-sign-action@v1 + - name: Sign files with Trusted Signing + uses: azure/trusted-signing-action@v0 with: - certificate: "${{ secrets.WINDOWS_CERTIFICATE }}" - password: "${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}" - files: | - auth/artifacts/ente-${{ github.ref_name }}-installer.exe - auth/ente-${{ github.ref_name }}-windows/auth.exe + azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }} + azure-client-id: ${{ secrets.AZURE_CLIENT_ID }} + azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }} + endpoint: ${{ secrets.AZURE_ENDPOINT }} + trusted-signing-account-name: ${{ secrets.AZURE_CODE_SIGNING_NAME }} + certificate-profile-name: ${{ secrets.AZURE_CERT_PROFILE_NAME }} + files: | + ${{ github.workspace }}/auth/artifacts/ente-${{ github.ref_name }}-installer.exe + ${{ github.workspace }}/auth/ente-${{ github.ref_name }}-windows/auth.exe + file-digest: SHA256 + timestamp-rfc3161: http://timestamp.acs.microsoft.com + timestamp-digest: SHA256 + - name: Zip Windows EXE and DLLs run: tar.exe -a -c -f artifacts/ente-${{ github.ref_name }}-windows.zip ente-${{ github.ref_name }}-windows diff --git a/.github/workflows/auth-win-sign.yml b/.github/workflows/auth-win-sign.yml new file mode 100644 index 0000000000..860cde2ca2 --- /dev/null +++ b/.github/workflows/auth-win-sign.yml @@ -0,0 +1,70 @@ +name: "Windows build & Sign (auth)" + + +on: + workflow_dispatch: # Allow manually running the action + +env: + FLUTTER_VERSION: "3.24.3" + +permissions: + contents: write + +jobs: + build-windows: + runs-on: windows-latest + environment: "auth-win-build" + + defaults: + run: + working-directory: auth + + steps: + - name: Checkout code and submodules + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Flutter ${{ env.FLUTTER_VERSION }} + uses: subosito/flutter-action@v2 + with: + channel: "stable" + flutter-version: ${{ env.FLUTTER_VERSION }} + cache: true + + - name: Create artifacts directory + run: mkdir artifacts + + - name: Build Windows installer + run: | + flutter config --enable-windows-desktop + # dart pub global activate flutter_distributor + dart pub global activate --source git https://github.com/ente-io/flutter_distributor_fork --git-ref develop --git-path packages/flutter_distributor + make innoinstall + flutter_distributor package --platform=windows --targets=exe --skip-clean + mv dist/**/*-windows-setup.exe artifacts/ente-${{ github.ref_name }}-installer.exe + + - name: Retain Windows EXE and DLLs + run: cp -r build/windows/x64/runner/Release ente-${{ github.ref_name }}-windows + + - name: Sign files with Trusted Signing + uses: azure/trusted-signing-action@v0 + with: + azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }} + azure-client-id: ${{ secrets.AZURE_CLIENT_ID }} + azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }} + endpoint: ${{ secrets.AZURE_ENDPOINT }} + trusted-signing-account-name: ${{ secrets.AZURE_CODE_SIGNING_NAME }} + certificate-profile-name: ${{ secrets.AZURE_CERT_PROFILE_NAME }} + files: | + ${{ github.workspace }}/auth/artifacts/ente-${{ github.ref_name }}-installer.exe + ${{ github.workspace }}/auth/ente-${{ github.ref_name }}-windows/auth.exe + file-digest: SHA256 + timestamp-rfc3161: http://timestamp.acs.microsoft.com + timestamp-digest: SHA256 + + - name: Zip Windows EXE and DLLs + run: tar.exe -a -c -f artifacts/ente-${{ github.ref_name }}-windows.zip ente-${{ github.ref_name }}-windows + + - name: Generate checksums + run: sha256sum artifacts/ente-* > artifacts/sha256sum-windows diff --git a/.github/workflows/docs-lint.yml b/.github/workflows/docs-lint.yml new file mode 100644 index 0000000000..f227f2115b --- /dev/null +++ b/.github/workflows/docs-lint.yml @@ -0,0 +1,32 @@ +name: "Lint (docs)" + +on: + # Run on every pull request (open or push to it) that changes docs/ + pull_request: + paths: + - "docs/**" + - ".github/workflows/docs-lint.yml" + +permissions: + contents: read + +jobs: + lint: + runs-on: ubuntu-latest + defaults: + run: + working-directory: docs + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup node and enable yarn caching + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: "yarn" + cache-dependency-path: "web/yarn.lock" + + - run: yarn install + + - run: yarn pretty:check diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 80e6424187..242cc2b65c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,7 +23,7 @@ Just hang around, enjoy the vibe. Answer someone's query on our [Discord](https://discord.gg/z2YVKkycX3), or pile on in the sporadic #off-topic rants there. Chuckle (or wince!) at our [Twitter](https://twitter.com/enteio) memes. Suggest a new feature in our [Github -Discussions](https://github.com/ente-io/ente/discussions/new?category=feature-requests), +Discussions](https://github.com/ente-io/ente/discussions/new?category=enhancements), or upvote the existing ones that you feel we should focus on first. Provide your opinion on existing threads. @@ -68,8 +68,8 @@ best to start small. Consider some well-scoped changes, say like adding more Each of the individual product/platform specific directories in this repository have instructions on setting up a dev environment. -For anything beyond trivial bug fixes, please use [features requests and -discussions](https://github.com/ente-io/ente/discussions) instead of performing +For anything beyond trivial bug fixes, please use +[discussions](https://github.com/ente-io/ente/discussions) instead of performing code changes directly. > [!TIP] diff --git a/auth/assets/custom-icons/_data/custom-icons.json b/auth/assets/custom-icons/_data/custom-icons.json index 3a7d283f6c..1e57c2a61c 100644 --- a/auth/assets/custom-icons/_data/custom-icons.json +++ b/auth/assets/custom-icons/_data/custom-icons.json @@ -39,6 +39,13 @@ "title": "Ankama", "slug": "ankama" }, + { + "title": "Ankara University", + "slug": "ankara_university", + "altNames": [ + "Ankara Üniversitesi" + ] + }, { "title": "Anycoin Direct", "slug": "anycoindirect" @@ -200,7 +207,9 @@ { "title": "bonify", "slug": "bonify", - "altNames": ["bonify.de"] + "altNames": [ + "bonify.de" + ] }, { "title": "Booking", @@ -304,6 +313,15 @@ { "title": "CSAM" }, + { + "title": "CSSBuy", + "slug": "cssbuy", + "altNames": [ + "CSS Buy", + "CSS-Buy", + "cssbuy.com" + ] + }, { "title": "CSFloat" }, @@ -464,6 +482,16 @@ "title": "FreeTaxUSA", "slug": "freetaxusa" }, + { + "title": "FZJ", + "slug": "fzj", + "hex": "023d6b", + "altNames": [ + "Forschungszentrum Jülich", + "FZJ IdP", + "iffLogin" + ] + }, { "title": "G2A" }, @@ -471,6 +499,9 @@ "title": "Gate.io", "slug": "gateio.svg" }, + { + "title": "GERID" + }, { "title": "GitHub" }, @@ -539,6 +570,14 @@ "Hugging Face" ] }, + { + "title": "IBKR", + "slug": "ibkr", + "altNames": [ + "Interactive Brokers", + "IB" + ] + }, { "title": "IceDrive", "slug": "ice_drive" @@ -660,6 +699,10 @@ "飞书" ] }, + { + "title": "LaunchDarkly", + "hex": "858585" + }, { "title": "Letterboxd" }, @@ -725,8 +768,11 @@ ] }, { - "title": "Mercado Livre", - "slug": "mercado_livre", + "title": "Memed" + }, + { + "title": "Mercado Libre", + "slug": "mercado_libre", "altNames": [ "Mercado Libre", "MercadoLibre", @@ -1006,6 +1052,14 @@ "qiniu" ] }, + { + "title": "R10.net", + "slug": "r10", + "altNames": [ + "R10", + "r10.net" + ] + }, { "title": "Raindrop.io", "slug": "raindrop_io", @@ -1090,6 +1144,16 @@ "title": "Seafile", "slug": "seafile" }, + { + "title": "SEI", + "altNames": [ + "sei", + "sei!", + "SEI!", + "Sistema Eletrônico de Informações", + "SEI/SEDE" + ] + }, { "title": "Sendgrid" }, @@ -1292,6 +1356,14 @@ "title": "US Mobile", "slug": "us_mobile" }, + { + "title": "uollet", + "slug": "uollet", + "altNames": [ + "UOLLET", + "uollet.com.br" + ] + }, { "title": "Vikunja" }, @@ -1377,6 +1449,37 @@ }, { "title": "CoinSpot" + }, + { + "title": "Aternos", + "slug": "aternos" + }, + { + "title": "Toshl Finance", + "slug": "toshl_finance", + "altNames": [ + "Toshl" + ] + }, + { + "title": "Tebex", + "slug": "tebex", + "altNames": [ + "tebex", + "tebex.io", + "buycraft" + ] + }, + { + "title": "xAI", + "slug": "xai" + }, + { + "title": "Cronometer", + "slug": "cronometer" + }, + { + "title": "Zitadel" } ] -} \ No newline at end of file +} diff --git a/auth/assets/custom-icons/icons/ankara_university.svg b/auth/assets/custom-icons/icons/ankara_university.svg new file mode 100644 index 0000000000..2108a14a66 --- /dev/null +++ b/auth/assets/custom-icons/icons/ankara_university.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/auth/assets/custom-icons/icons/aternos.svg b/auth/assets/custom-icons/icons/aternos.svg new file mode 100644 index 0000000000..8f5c5ddbc0 --- /dev/null +++ b/auth/assets/custom-icons/icons/aternos.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/auth/assets/custom-icons/icons/cronometer.svg b/auth/assets/custom-icons/icons/cronometer.svg new file mode 100644 index 0000000000..9037cc8e50 --- /dev/null +++ b/auth/assets/custom-icons/icons/cronometer.svg @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/auth/assets/custom-icons/icons/cssbuy.svg b/auth/assets/custom-icons/icons/cssbuy.svg new file mode 100644 index 0000000000..62aeeb7eed --- /dev/null +++ b/auth/assets/custom-icons/icons/cssbuy.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/auth/assets/custom-icons/icons/fzj.svg b/auth/assets/custom-icons/icons/fzj.svg new file mode 100644 index 0000000000..c2fb55c7c7 --- /dev/null +++ b/auth/assets/custom-icons/icons/fzj.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/auth/assets/custom-icons/icons/gerid.svg b/auth/assets/custom-icons/icons/gerid.svg new file mode 100644 index 0000000000..c1f9593174 --- /dev/null +++ b/auth/assets/custom-icons/icons/gerid.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/auth/assets/custom-icons/icons/ibkr.svg b/auth/assets/custom-icons/icons/ibkr.svg new file mode 100644 index 0000000000..3b725352f2 --- /dev/null +++ b/auth/assets/custom-icons/icons/ibkr.svg @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/auth/assets/custom-icons/icons/launchdarkly.svg b/auth/assets/custom-icons/icons/launchdarkly.svg new file mode 100644 index 0000000000..59f8d0f5e9 --- /dev/null +++ b/auth/assets/custom-icons/icons/launchdarkly.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/auth/assets/custom-icons/icons/memed.svg b/auth/assets/custom-icons/icons/memed.svg new file mode 100644 index 0000000000..9c0bd694f0 --- /dev/null +++ b/auth/assets/custom-icons/icons/memed.svg @@ -0,0 +1,47 @@ + + + + diff --git a/auth/assets/custom-icons/icons/mercado_livre.svg b/auth/assets/custom-icons/icons/mercado_libre.svg similarity index 100% rename from auth/assets/custom-icons/icons/mercado_livre.svg rename to auth/assets/custom-icons/icons/mercado_libre.svg diff --git a/auth/assets/custom-icons/icons/r10.svg b/auth/assets/custom-icons/icons/r10.svg new file mode 100644 index 0000000000..5be8bf4800 --- /dev/null +++ b/auth/assets/custom-icons/icons/r10.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/auth/assets/custom-icons/icons/sei.svg b/auth/assets/custom-icons/icons/sei.svg new file mode 100644 index 0000000000..5172e8e3e0 --- /dev/null +++ b/auth/assets/custom-icons/icons/sei.svg @@ -0,0 +1,3 @@ + + + diff --git a/auth/assets/custom-icons/icons/tebex.svg b/auth/assets/custom-icons/icons/tebex.svg new file mode 100644 index 0000000000..b7ec26fae5 --- /dev/null +++ b/auth/assets/custom-icons/icons/tebex.svg @@ -0,0 +1,19 @@ + + vikunja + + + + + + + + + + + + + + \ No newline at end of file diff --git a/auth/assets/custom-icons/icons/toshl_finance.svg b/auth/assets/custom-icons/icons/toshl_finance.svg new file mode 100644 index 0000000000..64e90dc34c --- /dev/null +++ b/auth/assets/custom-icons/icons/toshl_finance.svg @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/auth/assets/custom-icons/icons/uollet.svg b/auth/assets/custom-icons/icons/uollet.svg new file mode 100644 index 0000000000..c767077239 --- /dev/null +++ b/auth/assets/custom-icons/icons/uollet.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/auth/assets/custom-icons/icons/xai.svg b/auth/assets/custom-icons/icons/xai.svg new file mode 100644 index 0000000000..59246d5b24 --- /dev/null +++ b/auth/assets/custom-icons/icons/xai.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + diff --git a/auth/assets/custom-icons/icons/zitadel.svg b/auth/assets/custom-icons/icons/zitadel.svg new file mode 100644 index 0000000000..df44ec5398 --- /dev/null +++ b/auth/assets/custom-icons/icons/zitadel.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/auth/lib/core/configuration.dart b/auth/lib/core/configuration.dart index 7264ff6863..7ba6fa4922 100644 --- a/auth/lib/core/configuration.dart +++ b/auth/lib/core/configuration.dart @@ -14,7 +14,6 @@ import 'package:ente_auth/models/key_gen_result.dart'; import 'package:ente_auth/models/private_key_attributes.dart'; import 'package:ente_auth/store/authenticator_db.dart'; import 'package:ente_auth/utils/directory_utils.dart'; -import 'package:ente_auth/utils/lock_screen_settings.dart'; import 'package:ente_crypto_dart/ente_crypto_dart.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:logging/logging.dart'; @@ -33,7 +32,6 @@ class Configuration { static const emailKey = "email"; static const keyAttributesKey = "key_attributes"; - static const keyShouldShowLockScreen = "should_show_lock_screen"; static const lastTempFolderClearTimeKey = "last_temp_folder_clear_time"; static const keyKey = "key"; static const secretKeyKey = "secret_key"; @@ -133,7 +131,6 @@ class Configuration { key: key, ); } - await LockScreenSettings.instance.removePinAndPassword(); await AuthenticatorDB.instance.clearTable(); _key = null; _cachedToken = null; @@ -468,24 +465,6 @@ class Configuration { await _preferences.setBool(hasOptedForOfflineModeKey, true); } - Future shouldShowLockScreen() async { - final bool isPin = await LockScreenSettings.instance.isPinSet(); - final bool isPass = await LockScreenSettings.instance.isPasswordSet(); - return isPin || isPass || shouldShowSystemLockScreen(); - } - - bool shouldShowSystemLockScreen() { - if (_preferences.containsKey(keyShouldShowLockScreen)) { - return _preferences.getBool(keyShouldShowLockScreen)!; - } else { - return false; - } - } - - Future setSystemLockScreen(bool value) { - return _preferences.setBool(keyShouldShowLockScreen, value); - } - void setVolatilePassword(String volatilePassword) { _volatilePassword = volatilePassword; } diff --git a/auth/lib/core/constants.dart b/auth/lib/core/constants.dart index b58d7dce61..44af78c841 100644 --- a/auth/lib/core/constants.dart +++ b/auth/lib/core/constants.dart @@ -11,7 +11,7 @@ const String roadmapURL = "https://roadmap.ente.io"; const String kAccountsUrl = "https://accounts.ente.io"; const String githubFeatureRequestUrl = - "https://github.com/ente-io/ente/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+requests%22+label%3A%22-+auth%22+sort%3Atop"; + "https://github.com/ente-io/ente/discussions/categories/enhancements?discussions_q=is%3Aopen%+label%3A%22-+auth%22+sort%3Atop"; const int microSecondsInDay = 86400000000; const int android11SDKINT = 30; const int galleryLoadStartTime = -8000000000000000; // Wednesday, March 6, 1748 diff --git a/auth/lib/gateway/authenticator.dart b/auth/lib/gateway/authenticator.dart index 3f3c7c8974..1375146e48 100644 --- a/auth/lib/gateway/authenticator.dart +++ b/auth/lib/gateway/authenticator.dart @@ -73,7 +73,10 @@ class AuthenticatorGateway { ); } - Future> getDiff(int sinceTime, {int limit = 500}) async { + Future<(List, int?)> getDiff( + int sinceTime, { + int limit = 500, + }) async { try { final response = await _enteDio.get( "/authenticator/entity/diff", @@ -84,11 +87,12 @@ class AuthenticatorGateway { ); final List authEntities = []; final diff = response.data["diff"] as List; + final int? unixTimeInMicroSeconds = response.data["timestamp"] as int?; for (var entry in diff) { final AuthEntity entity = AuthEntity.fromMap(entry); authEntities.add(entity); } - return authEntities; + return (authEntities, unixTimeInMicroSeconds); } catch (e) { if (e is DioException && e.response?.statusCode == 401) { throw UnauthorizedError(); diff --git a/auth/lib/l10n/arb/app_ar.arb b/auth/lib/l10n/arb/app_ar.arb index 0a5456aa22..7872963dd8 100644 --- a/auth/lib/l10n/arb/app_ar.arb +++ b/auth/lib/l10n/arb/app_ar.arb @@ -173,6 +173,7 @@ "invalidQRCode": "شيفرة استجابة سريعة غير صالحة", "noRecoveryKeyTitle": "لا يوجد مفتاح استرجاع؟", "enterEmailHint": "أدخل عنوان البريد الإلكتروني الخاص بك", + "enterNewEmailHint": "أدخل عنوان بريدك الإلكتروني الجديد", "invalidEmailTitle": "عنوان البريد الإلكتروني غير صالح", "invalidEmailMessage": "الرجاء إدخال بريد إلكتروني صالح.", "deleteAccount": "إزالة الحساب", diff --git a/auth/lib/l10n/arb/app_be.arb b/auth/lib/l10n/arb/app_be.arb index 1f0cf8b089..8323190ec7 100644 --- a/auth/lib/l10n/arb/app_be.arb +++ b/auth/lib/l10n/arb/app_be.arb @@ -8,7 +8,7 @@ }, "onBoardingBody": "Бяспечна зрабіць рэзервовую копію кодаў 2ФА", "onBoardingGetStarted": "Пачаць", - "setupFirstAccount": "Наладзіць ваш першы ўліковы запіс", + "setupFirstAccount": "Наладзіць свой першы ўліковы запіс", "importScanQrCode": "Сканіраваць код QR-код", "qrCode": "QR-код", "importEnterSetupKey": "Увесці ключ наладжвання", @@ -45,19 +45,38 @@ "timeBasedKeyType": "Заснаваныя на часе (TOTP)", "counterBasedKeyType": "Заснаваныя на лічыльніку (HOTP)", "saveAction": "Захаваць", - "nextTotpTitle": "наступны", + "nextTotpTitle": "далей", "deleteCodeTitle": "Выдаліць код?", "deleteCodeMessage": "Вы сапраўды хочаце выдаліць гэты код? Гэта дзеянне з'яўляецца незваротным.", "trashCode": "Выдаліць код?", "trashCodeMessage": "Вы сапраўды хочаце выдаліць код для {account}?", "trash": "Сметніца", - "viewLogsAction": "Паглядзець журнал", - "preparingLogsTitle": "Падрыхтоўка журнала...", + "viewLogsAction": "Паглядзець журналы", + "preparingLogsTitle": "Падрыхтоўка журналаў...", "emailLogsTitle": "Адправіць журнал па электроннай пошце", - "exportLogsAction": "Экспартаваць журнал", - "reportABug": "Паведаміць пра памылку", - "reportBug": "Паведаміць пра памылку", + "emailLogsMessage": "Адпраўце журналы на {email}", + "@emailLogsMessage": { + "placeholders": { + "email": { + "type": "String" + } + } + }, + "copyEmailAction": "Скапіяваць электронную пошту", + "exportLogsAction": "Экспартаваць журналы", + "reportABug": "Паведаміць аб памылцы", + "crashAndErrorReporting": "Справаздачы аб збоях і памылках", + "reportBug": "Паведаміць аб памылцы", + "emailUsMessage": "Адпраўце нам ліст на {email}", + "@emailUsMessage": { + "placeholders": { + "email": { + "type": "String" + } + } + }, "contactSupport": "Звярнуцца ў службу падтрымкі", + "rateUsOnStore": "Ацаніць нас у {storeName}", "blog": "Блог", "verifyPassword": "Праверыць пароль", "pleaseWait": "Пачакайце...", @@ -66,32 +85,184 @@ "useRecoveryKey": "Выкарыстоўваць ключ аднаўлення", "incorrectPasswordTitle": "Няправільны пароль", "welcomeBack": "З вяртаннем!", + "changeEmail": "Змяніць адрас электроннай пошты", "changePassword": "Змяніць пароль", "data": "Даныя", "importCodes": "Імпартаваць коды", + "importTypePlainText": "Звычайны тэкст", + "importTypeEnteEncrypted": "Шыфраванне экспартавання з Ente", + "passwordForDecryptingExport": "Пароль для дэшыфроўкі экспартавання", "passwordEmptyError": "Пароль не можа быць пустым", "importFromApp": "Імпартаваць коды з {appName}", "exportCodes": "Экспартаваць коды", "importLabel": "Імпарт", "selectFile": "Выбраць файл", + "ok": "OK", + "cancel": "Скасаваць", "yes": "Так", "no": "Не", "email": "Электронная пошта", "support": "Падтрымка", + "general": "Агульныя", "settings": "Налады", + "copied": "Скапіявана", "pleaseTryAgain": "Калі ласка, паспрабуйце яшчэ раз", + "existingUser": "Існуючы карыстальнік", + "newUser": "Навічок у Ente", "delete": "Выдаліць", "enterYourPasswordHint": "Увядзіце ваш пароль", + "forgotPassword": "Забылі пароль", + "oops": "Вой", "faq": "Частыя пытанні", + "leaveFamily": "Пакінуць сямейны план", + "scan": "Сканіраваць", + "scanACode": "Сканіраваць код", + "verify": "Праверыць", + "verifyEmail": "Праверыць электронную пошту", + "lostDeviceTitle": "Згубілі прыладу?", + "verifyPasskey": "Праверыць ключ доступу", + "loginWithTOTP": "Увайсці з TOTP", + "recoverAccount": "Аднавіць уліковы запіс", + "recover": "Аднавіць", + "invalidQRCode": "Памылковы QR-код", "deleteAccount": "Выдаліць уліковы запіс", "noDeleteAccountAction": "Не, выдаліць уліковы запіс", "sendEmail": "Адправіць ліст", "createNewAccount": "Стварыць новы ўліковы запіс", + "weakStrength": "Ненадзейны", + "strongStrength": "Надзейны", + "moderateStrength": "Умераная", "confirmPassword": "Пацвердзіць пароль", "close": "Закрыць", "oopsSomethingWentWrong": "Штосьці пайшло не так.", + "selectLanguage": "Выберыце мову", "language": "Мова", + "social": "Сацыяльныя сеткі", "security": "Бяспека", + "lockscreen": "Экран блакіроўкі", "searchHint": "Пошук...", - "search": "Пошук" + "search": "Пошук", + "noResult": "Няма вынікаў", + "addCode": "Дадаць код", + "scanAQrCode": "Сканіраваць QR-код", + "edit": "Рэдагаваць", + "share": "Абагуліць", + "shareCodes": "Абагуліць коды", + "restore": "Аднавіць", + "error": "Памылка", + "doThisLater": "Зрабіць гэта пазней", + "saveKey": "Захаваць ключ", + "save": "Захаваць", + "send": "Адправіць", + "back": "Назад", + "createAccount": "Стварыць уліковы запіс", + "password": "Пароль", + "privacyPolicyTitle": "Палітыка прыватнасці", + "termsOfServicesTitle": "Умовы", + "encryption": "Шыфраванне", + "setPasswordTitle": "Задаць пароль", + "changePasswordTitle": "Змяніць пароль", + "resetPasswordTitle": "Скінуць пароль", + "encryptionKeys": "Ключы шыфравання", + "continueLabel": "Працягнуць", + "insecureDevice": "Небяспечная прылада", + "howItWorks": "Як гэта працуе", + "logInLabel": "Увайсці", + "logout": "Выйсці", + "yesLogout": "Так, выйсці", + "exit": "Выхад", + "theme": "Тема", + "lightTheme": "Светлая", + "darkTheme": "Цёмная", + "systemTheme": "Сістэманая", + "invalidKey": "Памылковы ключ", + "tryAgain": "Паспрабуйце яшчэ раз", + "confirm": "Пацвердзіць", + "emailYourLogs": "Адправіць журналы", + "exportLogs": "Экспартаваць журналы", + "about": "Аб праграме", + "privacy": "Прыватнасць", + "terms": "Умовы", + "checkStatus": "Праверыць статус", + "downloadUpdate": "Спампаваць", + "update": "Абнавіць", + "checking": "Праверка...", + "warning": "Папярэджанне", + "iUnderStand": "Ясна", + "@iUnderStand": { + "description": "Text for the button to confirm the user understands the warning" + }, + "importSuccessTitle": "Ура!", + "sorry": "Прабачце", + "pendingSyncs": "Папярэджанне", + "resendEmail": "Адправіць ліст яшчэ раз", + "manualSort": "Карыстальніцкая", + "editOrder": "Рэдагаваць заказ", + "mostFrequentlyUsed": "Часта выкарыстоўваюцца", + "mostRecentlyUsed": "Нядаўна выкарыстаныя", + "activeSessions": "Актыўныя сеансы", + "terminate": "Перарваць", + "thisDevice": "Гэта прылада", + "incorrectCode": "Няправільны код", + "enterPassword": "Увядзіце пароль", + "encrypted": "Зашыфравана", + "plainText": "Звычайны тэкст", + "export": "Экспартаваць", + "singIn": "Увайсці", + "compactMode": "Кампактны рэжым", + "shouldHideCode": "Схаваць коды", + "androidBiometricHint": "Праверыць ідэнтыфікацыю", + "@androidBiometricHint": { + "description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters." + }, + "androidBiometricSuccess": "Паспяхова", + "@androidBiometricSuccess": { + "description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters." + }, + "androidCancelButton": "Скасаваць", + "@androidCancelButton": { + "description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters." + }, + "goToSettings": "Перайсці ў налады", + "@goToSettings": { + "description": "Message showed on a button that the user can click to go to settings pages from the current dialog. It is used on both Android and iOS side. Maximum 30 characters." + }, + "iOSOkButton": "OK", + "@iOSOkButton": { + "description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters." + }, + "doNotSignOut": "Не выходзіць", + "passkey": "Ключ доступу", + "loginSessionExpired": "Сеанс завяршыўся", + "pinText": "Замацаваць", + "unpinText": "Адмацаваць", + "pinned": "Замацавана", + "tags": "Тэгі", + "createNewTag": "Стварыць новы тэг", + "tag": "Тэг", + "create": "Стварыць", + "editTag": "Рэдагаванне тэг", + "deleteTagTitle": "Выдаліць тэг?", + "viewRawCodes": "Паглядзець неапрацаваныя коды", + "rawCodes": "Неапрацаваныя коды", + "rawCodeData": "Неапрацаваныя даныя кода", + "appLock": "Блакіроўка праграмы", + "autoLock": "Аўтаблакіроўка", + "immediately": "Адразу", + "reEnterPin": "Увядзіце PIN-код яшчэ раз", + "next": "Далей", + "tapToUnlock": "Націсніце для разблакіроўкі", + "deviceLock": "Блакіроўка прылады", + "hideContent": "Схаваць змест", + "pinLock": "Блакіроўка PIN'ам", + "enterPin": "Увядзіце PIN-код", + "setNewPin": "Задаць новы PIN", + "deselectAll": "Зняць выбар з усіх", + "selectAll": "Выбраць усе", + "plainHTML": "Звычайны HTML", + "advanced": "Пашыраныя", + "algorithm": "Алгарытм", + "type": "Тып", + "period": "Перыяд", + "digits": "Лічбы" } \ No newline at end of file diff --git a/auth/lib/l10n/arb/app_id.arb b/auth/lib/l10n/arb/app_id.arb index c791a866a9..b5e2605a3f 100644 --- a/auth/lib/l10n/arb/app_id.arb +++ b/auth/lib/l10n/arb/app_id.arb @@ -88,6 +88,8 @@ "useRecoveryKey": "Gunakan kunci pemulihan", "incorrectPasswordTitle": "Kata sandi salah", "welcomeBack": "Selamat datang kembali!", + "emailAlreadyRegistered": "Email sudah terdaftar.", + "emailNotRegistered": "Email belum terdaftar.", "madeWithLoveAtPrefix": "dibuat dengan ❤️ di ", "supportDevs": "Berlangganan ente untuk mendukung kami", "supportDiscount": "Gunakan kode kupon \"AUTH\" untuk mendapatkan potongan 10% untuk tahun pertama", @@ -171,6 +173,7 @@ "invalidQRCode": "Kode QR tidak valid", "noRecoveryKeyTitle": "Tidak punya kunci pemulihan?", "enterEmailHint": "Masukkan alamat email Anda", + "enterNewEmailHint": "Masukkan alamat email baru anda", "invalidEmailTitle": "Alamat email tidak valid", "invalidEmailMessage": "Harap masukkan alamat email yang valid.", "deleteAccount": "Hapus akun", @@ -501,5 +504,12 @@ "deselectAll": "Batalkan semua pilihan", "selectAll": "Pilih semua", "deleteDuplicates": "Hapus duplikat", - "plainHTML": "HTML Sederhana" + "plainHTML": "HTML Sederhana", + "tellUsWhatYouThink": "Berikan pendapatmu", + "dropReviewAndroid": "Berikan ulasan di Play Store", + "advanced": "Lanjutan", + "algorithm": "Algoritma", + "type": "Tipe", + "period": "Periode", + "digits": "Digit" } \ No newline at end of file diff --git a/auth/lib/l10n/arb/app_ku.arb b/auth/lib/l10n/arb/app_ku.arb new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/auth/lib/l10n/arb/app_ku.arb @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/auth/lib/l10n/arb/app_sr.arb b/auth/lib/l10n/arb/app_sr.arb new file mode 100644 index 0000000000..dc461d9e89 --- /dev/null +++ b/auth/lib/l10n/arb/app_sr.arb @@ -0,0 +1,523 @@ +{ + "account": "Налог", + "unlock": "Откључај", + "recoveryKey": "Резервни Кључ", + "counterAppBarTitle": "Бројач", + "@counterAppBarTitle": { + "description": "Text shown in the AppBar of the Counter Page" + }, + "onBoardingBody": "Сигурносно правити копију 2ФА кôдова", + "onBoardingGetStarted": "Почети", + "setupFirstAccount": "Подесити свој први налог", + "importScanQrCode": "Скенирај QR кôд", + "qrCode": "QR кôд", + "importEnterSetupKey": "Унети кључ за подешавање", + "importAccountPageTitle": "Унети детаље налога", + "secretCanNotBeEmpty": "Тајна не може бити празна", + "bothIssuerAndAccountCanNotBeEmpty": "И издавалац и рачун не могу бити празни", + "incorrectDetails": "Погрешни детаљи", + "pleaseVerifyDetails": "Проверите детаље и покушајте поново", + "codeIssuerHint": "Издавач", + "codeSecretKeyHint": "Тајни кључ", + "secret": "Тајна", + "all": "Све", + "notes": "Белешке", + "notesLengthLimit": "Белешке могу имати највише {count} знакова", + "@notesLengthLimit": { + "description": "Text to indicate the maximum number of characters allowed for notes", + "placeholders": { + "count": { + "description": "The maximum number of characters allowed for notes", + "type": "int", + "example": "100" + } + } + }, + "codeAccountHint": "Налог (you@domain.com)", + "codeTagHint": "Ознака", + "accountKeyType": "Тип кључа", + "sessionExpired": "Сесија је истекла", + "@sessionExpired": { + "description": "Title of the dialog when the users current session is invalid/expired" + }, + "pleaseLoginAgain": "Молимо да се поново пријавите", + "loggingOut": "Одјављивање...", + "timeBasedKeyType": "Временски (TOTP)", + "counterBasedKeyType": "На основу бројања (HOTP)", + "saveAction": "Сачувај", + "nextTotpTitle": "следеће", + "deleteCodeTitle": "Обрисати кôд?", + "deleteCodeMessage": "Сигурно желите да избришете овај кôд? Ова акција је неповратна.", + "trashCode": "Кôд у смеће?", + "trashCodeMessage": "Сигурно желите да поставите кôд у смеће за {account}?", + "trash": "Смеће", + "viewLogsAction": "Прегледај извештаје", + "sendLogsDescription": "Ово ће делите ваше записе како би нам помогли да вам исправимо проблем. Док преузмемо мере предострожности да осигурамо да осетљиве информације нису пријављене, охрабрујемо вас да прегледате ове записе пре него што их делите.", + "preparingLogsTitle": "Спремање извештаја...", + "emailLogsTitle": "Имејловати извештаје", + "emailLogsMessage": "Пошаљите извештаје на {email}", + "@emailLogsMessage": { + "placeholders": { + "email": { + "type": "String" + } + } + }, + "copyEmailAction": "Копирати имејл", + "exportLogsAction": "Извези изештаје", + "reportABug": "Пријави грешку", + "crashAndErrorReporting": "Пријављивање дања и грешке", + "reportBug": "Пријaви грешку", + "emailUsMessage": "Пошаљите нам имејл на {email}", + "@emailUsMessage": { + "placeholders": { + "email": { + "type": "String" + } + } + }, + "contactSupport": "Контактирати подршку", + "rateUsOnStore": "Оцените нас на {storeName}", + "blog": "Блог", + "merchandise": "Роба", + "verifyPassword": "Верификујте лозинку", + "pleaseWait": "Молимо сачекајте...", + "generatingEncryptionKeysTitle": "Генерисање кључева за шифровање...", + "recreatePassword": "Поново креирати лозинку", + "recreatePasswordMessage": "Тренутни уређај није довољно моћан да потврди вашу лозинку, тако да је морамо да регенеришемо једном на начин који ради са свим уређајима. \n\nПријавите се помоћу кључа за опоравак и обновите своју лозинку (можете поново користити исту ако желите).", + "useRecoveryKey": "Користите кључ за опоравак", + "incorrectPasswordTitle": "Неисправна лозинка", + "welcomeBack": "Добродошли назад!", + "emailAlreadyRegistered": "Имејл је већ регистрован.", + "emailNotRegistered": "Имејл није регистрован.", + "madeWithLoveAtPrefix": "урађено са ❤️ на ", + "supportDevs": "Претплатити се на ente да би нас подржали", + "supportDiscount": "Употребите купон \"AUTH\" да би добили попуст од 10% прве године", + "changeEmail": "Промени имејл", + "changePassword": "Промени лозинку", + "data": "Подаци", + "importCodes": "Увоз кôдова", + "importTypePlainText": "Обичан текст", + "importTypeEnteEncrypted": "Ente шифрован извоз", + "passwordForDecryptingExport": "Лозинка за дешифровање извоза", + "passwordEmptyError": "Лозинка не може да буде празна", + "importFromApp": "Увоз кôдова од {appName}", + "importGoogleAuthGuide": "Извезите своје рачуне од Google Authenticator на QR кôд помоћу опције \"Трансфер налоге\". Затим помоћу другог уређаја скенирајте QR кôд.\n\nСавет: можете користити веб камеру вашег лаптопа да бисте снимили слику QR кôда.", + "importSelectJsonFile": "Одабрати JSON датотеку", + "importSelectAppExport": "Одабрати извозну датотеку {appName}-а", + "importEnteEncGuide": "Одабрати шифровану извозну JSON датотеку од Ente", + "importRaivoGuide": "Употребите \"Export OTPs to Zip archive\" опцију из подешавања Raivo-а.\n\nИздвојите zip датотеку и увезите JSON датотеку.", + "importBitwardenGuide": "Употребите \"Извоз Сефа\" из Bitwarden и увезите нешифровану JSON датотеку.", + "importAegisGuide": "Употребити \"Export the vault\" из Aegis-а.\n\nАко је сеф шифрован, мораћете унети лозинку сефа да би га дешифровали.", + "import2FasGuide": "Употребити \"Settings->Backup -Export\" из 2FAS-а.\n\nАко је ваша копија шифрирана, мораћете да унесете лозинку за дешифрирање копије", + "importLastpassGuide": "Употребити \"Transfer accounts\" из Lastpass Authenticator и стисните \"Export accounts to file\". Унесите преузет JSON.", + "exportCodes": "Извоз кôдова", + "importLabel": "Увоз", + "importInstruction": "Изаберите датотеку која садржи списак ваших кôдова у следећем формату", + "importCodeDelimiterInfo": "Кôдови се могу одвојити зарезом или новом линијом", + "selectFile": "Изаберите датотеку", + "emailVerificationToggle": "Имејл провера", + "emailVerificationEnableWarning": "Да бисте избегли да се закључате са свог рачуна, обавезно чувајте копију 2ФА имејла ван Ente Auth пре него што омогућите имејл верификацију.", + "authToChangeEmailVerificationSetting": "Потврдите аутентичност да промените верификацији имејл", + "authenticateGeneric": "Молимо потврдите аутентичност", + "authToViewYourRecoveryKey": "Аутентификујте се да бисте погледали кључ за опоравак", + "authToChangeYourEmail": "Аутентификујте се да бисте променили имејл", + "authToChangeYourPassword": "Аутентификујте се да бисте променили лозинку", + "authToViewSecrets": "Аутентификујте се да бисте прегледали Ваше тајне", + "authToInitiateSignIn": "Аутентификујте се да бисте почели пријављивање за копију.", + "ok": "У реду", + "cancel": "Откажи", + "yes": "Да", + "no": "Не", + "email": "Имејл", + "support": "Подршка", + "general": "Опште", + "settings": "Подешавања", + "copied": "Копирано", + "pleaseTryAgain": "Пробајте поново", + "existingUser": "Постојећи корисник", + "newUser": "Нов у Ente", + "delete": "Обриши", + "enterYourPasswordHint": "Унесите лозинку", + "forgotPassword": "Заборавио сам лозинку", + "oops": "Упс", + "suggestFeatures": "Предложи карактеристике", + "faq": "Питања", + "somethingWentWrongMessage": "Нешто је пошло наопако, покушајте поново", + "leaveFamily": "Напусти family претплату", + "leaveFamilyMessage": "Јесте ли сигурни да желите да напустите family чланство?", + "inFamilyPlanMessage": "Имате family чланство!", + "hintForMobile": "Дуго притисните кôд за уређивање или уклањање.", + "hintForDesktop": "Десни клик на кôд за уређивање или уклањање.", + "scan": "Скенирај", + "scanACode": "Скенирај кôд", + "verify": "Верификуј", + "verifyEmail": "Потврди имејл", + "enterCodeHint": "Унесите 6-цифрени кôд из\nапликације за аутентификацију", + "lostDeviceTitle": "Узгубили сте уређај?", + "twoFactorAuthTitle": "Дво-факторска аутентификација", + "passkeyAuthTitle": "Верификација сигурносном кључем", + "verifyPasskey": "Проверите сигурносни кључ", + "loginWithTOTP": "Пријава са TOTP", + "recoverAccount": "Опоравак налога", + "enterRecoveryKeyHint": "Унети кључ за опоравак", + "recover": "Опорави", + "contactSupportViaEmailMessage": "Послати имејл на {email} са регистрованог имејла", + "@contactSupportViaEmailMessage": { + "placeholders": { + "email": { + "type": "String" + } + } + }, + "invalidQRCode": "Неважећи QR кôд", + "noRecoveryKeyTitle": "Немате кључ за опоравак?", + "enterEmailHint": "Унесите Ваш имејл", + "enterNewEmailHint": "Унесите Ваш нови имејл", + "invalidEmailTitle": "Погрешна имејл адреса", + "invalidEmailMessage": "Унесите важећи имејл.", + "deleteAccount": "Избриши налог", + "deleteAccountQuery": "Жао нам је што одлазите. Да ли се суочавате са неком грешком?", + "yesSendFeedbackAction": "Да, послати повратне информације", + "noDeleteAccountAction": "Не, избрисати налог", + "initiateAccountDeleteTitle": "Молимо вас да се аутентификујете за брисање рачуна", + "sendEmail": "Шаљи имејл", + "createNewAccount": "Креирај нови налог", + "weakStrength": "Слабо", + "strongStrength": "Јако", + "moderateStrength": "Умерено", + "confirmPassword": "Потврдите лозинку", + "close": "Затвори", + "oopsSomethingWentWrong": "Нешто није у реду.", + "selectLanguage": "Изабери језик", + "language": "Језик", + "social": "Друштвене мреже", + "security": "Безбедност", + "lockscreen": "Закључавање екрана", + "authToChangeLockscreenSetting": "Аутентификујте се да бисте променили закључавање екрана", + "deviceLockEnablePreSteps": "Да бисте омогућили закључавање уређаја, молимо вас да подесите шифру уређаја или закључавање екрана у системским подешавањима.", + "viewActiveSessions": "Видети активне сесије", + "authToViewYourActiveSessions": "Аутентификујте се да бисте преглеадали активне сесије", + "searchHint": "Претрага...", + "search": "Претрага", + "sorryUnableToGenCode": "Извините, не могу да генеришем кôд за {issuerName}", + "noResult": "Нема резултата", + "addCode": "Додај кôд", + "scanAQrCode": "Скенирај QR кôд", + "enterDetailsManually": "Ручно унети детеље", + "edit": "Уреди", + "share": "Подели", + "shareCodes": "Дели кôдове", + "shareCodesDuration": "Изаберите трајање за које желите да поделите кôдове.", + "restore": "Врати", + "copiedToClipboard": "Копирано у оставу", + "copiedNextToClipboard": "Копирали следећи кôд у остави", + "error": "Грешка", + "recoveryKeyCopiedToClipboard": "Кључ за опоравак копирано у остави", + "recoveryKeyOnForgotPassword": "Ако заборавите лозинку, једини начин на који можете повратити податке је са овим кључем.", + "recoveryKeySaveDescription": "Не чувамо овај кључ, молимо да сачувате кључ од 24 речи на сигурном месту.", + "doThisLater": "Уради то касније", + "saveKey": "Сачувај кључ", + "save": "Сачувај", + "send": "Пошаљи", + "saveOrSendDescription": "Да ли желите да ово сачувате у складиште (фасцикли за преузимање подразумевано) или да га пошаљете другим апликацијама?", + "saveOnlyDescription": "Да ли желите да ово сачувате у складиште (фасцикли за преузимање подразумевано)?", + "back": "Назад", + "createAccount": "Направи налог", + "passwordStrength": "Снага лозинке: {passwordStrengthValue}", + "@passwordStrength": { + "description": "Text to indicate the password strength", + "placeholders": { + "passwordStrengthValue": { + "description": "The strength of the password as a string", + "type": "String", + "example": "Weak or Moderate or Strong" + } + }, + "message": "Password Strength: {passwordStrengthText}" + }, + "password": "Лозинка", + "signUpTerms": "Прихватам услове сервиса и политику приватности", + "privacyPolicyTitle": "Политика приватности", + "termsOfServicesTitle": "Услови", + "encryption": "Шифровање", + "setPasswordTitle": "Постави лозинку", + "changePasswordTitle": "Промени лозинку", + "resetPasswordTitle": "Ресетуј лозинку", + "encryptionKeys": "Кључеве шифровања", + "passwordWarning": "Не чувамо ову лозинку, па ако је заборавите, не можемо дешифрирати ваше податке", + "enterPasswordToEncrypt": "Унесите лозинку за употребу за шифровање ваших података", + "enterNewPasswordToEncrypt": "Унесите нову лозинку за употребу за шифровање ваших података", + "passwordChangedSuccessfully": "Лозинка је успешно промењена", + "generatingEncryptionKeys": "Генерисање кључева за шифровање...", + "continueLabel": "Настави", + "insecureDevice": "Уређај није сигуран", + "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": "Извините, не можемо да генеришемо сигурне кључеве на овом уређају.\n\nМолимо пријавите се са другог уређаја.", + "howItWorks": "Како то функционише", + "ackPasswordLostWarning": "Разумем да ако изгубим лозинку, могу изгубити своје податке пошто су шифрирани од краја до краја.", + "loginTerms": "Кликом на пријаву, прихватам услове сервиса и политику приватности", + "logInLabel": "Пријави се", + "logout": "Одјави ме", + "areYouSureYouWantToLogout": "Да ли сте сигурни да се одјавите?", + "yesLogout": "Да, одјави ме", + "exit": "Излаз", + "theme": "Тема", + "lightTheme": "Светла", + "darkTheme": "Tamna", + "systemTheme": "Систем", + "verifyingRecoveryKey": "Провера кључа за опоравак...", + "recoveryKeyVerified": "Кључ за опоравак је проверен", + "recoveryKeySuccessBody": "Сјајно! Ваш кључ за опоравак важи. Хвала за проверу.\n\nИмајте на уму да задржите кључ за опоравак на сигрном.", + "invalidRecoveryKey": "Кључ за опоравак који сте унели није валидан. Молимо вас да будете сигурни да садржи 24 речи и проверите правопис сваког.\n\nАко сте унели старији кôд за опоравак, проверите да ли је дугачак 64 знака и проверите сваки од њих.", + "recreatePasswordTitle": "Поново креирати лозинку", + "recreatePasswordBody": "Тренутни уређај није довољно моћан да потврди вашу лозинку, али можемо регенерирати на начин који ради са свим уређајима.\n\nПријавите се помоћу кључа за опоравак и обновите своју лозинку (можете поново користити исту ако желите).", + "invalidKey": "Неисправан кључ", + "tryAgain": "Покушај поново", + "viewRecoveryKey": "Видети кључ за опоравак", + "confirmRecoveryKey": "Потврдити кључ за опоравак", + "recoveryKeyVerifyReason": "Ваш кључ за опоравак је једини начин да се врате фотографије ако заборавите лозинку. Можете пронаћи свој кључ за опоравак у Подешавања> Рачун.\n\nОвдје унесите кључ за опоравак да бисте проверили да ли сте га исправно сачували.", + "confirmYourRecoveryKey": "Потврдити кључ за опоравак", + "confirm": "Потврди", + "emailYourLogs": "Имејлирајте извештаје", + "pleaseSendTheLogsTo": "Пошаљите извештаје на \n{toEmail}", + "copyEmailAddress": "Копирати имејл адресу", + "exportLogs": "Извези изештаје", + "enterYourRecoveryKey": "Унети кључ за опоравак", + "tempErrorContactSupportIfPersists": "Изгледа да је нешто погрешно. Покушајте поново након неког времена. Ако грешка настави, обратите се нашем тиму за подршку.", + "networkHostLookUpErr": "Није могуће повезивање са Ente-ом, молимо вас да проверите мрежне поставке и контактирајте подршку ако грешка и даље постоји.", + "networkConnectionRefusedErr": "Није могуће повезивање са Ente-ом, покушајте поново мало касније. Ако грешка настави, обратите се подршци.", + "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Изгледа да је нешто погрешно. Покушајте поново након неког времена. Ако грешка настави, обратите се нашем тиму за подршку.", + "about": "О програму", + "weAreOpenSource": "Користимо отворени извор!", + "privacy": "Приватност", + "terms": "Услови", + "checkForUpdates": "Провери ажурирања", + "checkStatus": "Провери статус", + "downloadUpdate": "Преузми", + "criticalUpdateAvailable": "Критично ажурирање је доступно", + "updateAvailable": "Доступно ажурирање", + "update": "Ажурирај", + "checking": "Провера...", + "youAreOnTheLatestVersion": "Користите најновију верзију", + "warning": "Упозорење", + "exportWarningDesc": "Извозна датотека садржи осетљиве информације. Молимо вас да је чувате на сигурно.", + "iUnderStand": "Разумем", + "@iUnderStand": { + "description": "Text for the button to confirm the user understands the warning" + }, + "authToExportCodes": "Аутентификујте се да бисте извезли кôдове", + "importSuccessTitle": "Jeeee!", + "importSuccessDesc": "Увели сте {count} кôдова!", + "@importSuccessDesc": { + "placeholders": { + "count": { + "description": "The number of codes imported", + "type": "int", + "example": "1" + } + } + }, + "sorry": "Жао ми је", + "importFailureDesc": "Нисам могао да анализирам изабрану датотеку.\nПишите на support@ente.io ако вам је потребна помоћ!", + "pendingSyncs": "Упозорење", + "pendingSyncsWarningBody": "Неки од ваших кôдова нису сачувани.\n\nМолимо вас осигурајте да имате резервну копију за ове кôдове пре него што се одјавите.", + "checkInboxAndSpamFolder": "Молимо вас да проверите примљену пошту (и нежељену пошту) да бисте довршили верификацију", + "tapToEnterCode": "Пипните да бисте унели кôд", + "resendEmail": "Поново послати имејл", + "weHaveSendEmailTo": "Послали смо имејл на {email}", + "@weHaveSendEmailTo": { + "description": "Text to indicate that we have sent a mail to the user", + "placeholders": { + "email": { + "description": "The email address of the user", + "type": "String", + "example": "example@ente.io" + } + } + }, + "manualSort": "Прилагођено", + "editOrder": "Уреди поредак", + "mostFrequentlyUsed": "Често коришћено", + "mostRecentlyUsed": "Недавно коришћено", + "activeSessions": "Активне сесије", + "somethingWentWrongPleaseTryAgain": "Нешто је пошло наопако. Покушајте поново", + "thisWillLogYouOutOfThisDevice": "Ово ће вас одјавити из овог уређаја!", + "thisWillLogYouOutOfTheFollowingDevice": "Ово ће вас одјавити из овог уређаја:", + "terminateSession": "Прекинути сесију?", + "terminate": "Прекини", + "thisDevice": "Овај уређај", + "toResetVerifyEmail": "Да бисте ресетовали лозинку, прво потврдите свој имејл.", + "thisEmailIsAlreadyInUse": "Овај имејл је већ у употреби", + "verificationFailedPleaseTryAgain": "Неуспешна верификација, покушајте поново", + "yourVerificationCodeHasExpired": "Ваш верификациони кôд је истекао", + "incorrectCode": "Погрешан кôд", + "sorryTheCodeYouveEnteredIsIncorrect": "Унет кôд није добар", + "emailChangedTo": "Имејл промењен на {newEmail}", + "authenticationFailedPleaseTryAgain": "Аутентификација није успела, покушајте поново", + "authenticationSuccessful": "Успешна аутентификација!", + "twofactorAuthenticationSuccessfullyReset": "Двофакторска аутентификација успешно рисетирана", + "incorrectRecoveryKey": "Нетачан кључ за опоравак", + "theRecoveryKeyYouEnteredIsIncorrect": "Унети кључ за опоравак је натачан", + "enterPassword": "Унеси лозинку", + "selectExportFormat": "Изабрати формат извоза", + "exportDialogDesc": "Шифровани извоз ће бити заштићен лозинком по вашем избору.", + "encrypted": "Шифровано", + "plainText": "Обичан текст", + "passwordToEncryptExport": "Лозинка за шифровање извоза", + "export": "Извези", + "useOffline": "Користите без резервних копија", + "signInToBackup": "Пријавите се да бисте сачували кôдове", + "singIn": "Пријавите се", + "sigInBackupReminder": "Извезите кôдове да бисте имали резервну копију од које можете да их вратите.", + "offlineModeWarning": "Одлучили сте да наставите без резервних копија. Молимо примите ручне резервне копије да бисте били сигурни да су ваше кодове на сигурном.", + "showLargeIcons": "Прикажи велике иконе", + "compactMode": "Компактни режим", + "shouldHideCode": "Сакриј кодове", + "doubleTapToViewHiddenCode": "Можете да двапут додирнете унос да бисте видели кôд", + "focusOnSearchBar": "Фокус на претрагу на покретање", + "confirmUpdatingkey": "Јесте ли сигурни да желите да ажурирате тајну кључ?", + "minimizeAppOnCopy": "Умањи апликацију после копије", + "editCodeAuthMessage": "Аутентификуј се за уред кôда", + "deleteCodeAuthMessage": "Аутентификуј се за брсање кôда", + "showQRAuthMessage": "Аутентификуј се за приказ QR кôда", + "confirmAccountDeleteTitle": "Потврда брисања рачуна", + "confirmAccountDeleteMessage": "Овај налог је повезан са другим Ente апликацијама, ако користите било коју.\n\nВаши преношени подаци, на свим Ente апликацијама биће заказани за брисање, и ваш рачун ће се трајно избрисати.", + "androidBiometricHint": "Потврдите идентитет", + "@androidBiometricHint": { + "description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters." + }, + "androidBiometricNotRecognized": "Нисмо препознали. Покушати поново.", + "@androidBiometricNotRecognized": { + "description": "Message to let the user know that authentication was failed. It is used on Android side. Maximum 60 characters." + }, + "androidBiometricSuccess": "Успех", + "@androidBiometricSuccess": { + "description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters." + }, + "androidCancelButton": "Откажи", + "@androidCancelButton": { + "description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters." + }, + "androidSignInTitle": "Потребна аутентификација", + "@androidSignInTitle": { + "description": "Message showed as a title in a dialog which indicates the user that they need to scan biometric to continue. It is used on Android side. Maximum 60 characters." + }, + "androidBiometricRequiredTitle": "Потребна је биометрија", + "@androidBiometricRequiredTitle": { + "description": "Message showed as a title in a dialog which indicates the user has not set up biometric authentication on their device. It is used on Android side. Maximum 60 characters." + }, + "androidDeviceCredentialsRequiredTitle": "Потребни су акредитиви уређаја", + "@androidDeviceCredentialsRequiredTitle": { + "description": "Message showed as a title in a dialog which indicates the user has not set up credentials authentication on their device. It is used on Android side. Maximum 60 characters." + }, + "androidDeviceCredentialsSetupDescription": "Потребни су акредитиви уређаја", + "@androidDeviceCredentialsSetupDescription": { + "description": "Message advising the user to go to the settings and configure device credentials on their device. It shows in a dialog on Android side." + }, + "goToSettings": "Иди на поставке", + "@goToSettings": { + "description": "Message showed on a button that the user can click to go to settings pages from the current dialog. It is used on both Android and iOS side. Maximum 30 characters." + }, + "androidGoToSettingsDescription": "Биометријска аутентификација није постављена на вашем уређају. Идите на \"Подешавања> Сигурност\" да бисте додали биометријску аутентификацију.", + "@androidGoToSettingsDescription": { + "description": "Message advising the user to go to the settings and configure biometric on their device. It shows in a dialog on Android side." + }, + "iOSLockOut": "Биометријска аутентификација је онемогућена. Закључајте и откључите екран да бисте је омогућили.", + "@iOSLockOut": { + "description": "Message advising the user to re-enable biometrics on their device. It shows in a dialog on iOS side." + }, + "iOSGoToSettingsDescription": "Биометријска аутентификација није постављена на вашем уређају. Молимо или омогућите Touch ID или Face ID.", + "@iOSGoToSettingsDescription": { + "description": "Message advising the user to go to the settings and configure Biometrics for their device. It shows in a dialog on iOS side." + }, + "iOSOkButton": "У реду", + "@iOSOkButton": { + "description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters." + }, + "noInternetConnection": "Нема интернет везе", + "pleaseCheckYourInternetConnectionAndTryAgain": "Провери своју везу са интернетом и покушај поново.", + "signOutFromOtherDevices": "Одјави се из других уређаја", + "signOutOtherBody": "Ако мислиш да неко може знати твоју лозинку, можеш приморати одјављивање све остале уређаје које користе твој налог.", + "signOutOtherDevices": "Одјави друге уређаје", + "doNotSignOut": "Не одјави", + "hearUsWhereTitle": "Како сте чули о Ente? (опционо)", + "hearUsExplanation": "Не пратимо инсталацију апликације. Помогло би да нам кажеш како си нас нашао!", + "recoveryKeySaved": "Кључ за опоравак сачуван у фасцикли за преузимање!", + "waitingForBrowserRequest": "Чека се захтев за претраживач...", + "waitingForVerification": "Чека се верификација...", + "passkey": "Кључ за приступ", + "passKeyPendingVerification": "Верификација је још у току", + "loginSessionExpired": "Сесија је истекла", + "loginSessionExpiredDetails": "Ваша сесија је истекла. Молимо пријавите се поново.", + "developerSettingsWarning": "Сигурно желиш да промениш подешавања за програмере?", + "developerSettings": "Подешавања за програмере", + "serverEndpoint": "Крајња тачка сервера", + "invalidEndpoint": "Погрешна крајња тачка", + "invalidEndpointMessage": "Извини, крајња тачка коју си унео је неважећа. Унеси важећу крајњу тачку и покушај поново.", + "endpointUpdatedMessage": "Крајна тачка успешно ажурирана", + "customEndpoint": "Везано за {endpoint}", + "pinText": "Закачи", + "unpinText": "Откачи", + "pinnedCodeMessage": "{code} је прикачен", + "unpinnedCodeMessage": "{code} је одкачен", + "pinned": "Прикачено", + "tags": "Ознаке", + "createNewTag": "Креирај нову ознаку", + "tag": "Ознака", + "create": "Направи", + "editTag": "Уреди ознаку", + "deleteTagTitle": "Обрисати ознаку?", + "deleteTagMessage": "Сигурно желите да избришете ову ознаку? Ова акција је неповратна.", + "somethingWentWrongParsingCode": "Нисмо били у стању да рашчланимо {x} кôдова.", + "updateNotAvailable": "Ажурирање није доступно", + "viewRawCodes": "Погледајте сирове кôдове", + "rawCodes": "Сирове кôдове", + "rawCodeData": "Податак сировог кôда", + "appLock": "Закључавање апликације", + "noSystemLockFound": "Није пронађено ниједно закључавање система", + "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Да бисте омогућили закључавање апликације, молимо вас да подесите шифру уређаја или закључавање екрана у системским подешавањима.", + "autoLock": "Ауто-закључавање", + "immediately": "Одмах", + "reEnterPassword": "Поново унеси лозинку", + "reEnterPin": "Поново унеси ПИН", + "next": "Следеће", + "tooManyIncorrectAttempts": "Превише погрешних покушаја", + "tapToUnlock": "Додирните да бисте откључали", + "setNewPassword": "Постави нову лозинку", + "deviceLock": "Закључавање уређаја", + "hideContent": "Сакриј садржај", + "hideContentDescriptionAndroid": "Сакрива садржај апликације у пребацивање апликација и онемогућује снимке екрана", + "hideContentDescriptioniOS": "Сакрива садржај апликације у пребацивање апликација", + "autoLockFeatureDescription": "Време након којег се апликација блокира након што је постављенеа у позадину", + "appLockDescription": "Изаберите између заданог закључавање екрана вашег уређаја и прилагођени екран за закључавање са ПИН-ом или лозинком.", + "pinLock": "ПИН клокирање", + "enterPin": "Унеси ПИН", + "setNewPin": "Постави нови ПИН", + "importFailureDescNew": "Није могао да анализира изабрану датотеку.", + "appLockNotEnabled": "Блокирање апликације није упаљено", + "appLockNotEnabledDescription": "Молимо упалие блокирање апликације на Безбедност > Блокирај апликацију", + "authToViewPasskey": "Аутентификујте се да бисте прегледали кључ", + "appLockOfflineModeWarning": "Одлучили сте да наставите без резервних копија. Ако заборавите лозинку, нећете моћи да приступите својим подацима.", + "duplicateCodes": "Дупликатни кодови", + "noDuplicates": "✨ Нема дупликата", + "youveNoDuplicateCodesThatCanBeCleared": "Немате дупликатне кодове који се могу очистити", + "deduplicateCodes": "Дедуплицирај кодове", + "deselectAll": "Поништи избор свега", + "selectAll": "Изабери све", + "deleteDuplicates": "Обриши дупликате", + "plainHTML": "HTML", + "tellUsWhatYouThink": "Реци нам шта мислиш", + "dropReviewiOS": "Напиши мишљење на App Store", + "dropReviewAndroid": "Напиши мишљење на Play Store", + "supportEnte": "Подржи ente", + "giveUsAStarOnGithub": "Дај нам звездицу на Github", + "free5GB": "5GB бесплатно на ente Photos", + "loginWithAuthAccount": "Пријави се са твојим Auth налогом", + "freeStorageOffer": "Попуст од 10% на ente photos", + "freeStorageOfferDescription": "Употребите кôд \"AUTH\" да би добили попуст од 10% прве године", + "advanced": "Напредно", + "algorithm": "Алгоритам", + "type": "Тип", + "period": "Период", + "digits": "Цифре" +} \ No newline at end of file diff --git a/auth/lib/l10n/arb/app_sv.arb b/auth/lib/l10n/arb/app_sv.arb index 58e6032e5c..4092736661 100644 --- a/auth/lib/l10n/arb/app_sv.arb +++ b/auth/lib/l10n/arb/app_sv.arb @@ -173,6 +173,7 @@ "invalidQRCode": "Ogiltig QR-kod", "noRecoveryKeyTitle": "Ingen återställningsnyckel?", "enterEmailHint": "Ange din e-postadress", + "enterNewEmailHint": "Ange din nya e-postadress", "invalidEmailTitle": "Ogiltig e-postadress", "invalidEmailMessage": "Ange en giltig e-postadress.", "deleteAccount": "Radera konto", @@ -368,16 +369,19 @@ "signInToBackup": "Logga in för att säkerhetskopiera dina koder", "singIn": "Logga in", "sigInBackupReminder": "Vänligen exportera dina koder för att säkerställa att du har en säkerhetskopia som du kan återställa från.", + "offlineModeWarning": "Du har valt att fortsätta utan säkerhetskopior. Vänligen ta manuella säkerhetskopior för att se till att dina koder är säkra.", "showLargeIcons": "Visa stora ikoner", "compactMode": "Kompakt läge", "shouldHideCode": "Dölj koder", "doubleTapToViewHiddenCode": "Du kan dubbeltrycka på en post för att visa koden", "focusOnSearchBar": "Fokusera på sök vid appstart", + "confirmUpdatingkey": "Är du säker på att du vill uppdatera den hemliga nyckeln?", "minimizeAppOnCopy": "Minimera appen vid kopiering", "editCodeAuthMessage": "Autentisera för att redigera kod", "deleteCodeAuthMessage": "Autentisera för att radera kod", "showQRAuthMessage": "Autentisera för att visa QR-kod", "confirmAccountDeleteTitle": "Bekräfta radering av kontot", + "confirmAccountDeleteMessage": "Detta konto är kopplat till andra Ente apps, om du använder någon.\n\nDina uppladdade data, över alla Ente appar, kommer att schemaläggas för radering och ditt konto kommer att raderas permanent.", "androidBiometricHint": "Verifiera identitet", "@androidBiometricHint": { "description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters." @@ -414,6 +418,18 @@ "@goToSettings": { "description": "Message showed on a button that the user can click to go to settings pages from the current dialog. It is used on both Android and iOS side. Maximum 30 characters." }, + "androidGoToSettingsDescription": "Biometrisk autentisering är inte konfigurerad på din enhet. Gå till \"Inställningar > Säkerhet\" för att lägga till biometrisk autentisering.", + "@androidGoToSettingsDescription": { + "description": "Message advising the user to go to the settings and configure biometric on their device. It shows in a dialog on Android side." + }, + "iOSLockOut": "Biometrisk autentisering är inaktiverat. Lås och lås upp din skärm för att aktivera den.", + "@iOSLockOut": { + "description": "Message advising the user to re-enable biometrics on their device. It shows in a dialog on iOS side." + }, + "iOSGoToSettingsDescription": "Biometrisk autentisering är inte konfigurerad på din enhet. Aktivera antingen Touch ID eller Face ID på din telefon.", + "@iOSGoToSettingsDescription": { + "description": "Message advising the user to go to the settings and configure Biometrics for their device. It shows in a dialog on iOS side." + }, "iOSOkButton": "OK", "@iOSOkButton": { "description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters." @@ -421,6 +437,7 @@ "noInternetConnection": "Ingen internetanslutning", "pleaseCheckYourInternetConnectionAndTryAgain": "Kontrollera din internetanslutning och försök igen.", "signOutFromOtherDevices": "Logga ut från andra enheter", + "signOutOtherBody": "Om du tror att någon kanske känner till ditt lösenord kan du tvinga alla andra enheter med ditt konto att logga ut.", "signOutOtherDevices": "Logga ut andra enheter", "doNotSignOut": "Logga inte ut", "hearUsWhereTitle": "Hur hörde du talas om Ente? (valfritt)", @@ -450,6 +467,7 @@ "create": "Skapa", "editTag": "Redigera tagg", "deleteTagTitle": "Radera tagg?", + "deleteTagMessage": "Vill du ta bort den här koden? Det går inte att ångra den här åtgärden.", "somethingWentWrongParsingCode": "Vi kunde inte tolka {x} koder.", "updateNotAvailable": "Uppdateringen är inte tillgänglig", "viewRawCodes": "Visa råa koder", diff --git a/auth/lib/l10n/arb/app_tr.arb b/auth/lib/l10n/arb/app_tr.arb index bb66efa9e1..2500455576 100644 --- a/auth/lib/l10n/arb/app_tr.arb +++ b/auth/lib/l10n/arb/app_tr.arb @@ -173,6 +173,7 @@ "invalidQRCode": "Geçersiz QR kodu", "noRecoveryKeyTitle": "Kurtarma anahtarınız yok mu?", "enterEmailHint": "E-posta adresinizi girin", + "enterNewEmailHint": "Yeni e-posta adresinizi girin", "invalidEmailTitle": "Geçersiz e-posta adresi", "invalidEmailMessage": "Lütfen geçerli bir e-posta adresi girin.", "deleteAccount": "Hesabı sil", diff --git a/auth/lib/l10n/arb/app_zh_TW.arb b/auth/lib/l10n/arb/app_zh_TW.arb index 57734db276..230c4d2d1f 100644 --- a/auth/lib/l10n/arb/app_zh_TW.arb +++ b/auth/lib/l10n/arb/app_zh_TW.arb @@ -173,6 +173,7 @@ "invalidQRCode": "QR 碼無效", "noRecoveryKeyTitle": "沒有復原密鑰嗎?", "enterEmailHint": "請輸入您的電子郵件地址", + "enterNewEmailHint": "輸入你的新電子郵件地址", "invalidEmailTitle": "無效的電子郵件地址", "invalidEmailMessage": "請輸入一個有效的電子郵件地址。", "deleteAccount": "刪除帳戶", diff --git a/auth/lib/main.dart b/auth/lib/main.dart index c747ac41eb..54f8da92aa 100644 --- a/auth/lib/main.dart +++ b/auth/lib/main.dart @@ -14,7 +14,6 @@ import 'package:ente_auth/services/billing_service.dart'; import 'package:ente_auth/services/notification_service.dart'; import 'package:ente_auth/services/preference_service.dart'; import 'package:ente_auth/services/update_service.dart'; -import 'package:ente_auth/services/user_remote_flag_service.dart'; import 'package:ente_auth/services/user_service.dart'; import 'package:ente_auth/services/window_listener_service.dart'; import 'package:ente_auth/store/code_display_store.dart'; @@ -87,19 +86,6 @@ void main() async { } } -// Future whiteListLetsEncryptRootCA() async { -// try { -// // https://stackoverflow.com/a/71090239 -// // https://github.com/ente-io/ente/issues/2178 -// ByteData data = -// await PlatformAssetBundle().load('assets/ca/lets-encrypt-r3.pem'); -// SecurityContext.defaultContext -// .setTrustedCertificatesBytes(data.buffer.asUint8List()); -// } catch (e) { -// _logger.severe("Failed to whitelist Let's Encrypt Root CA", e); -// } -// } - Future _runInForeground() async { final savedThemeMode = _themeMode(await AdaptiveTheme.getThemeMode()); return await _runWithLogs(() async { @@ -116,7 +102,7 @@ Future _runInForeground() async { AppLock( builder: (args) => App(locale: locale), lockScreen: const LockScreen(), - enabled: await Configuration.instance.shouldShowLockScreen(), + enabled: await LockScreenSettings.instance.shouldShowLockScreen(), locale: locale, lightTheme: lightThemeData, darkTheme: darkThemeData, @@ -169,7 +155,6 @@ Future _init(bool bool, {String? via}) async { await Configuration.instance.init(); await Network.instance.init(); await UserService.instance.init(); - await UserRemoteFlagService.instance.init(); await AuthenticatorService.instance.init(); await BillingService.instance.init(); await NotificationService.instance.init(); diff --git a/auth/lib/services/authenticator_service.dart b/auth/lib/services/authenticator_service.dart index ee0ad32bd4..559e85f81a 100644 --- a/auth/lib/services/authenticator_service.dart +++ b/auth/lib/services/authenticator_service.dart @@ -13,6 +13,7 @@ import 'package:ente_auth/models/authenticator/auth_entity.dart'; import 'package:ente_auth/models/authenticator/auth_key.dart'; import 'package:ente_auth/models/authenticator/entity_result.dart'; import 'package:ente_auth/models/authenticator/local_auth_entity.dart'; +import 'package:ente_auth/services/preference_service.dart'; import 'package:ente_auth/store/authenticator_db.dart'; import 'package:ente_auth/store/offline_authenticator_db.dart'; import 'package:ente_crypto_dart/ente_crypto_dart.dart'; @@ -194,8 +195,13 @@ class AuthenticatorService { final int lastSyncTime = _prefs.getInt(_lastEntitySyncTime) ?? 0; _logger.info("Current sync is $lastSyncTime"); const int fetchLimit = 500; - final List result = + late final List result; + late final int? epochTimeInMicroseconds; + (result, epochTimeInMicroseconds) = await _gateway.getDiff(lastSyncTime, limit: fetchLimit); + PreferenceService.instance + .computeAndStoreTimeOffset(epochTimeInMicroseconds); + _logger.info("${result.length} entries fetched from remote"); if (result.isEmpty) { return; diff --git a/auth/lib/services/local_authentication_service.dart b/auth/lib/services/local_authentication_service.dart index 02c609591d..1502b2a36e 100644 --- a/auth/lib/services/local_authentication_service.dart +++ b/auth/lib/services/local_authentication_service.dart @@ -1,6 +1,5 @@ import 'dart:io'; -import 'package:ente_auth/core/configuration.dart'; import 'package:ente_auth/ui/settings/lock_screen/lock_screen_password.dart'; import 'package:ente_auth/ui/settings/lock_screen/lock_screen_pin.dart'; import 'package:ente_auth/ui/tools/app_lock.dart'; @@ -42,7 +41,7 @@ class LocalAuthenticationService { isAuthenticatingForInAppChange: true, ); AppLock.of(context)!.setEnabled( - await Configuration.instance.shouldShowLockScreen(), + await LockScreenSettings.instance.shouldShowLockScreen(), ); if (!result) { showToast(context, infoMessage); @@ -114,12 +113,13 @@ class LocalAuthenticationService { ); if (result) { AppLock.of(context)!.setEnabled(shouldEnableLockScreen); - await Configuration.instance + await LockScreenSettings.instance .setSystemLockScreen(shouldEnableLockScreen); return true; } else { - AppLock.of(context)! - .setEnabled(await Configuration.instance.shouldShowLockScreen()); + AppLock.of(context)!.setEnabled( + await LockScreenSettings.instance.shouldShowLockScreen(), + ); } } else { // ignore: unawaited_futures diff --git a/auth/lib/services/preference_service.dart b/auth/lib/services/preference_service.dart index 45a2cf0e66..773ee1b149 100644 --- a/auth/lib/services/preference_service.dart +++ b/auth/lib/services/preference_service.dart @@ -18,6 +18,7 @@ class PreferenceService { late final SharedPreferences _prefs; static const kHasShownCoachMarkKey = "has_shown_coach_mark_v2"; + static const kLocalTimeOffsetKey = "local_time_offset"; static const kShouldShowLargeIconsKey = "should_show_large_icons"; static const kShouldHideCodesKey = "should_hide_codes"; static const kShouldAutoFocusOnSearchBar = "should_auto_focus_on_search_bar"; @@ -114,4 +115,24 @@ class PreferenceService { return installedTimeinMillis; } } + + // localEpochOffsetInMilliSecond returns the local epoch offset in milliseconds. + // This is used to adjust the time for TOTP calculations when device local time is not in sync with actual time. + int timeOffsetInMilliSeconds() { + return _prefs.getInt(kLocalTimeOffsetKey) ?? 0; + } + + void computeAndStoreTimeOffset( + int? epochTimeInMicroseconds, + ) { + if (epochTimeInMicroseconds == null) { + _prefs.remove(kLocalTimeOffsetKey); + return; + } + int serverEpochTimeInMilliSecond = epochTimeInMicroseconds ~/ 1000; + int localEpochTimeInMilliSecond = DateTime.now().millisecondsSinceEpoch; + int localEpochOffset = + serverEpochTimeInMilliSecond - localEpochTimeInMilliSecond; + _prefs.setInt(kLocalTimeOffsetKey, localEpochOffset); + } } diff --git a/auth/lib/services/user_remote_flag_service.dart b/auth/lib/services/user_remote_flag_service.dart deleted file mode 100644 index 74deae5843..0000000000 --- a/auth/lib/services/user_remote_flag_service.dart +++ /dev/null @@ -1,141 +0,0 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:collection/collection.dart'; -import 'package:dio/dio.dart'; -import 'package:ente_auth/core/configuration.dart'; -import 'package:ente_auth/core/event_bus.dart'; -import 'package:ente_auth/core/network.dart'; -import 'package:ente_auth/events/notification_event.dart'; -import 'package:ente_auth/services/user_service.dart'; -import 'package:logging/logging.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -class UserRemoteFlagService { - final _dio = Network.instance.getDio(); - final _logger = Logger((UserRemoteFlagService).toString()); - final _config = Configuration.instance; - late SharedPreferences _prefs; - - UserRemoteFlagService._privateConstructor(); - - static final UserRemoteFlagService instance = - UserRemoteFlagService._privateConstructor(); - - static const String recoveryVerificationFlag = "recoveryKeyVerified"; - static const String needRecoveryKeyVerification = - "needRecoveryKeyVerification"; - - Future init() async { - _prefs = await SharedPreferences.getInstance(); - } - - bool shouldShowRecoveryVerification() { - if (!_prefs.containsKey(needRecoveryKeyVerification)) { - // fetch the status from remote - unawaited(_refreshRecoveryVerificationFlag()); - return false; - } else { - final bool shouldShow = _prefs.getBool(needRecoveryKeyVerification)!; - if (shouldShow) { - // refresh the status to check if user marked it as done on another device - unawaited(_refreshRecoveryVerificationFlag()); - } - return shouldShow; - } - } - - // markRecoveryVerificationAsDone is used to track if user has verified their - // recovery key in the past or not. This helps in avoid showing the same - // prompt to the user on re-install or signing into a different device - Future markRecoveryVerificationAsDone() async { - await _updateKeyValue(recoveryVerificationFlag, true.toString()); - await _prefs.setBool(needRecoveryKeyVerification, false); - } - - Future _refreshRecoveryVerificationFlag() async { - _logger.finest('refresh recovery key verification flag'); - final remoteStatusValue = - await _getValue(recoveryVerificationFlag, "false"); - final bool isNeedVerificationFlagSet = - _prefs.containsKey(needRecoveryKeyVerification); - if (remoteStatusValue.toLowerCase() == "true") { - await _prefs.setBool(needRecoveryKeyVerification, false); - // If the user verified on different device, then we should refresh - // the UI to dismiss the Notification. - if (isNeedVerificationFlagSet) { - Bus.instance.fire(NotificationEvent()); - } - } else if (!isNeedVerificationFlagSet) { - // Verification is not done yet as remoteStatus is false and local flag to - // show notification isn't set. Set the flag to true if any active - // session is older than 1 day. - final activeSessions = await UserService.instance.getActiveSessions(); - final int microSecondsInADay = const Duration(days: 1).inMicroseconds; - final bool anyActiveSessionOlderThanADay = - activeSessions.sessions.firstWhereOrNull( - (e) => - (e.creationTime + microSecondsInADay) < - DateTime.now().microsecondsSinceEpoch, - ) != - null; - if (anyActiveSessionOlderThanADay) { - await _prefs.setBool(needRecoveryKeyVerification, true); - Bus.instance.fire(NotificationEvent()); - } else { - // continue defaulting to no verification prompt - _logger.finest('No active session older than 1 day'); - } - } - } - - Future _getValue(String key, String? defaultValue) async { - try { - final Map queryParams = {"key": key}; - if (defaultValue != null) { - queryParams["defaultValue"] = defaultValue; - } - final response = await _dio.get( - "${_config.getHttpEndpoint()}/remote-store", - queryParameters: queryParams, - options: Options( - headers: { - "X-Auth-Token": _config.getToken(), - }, - ), - ); - if (response.statusCode != HttpStatus.ok) { - throw Exception("Unexpected status code ${response.statusCode}"); - } - return response.data["value"]; - } catch (e) { - _logger.info("Error while fetching bool status for $key", e); - rethrow; - } - } - - // _setBooleanFlag sets the corresponding flag on remote - // to mark recovery as completed - Future _updateKeyValue(String key, String value) async { - try { - final response = await _dio.post( - "${_config.getHttpEndpoint()}/remote-store/update", - data: { - "key": key, - "value": value, - }, - options: Options( - headers: { - "X-Auth-Token": _config.getToken(), - }, - ), - ); - if (response.statusCode != HttpStatus.ok) { - throw Exception("Unexpected state"); - } - } catch (e) { - _logger.warning("Failed to set flag for $key", e); - rethrow; - } - } -} diff --git a/auth/lib/ui/account/verify_recovery_page.dart b/auth/lib/ui/account/verify_recovery_page.dart deleted file mode 100644 index bb4ebb068a..0000000000 --- a/auth/lib/ui/account/verify_recovery_page.dart +++ /dev/null @@ -1,219 +0,0 @@ -import 'package:bip39/bip39.dart' as bip39; -import 'package:dio/dio.dart'; -import 'package:ente_auth/core/configuration.dart'; -import 'package:ente_auth/ente_theme_data.dart'; -import 'package:ente_auth/l10n/l10n.dart'; -import 'package:ente_auth/services/local_authentication_service.dart'; -import 'package:ente_auth/services/user_remote_flag_service.dart'; -import 'package:ente_auth/ui/account/recovery_key_page.dart'; -import 'package:ente_auth/ui/common/gradient_button.dart'; -import 'package:ente_auth/ui/components/buttons/button_widget.dart'; -import 'package:ente_auth/utils/dialog_util.dart'; -import 'package:ente_auth/utils/navigation_util.dart'; -import 'package:ente_auth/utils/platform_util.dart'; -import 'package:ente_crypto_dart/ente_crypto_dart.dart'; -import 'package:flutter/material.dart'; -import 'package:logging/logging.dart'; - -class VerifyRecoveryPage extends StatefulWidget { - const VerifyRecoveryPage({super.key}); - - @override - State createState() => _VerifyRecoveryPageState(); -} - -class _VerifyRecoveryPageState extends State { - final _recoveryKey = TextEditingController(); - final Logger _logger = Logger((_VerifyRecoveryPageState).toString()); - - void _verifyRecoveryKey() async { - final dialog = - createProgressDialog(context, context.l10n.verifyingRecoveryKey); - await dialog.show(); - try { - final String inputKey = _recoveryKey.text.trim(); - final String recoveryKey = - CryptoUtil.bin2hex(Configuration.instance.getRecoveryKey()); - final String recoveryKeyWords = bip39.entropyToMnemonic(recoveryKey); - if (inputKey == recoveryKey || inputKey == recoveryKeyWords) { - try { - await UserRemoteFlagService.instance.markRecoveryVerificationAsDone(); - } catch (e) { - await dialog.hide(); - if (e is DioException && e.type == DioExceptionType.unknown) { - await showErrorDialog( - context, - "No internet connection", - "Please check your internet connection and try again.", - ); - } else { - await showGenericErrorDialog( - context: context, - error: e, - ); - } - return; - } - - await dialog.hide(); - // todo: change this as per figma once the component is ready - await showErrorDialog( - context, - context.l10n.recoveryKeyVerified, - context.l10n.recoveryKeySuccessBody, - ); - Navigator.of(context).pop(); - } else { - throw Exception("recovery key didn't match"); - } - } catch (e, s) { - _logger.severe("failed to verify recovery key", e, s); - await dialog.hide(); - final String errMessage = context.l10n.invalidRecoveryKey; - final result = await showChoiceDialog( - context, - title: context.l10n.invalidKey, - body: errMessage, - firstButtonLabel: context.l10n.tryAgain, - secondButtonLabel: context.l10n.viewRecoveryKey, - secondButtonAction: ButtonAction.second, - ); - if (result!.action == ButtonAction.second) { - await _onViewRecoveryKeyClick(); - } - } - } - - Future _onViewRecoveryKeyClick() async { - final hasAuthenticated = - await LocalAuthenticationService.instance.requestLocalAuthentication( - context, - "Please authenticate to view your recovery key", - ); - await PlatformUtil.refocusWindows(); - - if (hasAuthenticated) { - String recoveryKey; - try { - recoveryKey = - CryptoUtil.bin2hex(Configuration.instance.getRecoveryKey()); - await routeToPage( - context, - RecoveryKeyPage( - recoveryKey, - context.l10n.ok, - showAppBar: true, - onDone: () { - Navigator.of(context).pop(); - }, - ), - ); - } catch (e) { - // ignore: unawaited_futures - showGenericErrorDialog( - context: context, - error: e, - ); - return; - } - } - } - - @override - Widget build(BuildContext context) { - final enteTheme = Theme.of(context).colorScheme.enteTheme; - return Scaffold( - appBar: AppBar( - elevation: 0, - leading: IconButton( - icon: const Icon(Icons.arrow_back), - color: Theme.of(context).iconTheme.color, - onPressed: () { - Navigator.of(context).pop(); - }, - ), - ), - body: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: LayoutBuilder( - builder: (context, constraints) { - return SingleChildScrollView( - child: ConstrainedBox( - constraints: BoxConstraints( - minWidth: constraints.maxWidth, - minHeight: constraints.maxHeight, - ), - child: IntrinsicHeight( - child: Column( - children: [ - const SizedBox(height: 12), - SizedBox( - width: double.infinity, - child: Text( - context.l10n.confirmRecoveryKey, - style: enteTheme.textTheme.h3Bold, - textAlign: TextAlign.left, - ), - ), - const SizedBox(height: 18), - Text( - context.l10n.recoveryKeyVerifyReason, - style: enteTheme.textTheme.small - .copyWith(color: enteTheme.colorScheme.textMuted), - ), - const SizedBox(height: 12), - TextFormField( - decoration: InputDecoration( - filled: true, - hintText: context.l10n.enterYourRecoveryKey, - contentPadding: const EdgeInsets.all(20), - border: UnderlineInputBorder( - borderSide: BorderSide.none, - borderRadius: BorderRadius.circular(6), - ), - ), - style: const TextStyle( - fontSize: 14, - fontFeatures: [FontFeature.tabularFigures()], - ), - controller: _recoveryKey, - autofocus: false, - autocorrect: false, - keyboardType: TextInputType.multiline, - minLines: 4, - maxLines: null, - onChanged: (_) { - setState(() {}); - }, - ), - const SizedBox(height: 12), - Expanded( - child: Container( - alignment: Alignment.bottomCenter, - width: double.infinity, - padding: const EdgeInsets.fromLTRB(0, 12, 0, 40), - child: Column( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - GradientButton( - onTap: _verifyRecoveryKey, - text: context.l10n.confirm, - ), - const SizedBox(height: 8), - ], - ), - ), - ), - const SizedBox(height: 20), - ], - ), - ), - ), - ); - }, - ), - ), - ); - } -} diff --git a/auth/lib/ui/code_timer_progress.dart b/auth/lib/ui/code_timer_progress.dart index 520a18d76c..58386fe438 100644 --- a/auth/lib/ui/code_timer_progress.dart +++ b/auth/lib/ui/code_timer_progress.dart @@ -7,10 +7,12 @@ import 'package:flutter/material.dart'; class CodeTimerProgress extends StatefulWidget { final int period; final bool isCompactMode; + final int timeOffsetInMilliseconds; const CodeTimerProgress({ super.key, required this.period, this.isCompactMode = false, + this.timeOffsetInMilliseconds = 0, }); @override @@ -20,7 +22,7 @@ class CodeTimerProgress extends StatefulWidget { class _CodeTimerProgressState extends State { late final Timer _timer; late final ValueNotifier _progress; - late final int _periodInMicros; + late final int _periodInMilii; // Reduce update frequency final int _updateIntervalMs = @@ -29,29 +31,30 @@ class _CodeTimerProgressState extends State { @override void initState() { super.initState(); - _periodInMicros = widget.period * 1000000; + _periodInMilii = widget.period * 1000; _progress = ValueNotifier(0.0); - _updateTimeRemaining(DateTime.now().microsecondsSinceEpoch); + _updateTimeRemaining(DateTime.now().millisecondsSinceEpoch); _timer = Timer.periodic(Duration(milliseconds: _updateIntervalMs), (timer) { - final now = DateTime.now().microsecondsSinceEpoch; + final now = DateTime.now().millisecondsSinceEpoch; _updateTimeRemaining(now); }); } - void _updateTimeRemaining(int currentMicros) { + void _updateTimeRemaining(int currentMilliSeconds) { // More efficient time calculation using modulo - final elapsed = (currentMicros) % _periodInMicros; - final timeRemaining = _periodInMicros - elapsed; - _progress.value = timeRemaining / _periodInMicros; + final elapsed = (currentMilliSeconds + widget.timeOffsetInMilliseconds) % + _periodInMilii; + final timeRemaining = _periodInMilii - elapsed; + _progress.value = timeRemaining / _periodInMilii; } @override void didUpdateWidget(covariant CodeTimerProgress oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.period != widget.period) { - _periodInMicros = widget.period * 1000000; - _updateTimeRemaining(DateTime.now().microsecondsSinceEpoch); + _periodInMilii = widget.period * 1000; + _updateTimeRemaining(DateTime.now().millisecondsSinceEpoch); } } diff --git a/auth/lib/ui/code_widget.dart b/auth/lib/ui/code_widget.dart index 3ccb7ab67b..be9c2b8a69 100644 --- a/auth/lib/ui/code_widget.dart +++ b/auth/lib/ui/code_widget.dart @@ -152,6 +152,8 @@ class _CodeWidgetState extends State { key: ValueKey('period_${widget.code.period}'), period: widget.code.period, isCompactMode: widget.isCompactMode, + timeOffsetInMilliseconds: + PreferenceService.instance.timeOffsetInMilliSeconds(), ), widget.isCompactMode ? const SizedBox(height: 4) diff --git a/auth/lib/ui/home_page.dart b/auth/lib/ui/home_page.dart index cd522b7746..3a3d650259 100644 --- a/auth/lib/ui/home_page.dart +++ b/auth/lib/ui/home_page.dart @@ -319,7 +319,7 @@ class _HomePageState extends State { Future navigateToLockScreen() async { final bool shouldShowLockScreen = - await Configuration.instance.shouldShowLockScreen(); + await LockScreenSettings.instance.shouldShowLockScreen(); if (shouldShowLockScreen) { await AppLock.of(context)!.showLockScreen(); } else { diff --git a/auth/lib/ui/settings/lock_screen/lock_screen_options.dart b/auth/lib/ui/settings/lock_screen/lock_screen_options.dart index 9f53f10248..7f48bca84d 100644 --- a/auth/lib/ui/settings/lock_screen/lock_screen_options.dart +++ b/auth/lib/ui/settings/lock_screen/lock_screen_options.dart @@ -1,7 +1,6 @@ import "dart:async"; import "dart:io"; -import "package:ente_auth/core/configuration.dart"; import "package:ente_auth/l10n/l10n.dart"; import "package:ente_auth/services/local_authentication_service.dart"; import "package:ente_auth/theme/ente_theme.dart"; @@ -31,8 +30,7 @@ class LockScreenOptions extends StatefulWidget { } class _LockScreenOptionsState extends State { - final Configuration _configuration = Configuration.instance; - final LockScreenSettings _lockscreenSetting = LockScreenSettings.instance; + final LockScreenSettings _lockScreenSettings = LockScreenSettings.instance; late bool appLock = false; bool isPinEnabled = false; bool isPasswordEnabled = false; @@ -43,18 +41,18 @@ class _LockScreenOptionsState extends State { @override void initState() { super.initState(); - hideAppContent = _lockscreenSetting.getShouldHideAppContent(); - autoLockTimeInMilliseconds = _lockscreenSetting.getAutoLockTime(); + hideAppContent = _lockScreenSettings.getShouldHideAppContent(); + autoLockTimeInMilliseconds = _lockScreenSettings.getAutoLockTime(); _initializeSettings(); - appLock = _lockscreenSetting.getIsAppLockSet(); + appLock = _lockScreenSettings.getIsAppLockSet(); } Future _initializeSettings() async { - final bool passwordEnabled = await _lockscreenSetting.isPasswordSet(); - final bool pinEnabled = await _lockscreenSetting.isPinSet(); + final bool passwordEnabled = await _lockScreenSettings.isPasswordSet(); + final bool pinEnabled = await _lockScreenSettings.isPinSet(); final bool shouldHideAppContent = - _lockscreenSetting.getShouldHideAppContent(); - final bool systemLockEnabled = _configuration.shouldShowSystemLockScreen(); + _lockScreenSettings.getShouldHideAppContent(); + final bool systemLockEnabled = _lockScreenSettings.shouldShowSystemLockScreen(); setState(() { isPasswordEnabled = passwordEnabled; isPinEnabled = pinEnabled; @@ -66,8 +64,8 @@ class _LockScreenOptionsState extends State { Future _deviceLock() async { if (await LocalAuthenticationService.instance .isLocalAuthSupportedOnDevice()) { - await _lockscreenSetting.removePinAndPassword(); - await _configuration.setSystemLockScreen(!isSystemLockEnabled); + await _lockScreenSettings.removePinAndPassword(); + await _lockScreenSettings.setSystemLockScreen(!isSystemLockEnabled); } else { await showDialogWidget( context: context, @@ -96,10 +94,10 @@ class _LockScreenOptionsState extends State { ); if (result) { - await _configuration.setSystemLockScreen(false); - await _lockscreenSetting.setAppLockEnabled(true); + await _lockScreenSettings.setSystemLockScreen(false); + await _lockScreenSettings.setAppLockEnabled(true); setState(() { - appLock = _lockscreenSetting.getIsAppLockSet(); + appLock = _lockScreenSettings.getIsAppLockSet(); }); } await _initializeSettings(); @@ -114,9 +112,9 @@ class _LockScreenOptionsState extends State { ), ); if (result) { - await _configuration.setSystemLockScreen(false); + await _lockScreenSettings.setSystemLockScreen(false); setState(() { - appLock = _lockscreenSetting.getIsAppLockSet(); + appLock = _lockScreenSettings.getIsAppLockSet(); }); } await _initializeSettings(); @@ -126,17 +124,17 @@ class _LockScreenOptionsState extends State { AppLock.of(context)!.setEnabled(!appLock); if (await LocalAuthenticationService.instance .isLocalAuthSupportedOnDevice()) { - await _configuration.setSystemLockScreen(!appLock); - await _lockscreenSetting.setAppLockEnabled(!appLock); + await _lockScreenSettings.setSystemLockScreen(!appLock); + await _lockScreenSettings.setAppLockEnabled(!appLock); } else { - await _configuration.setSystemLockScreen(false); - await _lockscreenSetting.setAppLockEnabled(false); + await _lockScreenSettings.setSystemLockScreen(false); + await _lockScreenSettings.setAppLockEnabled(false); } - await _lockscreenSetting.removePinAndPassword(); + await _lockScreenSettings.removePinAndPassword(); if (PlatformUtil.isMobile()) { - await _lockscreenSetting.setHideAppContent(!appLock); + await _lockScreenSettings.setHideAppContent(!appLock); setState(() { - hideAppContent = _lockscreenSetting.getShouldHideAppContent(); + hideAppContent = _lockScreenSettings.getShouldHideAppContent(); }); } await _initializeSettings(); @@ -152,7 +150,7 @@ class _LockScreenOptionsState extends State { ).then( (value) { setState(() { - autoLockTimeInMilliseconds = _lockscreenSetting.getAutoLockTime(); + autoLockTimeInMilliseconds = _lockScreenSettings.getAutoLockTime(); }); }, ); @@ -162,7 +160,7 @@ class _LockScreenOptionsState extends State { setState(() { hideAppContent = !hideAppContent; }); - await _lockscreenSetting.setHideAppContent(hideAppContent); + await _lockScreenSettings.setHideAppContent(hideAppContent); } String _formatTime(Duration duration) { diff --git a/auth/lib/ui/settings/security_section_widget.dart b/auth/lib/ui/settings/security_section_widget.dart index 41b04c80b5..dab16cb56f 100644 --- a/auth/lib/ui/settings/security_section_widget.dart +++ b/auth/lib/ui/settings/security_section_widget.dart @@ -166,7 +166,7 @@ class _SecuritySectionWidgetState extends State { return; } } - if (await Configuration.instance.shouldShowLockScreen()) { + if (await LockScreenSettings.instance.shouldShowLockScreen()) { final bool result = await requestAuthentication( context, context.l10n.authToChangeLockscreenSetting, diff --git a/auth/lib/utils/auth_util.dart b/auth/lib/utils/auth_util.dart index df11211c92..6c797a4328 100644 --- a/auth/lib/utils/auth_util.dart +++ b/auth/lib/utils/auth_util.dart @@ -53,6 +53,7 @@ Future requestAuthentication( signInTitle: l10n.androidSignInTitle, ), IOSAuthMessages( + localizedFallbackTitle: l10n.enterPassword, goToSettingsButton: l10n.goToSettings, goToSettingsDescription: l10n.goToSettings, lockOut: l10n.iOSLockOut, diff --git a/auth/lib/utils/lock_screen_settings.dart b/auth/lib/utils/lock_screen_settings.dart index b87323e37d..247f7ae4b2 100644 --- a/auth/lib/utils/lock_screen_settings.dart +++ b/auth/lib/utils/lock_screen_settings.dart @@ -3,6 +3,8 @@ import "dart:io"; import "dart:typed_data"; import "package:ente_auth/core/configuration.dart"; +import "package:ente_auth/core/event_bus.dart"; +import "package:ente_auth/events/signed_out_event.dart"; import "package:ente_auth/utils/platform_util.dart"; import "package:ente_crypto_dart/ente_crypto_dart.dart"; import "package:flutter/material.dart"; @@ -26,6 +28,7 @@ class LockScreenSettings { static const keyHasMigratedLockScreenChanges = "ls_has_migrated_lock_screen_changes"; static const keyShowOfflineModeWarning = "ls_show_offline_mode_warning"; + static const keyShouldShowLockScreen = "should_show_lock_screen"; static const String kIsLightMode = "is_light_mode"; final List autoLockDurations = const [ @@ -52,6 +55,10 @@ class LockScreenSettings { await runLockScreenChangesMigration(); await _clearLsDataInKeychainIfFreshInstall(); + + Bus.instance.on().listen((event) { + removePinAndPassword(); + }); } Future setOfflineModeWarningStatus(bool value) async { @@ -69,8 +76,7 @@ class LockScreenSettings { final bool passwordEnabled = await isPasswordSet(); final bool pinEnabled = await isPinSet(); - final bool systemLockEnabled = - Configuration.instance.shouldShowSystemLockScreen(); + final bool systemLockEnabled = shouldShowSystemLockScreen(); if (passwordEnabled || pinEnabled || systemLockEnabled) { await setAppLockEnabled(true); @@ -214,6 +220,24 @@ class LockScreenSettings { return await _secureStorage.containsKey(key: password); } + Future shouldShowLockScreen() async { + final bool isPin = await isPinSet(); + final bool isPass = await isPasswordSet(); + return isPin || isPass || shouldShowSystemLockScreen(); + } + + bool shouldShowSystemLockScreen() { + if (_preferences.containsKey(keyShouldShowLockScreen)) { + return _preferences.getBool(keyShouldShowLockScreen)!; + } else { + return false; + } + } + + Future setSystemLockScreen(bool value) { + return _preferences.setBool(keyShouldShowLockScreen, value); + } + // If the app was uninstalled (without logging out if it was used with // backups), keychain items of the app persist in the keychain. To avoid using // old keychain items, we delete them on reinstall. diff --git a/auth/lib/utils/totp_util.dart b/auth/lib/utils/totp_util.dart index 6b7f53ae5b..53b68be5ff 100644 --- a/auth/lib/utils/totp_util.dart +++ b/auth/lib/utils/totp_util.dart @@ -1,8 +1,14 @@ import 'package:ente_auth/models/code.dart'; +import 'package:ente_auth/services/preference_service.dart'; import 'package:flutter/foundation.dart'; import 'package:otp/otp.dart' as otp; import 'package:steam_totp/steam_totp.dart'; +int millisecondsSinceEpoch() { + return DateTime.now().millisecondsSinceEpoch + + PreferenceService.instance.timeOffsetInMilliSeconds(); +} + String getOTP(Code code) { if (code.type == Type.steam || code.issuer.toLowerCase() == 'steam') { return _getSteamCode(code); @@ -12,7 +18,7 @@ String getOTP(Code code) { } return otp.OTP.generateTOTPCodeString( getSanitizedSecret(code.secret), - DateTime.now().millisecondsSinceEpoch, + millisecondsSinceEpoch(), length: code.digits, interval: code.period, algorithm: _getAlgorithm(code), @@ -34,7 +40,7 @@ String _getSteamCode(Code code, [bool isNext = false]) { final SteamTOTP steamtotp = SteamTOTP(secret: code.secret); return steamtotp.generate( - DateTime.now().millisecondsSinceEpoch ~/ 1000 + (isNext ? code.period : 0), + millisecondsSinceEpoch() ~/ 1000 + (isNext ? code.period : 0), ); } @@ -44,7 +50,7 @@ String getNextTotp(Code code) { } return otp.OTP.generateTOTPCodeString( getSanitizedSecret(code.secret), - DateTime.now().millisecondsSinceEpoch + code.period * 1000, + millisecondsSinceEpoch() + code.period * 1000, length: code.digits, interval: code.period, algorithm: _getAlgorithm(code), @@ -56,9 +62,7 @@ String getNextTotp(Code code) { // It returns the start time and a list of future codes. (int, List) generateFutureTotpCodes(Code code, int count) { final int startTime = - ((DateTime.now().millisecondsSinceEpoch ~/ 1000) ~/ code.period) * - code.period * - 1000; + ((millisecondsSinceEpoch() ~/ 1000) ~/ code.period) * code.period * 1000; final String secret = getSanitizedSecret(code.secret); final List codes = []; if (code.type == Type.steam || code.issuer.toLowerCase() == 'steam') { diff --git a/auth/linux/packaging/enteauth.appdata.xml b/auth/linux/packaging/enteauth.appdata.xml index 82549faa00..6785961a91 100644 --- a/auth/linux/packaging/enteauth.appdata.xml +++ b/auth/linux/packaging/enteauth.appdata.xml @@ -18,6 +18,7 @@ + diff --git a/auth/pubspec.lock b/auth/pubspec.lock index fa632892e2..4b9e12285f 100644 --- a/auth/pubspec.lock +++ b/auth/pubspec.lock @@ -543,67 +543,74 @@ packages: flutter_inappwebview: dependency: "direct main" description: - name: flutter_inappwebview - sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5" - url: "https://pub.dev" - source: hosted - version: "6.1.5" + path: flutter_inappwebview + ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + resolved-ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + url: "https://github.com/pichillilorenzo/flutter_inappwebview.git" + source: git + version: "6.2.0-beta.3" flutter_inappwebview_android: dependency: transitive description: - name: flutter_inappwebview_android - sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba" - url: "https://pub.dev" - source: hosted - version: "1.1.3" + path: flutter_inappwebview_android + ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + resolved-ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + url: "https://github.com/pichillilorenzo/flutter_inappwebview.git" + source: git + version: "1.2.0-beta.3" flutter_inappwebview_internal_annotations: dependency: transitive description: name: flutter_inappwebview_internal_annotations - sha256: "5f80fd30e208ddded7dbbcd0d569e7995f9f63d45ea3f548d8dd4c0b473fb4c8" + sha256: "787171d43f8af67864740b6f04166c13190aa74a1468a1f1f1e9ee5b90c359cd" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" flutter_inappwebview_ios: dependency: transitive description: - name: flutter_inappwebview_ios - sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d" - url: "https://pub.dev" - source: hosted - version: "1.1.2" + path: flutter_inappwebview_ios + ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + resolved-ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + url: "https://github.com/pichillilorenzo/flutter_inappwebview.git" + source: git + version: "1.2.0-beta.3" flutter_inappwebview_macos: dependency: transitive description: - name: flutter_inappwebview_macos - sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1 - url: "https://pub.dev" - source: hosted - version: "1.1.2" + path: flutter_inappwebview_macos + ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + resolved-ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + url: "https://github.com/pichillilorenzo/flutter_inappwebview.git" + source: git + version: "1.2.0-beta.3" flutter_inappwebview_platform_interface: dependency: transitive description: - name: flutter_inappwebview_platform_interface - sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500 - url: "https://pub.dev" - source: hosted - version: "1.3.0+1" + path: flutter_inappwebview_platform_interface + ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + resolved-ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + url: "https://github.com/pichillilorenzo/flutter_inappwebview.git" + source: git + version: "1.4.0-beta.3" flutter_inappwebview_web: dependency: transitive description: - name: flutter_inappwebview_web - sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598" - url: "https://pub.dev" - source: hosted - version: "1.1.2" + path: flutter_inappwebview_web + ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + resolved-ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + url: "https://github.com/pichillilorenzo/flutter_inappwebview.git" + source: git + version: "1.2.0-beta.3" flutter_inappwebview_windows: dependency: transitive description: - name: flutter_inappwebview_windows - sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055" - url: "https://pub.dev" - source: hosted - version: "0.6.0" + path: flutter_inappwebview_windows + ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + resolved-ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + url: "https://github.com/pichillilorenzo/flutter_inappwebview.git" + source: git + version: "0.7.0-beta.3" flutter_launcher_icons: dependency: "direct main" description: diff --git a/auth/pubspec.yaml b/auth/pubspec.yaml index b4027096be..74c48b251a 100644 --- a/auth/pubspec.yaml +++ b/auth/pubspec.yaml @@ -1,7 +1,7 @@ name: ente_auth description: ente two-factor authenticator -version: 4.3.8+438 +version: 4.4.1+441 publish_to: none environment: @@ -45,7 +45,13 @@ dependencies: flutter_context_menu: ^0.2.0 flutter_displaymode: ^0.6.0 flutter_email_sender: ^6.0.2 - flutter_inappwebview: ^6.1.5 + # revert to pub.dev when merged + # https://github.com/pichillilorenzo/flutter_inappwebview/pull/2548 + flutter_inappwebview: + git: + url: https://github.com/pichillilorenzo/flutter_inappwebview.git + path: flutter_inappwebview + ref: 3e6c4c4a25340cd363af9d38891d88498b90be26 flutter_launcher_icons: ^0.14.1 flutter_local_authentication: git: diff --git a/cli/config.yaml.example b/cli/config.yaml.example index a709e080ed..8a4627d555 100644 --- a/cli/config.yaml.example +++ b/cli/config.yaml.example @@ -5,8 +5,6 @@ endpoint: api: "http://localhost:8080" - # Endpoint for the account service for passkey - accounts: "http://localhost:3001" log: http: false # log status code & time taken by requests diff --git a/cli/internal/api/login_type.go b/cli/internal/api/login_type.go index 951e72fcc1..3980ab9d49 100644 --- a/cli/internal/api/login_type.go +++ b/cli/internal/api/login_type.go @@ -35,6 +35,7 @@ type AuthorizationResponse struct { ID int64 `json:"id"` KeyAttributes *KeyAttributes `json:"keyAttributes,omitempty"` EncryptedToken string `json:"encryptedToken,omitempty"` + AccountsUrl string `json:"accountsUrl"` Token string `json:"token,omitempty"` TwoFactorSessionID string `json:"twoFactorSessionID"` PassKeySessionID string `json:"passkeySessionID"` diff --git a/cli/main.go b/cli/main.go index 15dc6ac5a3..013557d1fb 100644 --- a/cli/main.go +++ b/cli/main.go @@ -110,7 +110,6 @@ func initConfig(cliConfigDir string) { viper.AddConfigPath(".") // optionally look for config in the working directory viper.SetDefault("endpoint.api", constants.EnteApiUrl) - viper.SetDefault("endpoint.accounts", constants.EnteAccountUrl) viper.SetDefault("log.http", false) if err := viper.ReadInConfig(); err != nil { if _, ok := err.(viper.ConfigFileNotFoundError); ok { diff --git a/cli/pkg/sign_in.go b/cli/pkg/sign_in.go index 7fb54738db..26f3db1f0c 100644 --- a/cli/pkg/sign_in.go +++ b/cli/pkg/sign_in.go @@ -8,8 +8,8 @@ import ( eCrypto "github.com/ente-io/cli/internal/crypto" "github.com/ente-io/cli/pkg/model" "github.com/ente-io/cli/utils/browser" + "github.com/ente-io/cli/utils/constants" "github.com/ente-io/cli/utils/encoding" - "github.com/spf13/viper" "log" "github.com/kong/go-srp" @@ -145,7 +145,10 @@ func (c *ClICtrl) verifyPassKey(ctx context.Context, authResp *api.Authorization if !authResp.IsPasskeyRequired() { return authResp, nil } - baseAccountUrl := viper.GetString("endpoint.accounts") + baseAccountUrl := constants.EnteAccountUrl + if authResp.AccountsUrl != "" { + baseAccountUrl = authResp.AccountsUrl + } passkeyAuthUrl := fmt.Sprintf("%s/passkeys/verify?passkeySessionID=%s&redirect=ente-cli://passkey&clientPackage=%s", baseAccountUrl, authResp.PassKeySessionID, app.ClientPkg()) fmt.Printf("Open this url in browser to verify passkey: %s\n", passkeyAuthUrl) err := browser.OpenURL(passkeyAuthUrl) diff --git a/desktop/.github/workflows/desktop-release.yml b/desktop/.github/workflows/desktop-release.yml index fa8c8e53ef..a3b8b38a13 100644 --- a/desktop/.github/workflows/desktop-release.yml +++ b/desktop/.github/workflows/desktop-release.yml @@ -113,6 +113,11 @@ jobs: APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + # Windows Azure Trusted Signing related values + # https://www.electron.build/code-signing-win#using-azure-trusted-signing-beta + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} # Default is "draft", but since our nightly builds update # existing pre-releases, set this to "prerelease". EP_PRE_RELEASE: true diff --git a/desktop/CHANGELOG.md b/desktop/CHANGELOG.md index dc4c1e9b2b..2cff804323 100644 --- a/desktop/CHANGELOG.md +++ b/desktop/CHANGELOG.md @@ -1,6 +1,14 @@ # CHANGELOG -## v1.7.13 (Unreleased) +## v1.7.15 (Unreleased) + +- . + +## v1.7.14 + +- Increase file size limit to 10 GB. + +## v1.7.13 - Generate streams for videos (beta) @@ -8,7 +16,6 @@ > [video streaming FAQ](https://help.ente.io/photos/faq/video-streaming). - Support Turkish translations. -- . ## v1.7.12 diff --git a/desktop/docs/dependencies.md b/desktop/docs/dependencies.md index 3d83b08b00..084355b096 100644 --- a/desktop/docs/dependencies.md +++ b/desktop/docs/dependencies.md @@ -3,6 +3,7 @@ - [Electron](#electron) - [Dev dependencies](#dev) - [Functionality](#functionality) +- [Pinned](#pinned) ## Electron @@ -140,3 +141,24 @@ handles to avoid reopening them for every operation. [chokidar](https://github.com/paulmillr/chokidar) is used as a file system watcher for the watch folders functionality. + +## Pinned + +- `electron-builder` is pinned to 26.0.16 because of + https://github.com/electron-userland/electron-builder/issues/9161#issuecomment-2977829326 + +- `electron-builder` is pinned to 26.0.14 because of a new error when building: + + > Detected file + > "Contents/Resources/app.asar.unpacked/node_modules/onnxruntime-node/bin/napi-v3/darwin/arm64/libonnxruntime.1.20.1.dylib" + > that's the same in both x64 and arm64 builds and not covered by the + > x64ArchFiles rule: "undefined" failedTask=build stackTrace=Error: Detected + > file + > "Contents/Resources/app.asar.unpacked/node_modules/onnxruntime-node/bin/napi-v3/darwin/arm64/libonnxruntime.1.20.1.dylib" + > that's the same in both x64 and arm64 builds and not covered by the + > x64ArchFiles rule: "undefined" + + To reproduce this locally, add `x64ArchFiles: "ffmpeg"` to + `electron-builder.yml`, then run `node_modules/.bin/electron-builder --mac` + +- `electron-store` is pinned to 8.2.0 because subsequent versions are ESM only. diff --git a/desktop/electron-builder.yml b/desktop/electron-builder.yml index 42d152dc4d..0fb94370ae 100644 --- a/desktop/electron-builder.yml +++ b/desktop/electron-builder.yml @@ -14,6 +14,11 @@ win: target: - target: nsis arch: [x64, arm64] + azureSignOptions: + publisherName: ENTE TECHNOLOGIES, INC. + endpoint: https://eus.codesigning.azure.net/ + certificateProfileName: EnteTrustCertProfile + codeSigningAccountName: EnteTechnologiesInc nsis: deleteAppDataOnUninstall: true linux: diff --git a/desktop/package.json b/desktop/package.json index c6ae8b6514..9dc9e4f2e2 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -1,6 +1,6 @@ { "name": "ente", - "version": "1.7.13-beta", + "version": "1.7.15-beta", "private": true, "description": "Desktop client for Ente Photos", "repository": "github:ente-io/photos-desktop", @@ -31,33 +31,32 @@ "clip-bpe-js": "^0.0.6", "comlink": "^4.4.2", "compare-versions": "^6.1.1", - "electron-log": "^5.4.0", + "electron-log": "^5.4.1", "electron-store": "^8.2.0", - "electron-updater": "^6.6.3", + "electron-updater": "^6.6.5", "ffmpeg-static": "^5.2.0", "lru-cache": "^11.1.0", "next-electron-server": "^1.0.0", "node-stream-zip": "^1.15.0", "onnxruntime-node": "^1.20.1", - "zod": "^3.25.23" + "zod": "^3.25.67" }, "devDependencies": { - "@eslint/js": "^9.27.0", + "@eslint/js": "^9.29.0", "@tsconfig/node22": "^22.0.2", "@types/auto-launch": "^5.0.5", - "@types/ffmpeg-static": "^3.0.3", "ajv": "^8.17.1", "concurrently": "^9.1.2", "cross-env": "^7.0.3", - "electron": "^36.3.1", - "electron-builder": "^26.0.14", + "electron": "^37.1.0", + "electron-builder": "26.0.14", "eslint": "^9", "prettier": "3.5.3", "prettier-plugin-organize-imports": "^4.1.0", - "prettier-plugin-packagejson": "^2.5.14", + "prettier-plugin-packagejson": "^2.5.15", "shx": "^0.4.0", "typescript": "^5.8.3", - "typescript-eslint": "^8.32.1" + "typescript-eslint": "^8.34.1" }, "packageManager": "yarn@1.22.22", "productName": "ente" diff --git a/desktop/src/main.ts b/desktop/src/main.ts index 687d8b11d6..dd6cab4a18 100644 --- a/desktop/src/main.ts +++ b/desktop/src/main.ts @@ -78,14 +78,6 @@ export const allowWindowClose = (): void => { * We call this at the end of this file. */ const main = () => { - // Workaround for Electron 36 not launching on some Linux distros. Remove - // once fixed or otherwise mitigated upstream. - // - // https://github.com/electron/electron/issues/46538#issuecomment-2808806722 - if (process.platform == "linux") { - app.commandLine.appendSwitch("gtk-version", "3"); - } - const gotTheLock = app.requestSingleInstanceLock(); if (!gotTheLock) { app.quit(); diff --git a/desktop/src/main/ipc.ts b/desktop/src/main/ipc.ts index b4e7eff0ca..ce977a5088 100644 --- a/desktop/src/main/ipc.ts +++ b/desktop/src/main/ipc.ts @@ -50,8 +50,8 @@ import { convertToJPEG, generateImageThumbnail } from "./services/image"; import { logout } from "./services/logout"; import { lastShownChangelogVersion, - masterKeyB64, - saveMasterKeyB64, + masterKeyFromSafeStorage, + saveMasterKeyInSafeStorage, setLastShownChangelogVersion, } from "./services/store"; import { @@ -108,10 +108,12 @@ export const attachIPCHandlers = () => { ipcMain.handle("selectDirectory", () => selectDirectory()); - ipcMain.handle("masterKeyB64", () => masterKeyB64()); + ipcMain.handle("masterKeyFromSafeStorage", () => + masterKeyFromSafeStorage(), + ); - ipcMain.handle("saveMasterKeyB64", (_, masterKeyB64: string) => - saveMasterKeyB64(masterKeyB64), + ipcMain.handle("saveMasterKeyInSafeStorage", (_, masterKey: string) => + saveMasterKeyInSafeStorage(masterKey), ); ipcMain.handle("lastShownChangelogVersion", () => diff --git a/desktop/src/main/services/ffmpeg-worker.ts b/desktop/src/main/services/ffmpeg-worker.ts index 9b590127af..b63abcf023 100644 --- a/desktop/src/main/services/ffmpeg-worker.ts +++ b/desktop/src/main/services/ffmpeg-worker.ts @@ -12,7 +12,7 @@ import fs_ from "node:fs"; import fs from "node:fs/promises"; import path from "node:path"; import { Readable } from "node:stream"; -import { z } from "zod"; +import { z } from "zod/v4"; import type { FFmpegCommand } from "../../types/ipc"; import log from "../log-worker"; import { messagePortMainEndpoint } from "../utils/comlink"; @@ -832,7 +832,8 @@ const pseudoFFProbeVideo = async (inputFilePath: string) => { * Upload the file at the given {@link videoFilePath} to the provided pre-signed * URL(s) using a HTTP PUT request. * - * All HTTP requests are retried up to 3 times with exponential backoff. + * All HTTP requests are retried up to 4 times (1 original + 3 retries) with + * exponential backoff. * * See: [Note: Upload HLS video segment from node side]. * @@ -977,19 +978,19 @@ const uploadVideoSegmentsSingle = ( ); /** - * Retry a async operation on failure up to 3 times (1 original + 2 retries) + * Retry a async operation on failure up to 4 times (1 original + 3 retries) * with exponential backoff. * - * This is an inlined but bespoke reimplementation of `retryEnsuringHTTPOk` - * from `web/packages/base/http.ts` + * This is an inlined but bespoke reimplementation of `retryEnsuringHTTPOk` from + * `web/packages/base/http.ts` * * - We don't have the rest of the scaffolding used by that function, which is * why it is intially inlined bespoked. * * - It handles the specific use case of uploading videos since generating the * HLS stream is a fairly expensive operation, so a retry to discount - * transient network issues is called for. There are only 2 retries for a - * total of 3 attempts, and the retry gaps are more spaced out. + * transient network issues is called for. The number of retries and their + * gaps are same as the "background" `retryProfile` of the web implementation. * * - Later it was discovered that net.fetch is much slower than node's native * fetch, so this implementation has further diverged. @@ -998,7 +999,7 @@ const uploadVideoSegmentsSingle = ( * ability to import electron API. */ const retryEnsuringHTTPOk = async (request: () => Promise) => { - const waitTimeBeforeNextTry = [10000, 30000]; + const waitTimeBeforeNextTry = [10000, 30000, 120000]; while (true) { try { diff --git a/desktop/src/main/services/ml-worker.ts b/desktop/src/main/services/ml-worker.ts index 234c3abb23..22fad4ec1c 100644 --- a/desktop/src/main/services/ml-worker.ts +++ b/desktop/src/main/services/ml-worker.ts @@ -15,7 +15,7 @@ import { existsSync } from "fs"; import fs from "node:fs/promises"; import path from "node:path"; import * as ort from "onnxruntime-node"; -import { z } from "zod"; +import { z } from "zod/v4"; import log from "../log-worker"; import { messagePortMainEndpoint } from "../utils/comlink"; import { wait } from "../utils/common"; @@ -184,14 +184,13 @@ const downloadModel = async (saveLocation: string, name: string) => { /** * Create an ONNX {@link InferenceSession} with some defaults. */ -const createInferenceSession = async (modelPath: string) => { - return await ort.InferenceSession.create(modelPath, { +const createInferenceSession = (modelPath: string) => + ort.InferenceSession.create(modelPath, { // Restrict the number of threads to 1. intraOpNumThreads: 1, // Be more conservative with RAM usage. enableCpuMemArena: false, }); -}; const cachedCLIPImageSession = makeCachedInferenceSession( "mobileclip_s2_image_opset18_rgba_opt.onnx", @@ -233,9 +232,11 @@ const getTokenizer = () => (_tokenizer ??= new Tokenizer()); export const computeCLIPTextEmbeddingIfAvailable = async (text: string) => { const sessionOrSkip = await Promise.race([ cachedCLIPTextSession(), - // Wait for a tick to get the session promise to resolved the first time - // this code runs on each app start (and the model has been downloaded). - wait(0).then(() => 1), + // Wait a bit to get the session promise to resolved the first time this + // code runs on each app start (in these cases the model will already be + // downloaded, so session creation should take only a 1 or 2 ticks: file + // system stat, and ort.InferenceSession.create). + wait(50).then(() => 1), ]); // Don't wait for the download to complete. diff --git a/desktop/src/main/services/store.ts b/desktop/src/main/services/store.ts index f4f5a9369a..227fe691c6 100644 --- a/desktop/src/main/services/store.ts +++ b/desktop/src/main/services/store.ts @@ -24,17 +24,17 @@ export const clearStores = () => { * On macOS, `safeStorage` stores our data under a Keychain entry named * " Safe Storage". In our case, "ente Safe Storage". */ -export const saveMasterKeyB64 = (masterKeyB64: string) => { - const encryptedKey = safeStorage.encryptString(masterKeyB64); - const b64EncryptedKey = Buffer.from(encryptedKey).toString("base64"); - safeStorageStore.set("encryptionKey", b64EncryptedKey); +export const saveMasterKeyInSafeStorage = (masterKey: string) => { + const encryptedKeyBuffer = safeStorage.encryptString(masterKey); + const encryptedKey = Buffer.from(encryptedKeyBuffer).toString("base64"); + safeStorageStore.set("encryptionKey", encryptedKey); }; -export const masterKeyB64 = (): string | undefined => { - const b64EncryptedKey = safeStorageStore.get("encryptionKey"); - if (!b64EncryptedKey) return undefined; - const keyBuffer = Buffer.from(b64EncryptedKey, "base64"); - return safeStorage.decryptString(keyBuffer); +export const masterKeyFromSafeStorage = (): string | undefined => { + const encryptedKey = safeStorageStore.get("encryptionKey"); + if (!encryptedKey) return undefined; + const encryptedKeyBuffer = Buffer.from(encryptedKey, "base64"); + return safeStorage.decryptString(encryptedKeyBuffer); }; export const lastShownChangelogVersion = (): number | undefined => diff --git a/desktop/src/main/services/watch.ts b/desktop/src/main/services/watch.ts index 6f198c513b..4066a91c89 100644 --- a/desktop/src/main/services/watch.ts +++ b/desktop/src/main/services/watch.ts @@ -28,6 +28,13 @@ export const createWatcher = (mainWindow: BrowserWindow) => { // Ask the watcher to wait for a the file size to stabilize before // telling us about a new file. By default, it waits for 2 seconds. awaitWriteFinish: true, + // On macOS we start getting "EMFILE: too many open files" when watching + // large folders. This is a known regression in Chokidar v4: + // https://github.com/paulmillr/chokidar/issues/1385 + // + // The recommended workaround for now is to enable usePolling. Since it + // comes at a performance cost, we only do it where needed (macOS). + ...(process.platform == "darwin" ? { usePolling: true } : {}), }); watcher diff --git a/desktop/src/preload.ts b/desktop/src/preload.ts index e983855d5f..ea6a7af7b2 100644 --- a/desktop/src/preload.ts +++ b/desktop/src/preload.ts @@ -113,10 +113,11 @@ const logout = () => { return ipcRenderer.invoke("logout"); }; -const masterKeyB64 = () => ipcRenderer.invoke("masterKeyB64"); +const masterKeyFromSafeStorage = () => + ipcRenderer.invoke("masterKeyFromSafeStorage"); -const saveMasterKeyB64 = (masterKeyB64: string) => - ipcRenderer.invoke("saveMasterKeyB64", masterKeyB64); +const saveMasterKeyInSafeStorage = (masterKey: string) => + ipcRenderer.invoke("saveMasterKeyInSafeStorage", masterKey); const lastShownChangelogVersion = () => ipcRenderer.invoke("lastShownChangelogVersion"); @@ -358,8 +359,8 @@ contextBridge.exposeInMainWorld("electron", { selectDirectory, pathForFile, logout, - masterKeyB64, - saveMasterKeyB64, + masterKeyFromSafeStorage, + saveMasterKeyInSafeStorage, lastShownChangelogVersion, setLastShownChangelogVersion, isAutoLaunchEnabled, diff --git a/desktop/yarn.lock b/desktop/yarn.lock index 46c10414e6..31526c6dd5 100644 --- a/desktop/yarn.lock +++ b/desktop/yarn.lock @@ -25,7 +25,7 @@ ajv "^6.12.0" ajv-keywords "^3.4.1" -"@electron/asar@3.4.1": +"@electron/asar@3.4.1", "@electron/asar@^3.2.7": version "3.4.1" resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.4.1.tgz#4e9196a4b54fba18c56cd8d5cac67c5bdc588065" integrity sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA== @@ -34,15 +34,6 @@ glob "^7.1.6" minimatch "^3.0.4" -"@electron/asar@^3.2.7": - version "3.2.18" - resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.2.18.tgz#fa607f829209bab8b9e0ce6658d3fe81b2cba517" - integrity sha512-2XyvMe3N3Nrs8cV39IKELRHTYUWFKrmqqSY1U+GMlc0jvqjIVnoxhNd2H4JolWQncbJi1DCvb5TNxZuI2fEjWg== - dependencies: - commander "^5.0.0" - glob "^7.1.6" - minimatch "^3.0.4" - "@electron/fuses@^1.8.0": version "1.8.0" resolved "https://registry.yarnpkg.com/@electron/fuses/-/fuses-1.8.0.tgz#ad34d3cc4703b1258b83f6989917052cfc1490a0" @@ -184,10 +175,10 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.9.1.tgz#4a97e85e982099d6c7ee8410aacb55adaa576f06" integrity sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ== -"@eslint/js@^9.27.0": - version "9.27.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.27.0.tgz#181a23460877c484f6dd03890f4e3fa2fdeb8ff0" - integrity sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA== +"@eslint/js@^9.29.0": + version "9.29.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.29.0.tgz#dc6fd117c19825f8430867a662531da36320fe56" + integrity sha512-3PIF4cBw/y+1u2EazflInpV+lYsSG0aByVIQzAgb1m1MhHFSbqTyNqtBKHgWf/9Ykud+DhILS9EGkmekVhbKoQ== "@eslint/object-schema@^2.1.4": version "2.1.4" @@ -209,6 +200,18 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.0.tgz#6d86b8cb322660f03d3f0aa94b99bdd8e172d570" integrity sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew== +"@isaacs/balanced-match@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz#3081dadbc3460661b751e7591d7faea5df39dd29" + integrity sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ== + +"@isaacs/brace-expansion@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz#4b3dabab7d8e75a429414a96bd67bf4c1d13e0f3" + integrity sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA== + dependencies: + "@isaacs/balanced-match" "^4.0.1" + "@isaacs/fs-minipass@^4.0.0": version "4.0.1" resolved "https://registry.yarnpkg.com/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz#2d59ae3ab4b38fb4270bfa23d30f8e2e86c7fe32" @@ -324,11 +327,6 @@ dependencies: "@types/ms" "*" -"@types/ffmpeg-static@^3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/ffmpeg-static/-/ffmpeg-static-3.0.3.tgz#605358ac6304507a75c2fd5fd861534837b19e2f" - integrity sha512-wmjANN0CiYs5clQESK+xE6plet0y9ndqaNBdQx4IIw7ZbPBMQw+14Lq4ky2WqMqGlpFJ9ZUxU0O43TvVZziyyA== - "@types/fs-extra@9.0.13", "@types/fs-extra@^9.0.11": version "9.0.13" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.13.tgz#7594fbae04fe7f1918ce8b3d213f74ff44ac1f45" @@ -392,62 +390,78 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@8.32.1": - version "8.32.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.1.tgz#9185b3eaa3b083d8318910e12d56c68b3c4f45b4" - integrity sha512-6u6Plg9nP/J1GRpe/vcjjabo6Uc5YQPAMxsgQyGC/I0RuukiG1wIe3+Vtg3IrSCVJDmqK3j8adrtzXSENRtFgg== +"@typescript-eslint/eslint-plugin@8.34.1": + version "8.34.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.1.tgz#56cf35b89383eaf2bdcf602f5bbdac6dbb11e51b" + integrity sha512-STXcN6ebF6li4PxwNeFnqF8/2BNDvBupf2OPx2yWNzr6mKNGF7q49VM00Pz5FaomJyqvbXpY6PhO+T9w139YEQ== dependencies: "@eslint-community/regexpp" "^4.10.0" - "@typescript-eslint/scope-manager" "8.32.1" - "@typescript-eslint/type-utils" "8.32.1" - "@typescript-eslint/utils" "8.32.1" - "@typescript-eslint/visitor-keys" "8.32.1" + "@typescript-eslint/scope-manager" "8.34.1" + "@typescript-eslint/type-utils" "8.34.1" + "@typescript-eslint/utils" "8.34.1" + "@typescript-eslint/visitor-keys" "8.34.1" graphemer "^1.4.0" ignore "^7.0.0" natural-compare "^1.4.0" ts-api-utils "^2.1.0" -"@typescript-eslint/parser@8.32.1": - version "8.32.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.32.1.tgz#18b0e53315e0bc22b2619d398ae49a968370935e" - integrity sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg== +"@typescript-eslint/parser@8.34.1": + version "8.34.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.34.1.tgz#f102357ab3a02d5b8aa789655905662cc5093067" + integrity sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA== dependencies: - "@typescript-eslint/scope-manager" "8.32.1" - "@typescript-eslint/types" "8.32.1" - "@typescript-eslint/typescript-estree" "8.32.1" - "@typescript-eslint/visitor-keys" "8.32.1" + "@typescript-eslint/scope-manager" "8.34.1" + "@typescript-eslint/types" "8.34.1" + "@typescript-eslint/typescript-estree" "8.34.1" + "@typescript-eslint/visitor-keys" "8.34.1" debug "^4.3.4" -"@typescript-eslint/scope-manager@8.32.1": - version "8.32.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.32.1.tgz#9a6bf5fb2c5380e14fe9d38ccac6e4bbe17e8afc" - integrity sha512-7IsIaIDeZn7kffk7qXC3o6Z4UblZJKV3UBpkvRNpr5NSyLji7tvTcvmnMNYuYLyh26mN8W723xpo3i4MlD33vA== +"@typescript-eslint/project-service@8.34.1": + version "8.34.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.34.1.tgz#20501f8b87202c45f5e70a5b24dcdcb8fe12d460" + integrity sha512-nuHlOmFZfuRwLJKDGQOVc0xnQrAmuq1Mj/ISou5044y1ajGNp2BNliIqp7F2LPQ5sForz8lempMFCovfeS1XoA== dependencies: - "@typescript-eslint/types" "8.32.1" - "@typescript-eslint/visitor-keys" "8.32.1" + "@typescript-eslint/tsconfig-utils" "^8.34.1" + "@typescript-eslint/types" "^8.34.1" + debug "^4.3.4" -"@typescript-eslint/type-utils@8.32.1": - version "8.32.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.32.1.tgz#b9292a45f69ecdb7db74d1696e57d1a89514d21e" - integrity sha512-mv9YpQGA8iIsl5KyUPi+FGLm7+bA4fgXaeRcFKRDRwDMu4iwrSHeDPipwueNXhdIIZltwCJv+NkxftECbIZWfA== +"@typescript-eslint/scope-manager@8.34.1": + version "8.34.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.34.1.tgz#727ea43441f4d23d5c73d34195427d85042e5117" + integrity sha512-beu6o6QY4hJAgL1E8RaXNC071G4Kso2MGmJskCFQhRhg8VOH/FDbC8soP8NHN7e/Hdphwp8G8cE6OBzC8o41ZA== dependencies: - "@typescript-eslint/typescript-estree" "8.32.1" - "@typescript-eslint/utils" "8.32.1" + "@typescript-eslint/types" "8.34.1" + "@typescript-eslint/visitor-keys" "8.34.1" + +"@typescript-eslint/tsconfig-utils@8.34.1", "@typescript-eslint/tsconfig-utils@^8.34.1": + version "8.34.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.1.tgz#d6abb1b1e9f1f1c83ac92051c8fbf2dbc4dc9f5e" + integrity sha512-K4Sjdo4/xF9NEeA2khOb7Y5nY6NSXBnod87uniVYW9kHP+hNlDV8trUSFeynA2uxWam4gIWgWoygPrv9VMWrYg== + +"@typescript-eslint/type-utils@8.34.1": + version "8.34.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.34.1.tgz#df860d8edefbfe142473ea4defb7408edb0c379e" + integrity sha512-Tv7tCCr6e5m8hP4+xFugcrwTOucB8lshffJ6zf1mF1TbU67R+ntCc6DzLNKM+s/uzDyv8gLq7tufaAhIBYeV8g== + dependencies: + "@typescript-eslint/typescript-estree" "8.34.1" + "@typescript-eslint/utils" "8.34.1" debug "^4.3.4" ts-api-utils "^2.1.0" -"@typescript-eslint/types@8.32.1": - version "8.32.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.32.1.tgz#b19fe4ac0dc08317bae0ce9ec1168123576c1d4b" - integrity sha512-YmybwXUJcgGqgAp6bEsgpPXEg6dcCyPyCSr0CAAueacR/CCBi25G3V8gGQ2kRzQRBNol7VQknxMs9HvVa9Rvfg== +"@typescript-eslint/types@8.34.1", "@typescript-eslint/types@^8.34.1": + version "8.34.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.34.1.tgz#565a46a251580dae674dac5aafa8eb14b8322a35" + integrity sha512-rjLVbmE7HR18kDsjNIZQHxmv9RZwlgzavryL5Lnj2ujIRTeXlKtILHgRNmQ3j4daw7zd+mQgy+uyt6Zo6I0IGA== -"@typescript-eslint/typescript-estree@8.32.1": - version "8.32.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.1.tgz#9023720ca4ecf4f59c275a05b5fed69b1276face" - integrity sha512-Y3AP9EIfYwBb4kWGb+simvPaqQoT5oJuzzj9m0i6FCY6SPvlomY2Ei4UEMm7+FXtlNJbor80ximyslzaQF6xhg== +"@typescript-eslint/typescript-estree@8.34.1": + version "8.34.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.1.tgz#befdb042a6bc44fdad27429b2d3b679c80daad71" + integrity sha512-rjCNqqYPuMUF5ODD+hWBNmOitjBWghkGKJg6hiCHzUvXRy6rK22Jd3rwbP2Xi+R7oYVvIKhokHVhH41BxPV5mA== dependencies: - "@typescript-eslint/types" "8.32.1" - "@typescript-eslint/visitor-keys" "8.32.1" + "@typescript-eslint/project-service" "8.34.1" + "@typescript-eslint/tsconfig-utils" "8.34.1" + "@typescript-eslint/types" "8.34.1" + "@typescript-eslint/visitor-keys" "8.34.1" debug "^4.3.4" fast-glob "^3.3.2" is-glob "^4.0.3" @@ -455,23 +469,23 @@ semver "^7.6.0" ts-api-utils "^2.1.0" -"@typescript-eslint/utils@8.32.1": - version "8.32.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.32.1.tgz#4d6d5d29b9e519e9a85e9a74e9f7bdb58abe9704" - integrity sha512-DsSFNIgLSrc89gpq1LJB7Hm1YpuhK086DRDJSNrewcGvYloWW1vZLHBTIvarKZDcAORIy/uWNx8Gad+4oMpkSA== +"@typescript-eslint/utils@8.34.1": + version "8.34.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.34.1.tgz#f98c9b0c5cae407e34f5131cac0f3a74347a398e" + integrity sha512-mqOwUdZ3KjtGk7xJJnLbHxTuWVn3GO2WZZuM+Slhkun4+qthLdXx32C8xIXbO1kfCECb3jIs3eoxK3eryk7aoQ== dependencies: "@eslint-community/eslint-utils" "^4.7.0" - "@typescript-eslint/scope-manager" "8.32.1" - "@typescript-eslint/types" "8.32.1" - "@typescript-eslint/typescript-estree" "8.32.1" + "@typescript-eslint/scope-manager" "8.34.1" + "@typescript-eslint/types" "8.34.1" + "@typescript-eslint/typescript-estree" "8.34.1" -"@typescript-eslint/visitor-keys@8.32.1": - version "8.32.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.1.tgz#4321395cc55c2eb46036cbbb03e101994d11ddca" - integrity sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w== +"@typescript-eslint/visitor-keys@8.34.1": + version "8.34.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.1.tgz#28a1987ea3542ccafb92aa792726a304b39531cf" + integrity sha512-xoh5rJ+tgsRKoXnkBPFRLZ7rjKM0AfVbC68UZ/ECXoDbfggb9RbEySN359acY1vS3qZ0jVTVWzbtfapwm5ztxw== dependencies: - "@typescript-eslint/types" "8.32.1" - eslint-visitor-keys "^4.2.0" + "@typescript-eslint/types" "8.34.1" + eslint-visitor-keys "^4.2.1" "@xmldom/xmldom@^0.8.8": version "0.8.10" @@ -1177,7 +1191,7 @@ ejs@^3.1.8: dependencies: jake "^10.8.5" -electron-builder@^26.0.14: +electron-builder@26.0.14: version "26.0.14" resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-26.0.14.tgz#8927c6da42a69425d15e08f351e944ea0e7866da" integrity sha512-YBxpWLMGj0oS7fbS3LVingeZqFunU0F8s+uB9QTd5+wN4qgrf/rSGRkqoImbWg2+F2yHq11wmaA/Xr9xzvgQ0w== @@ -1193,10 +1207,10 @@ electron-builder@^26.0.14: simple-update-notifier "2.0.0" yargs "^17.6.2" -electron-log@^5.4.0: - version "5.4.0" - resolved "https://registry.yarnpkg.com/electron-log/-/electron-log-5.4.0.tgz#3180bf5194b2e2efacb62ec1392f8150faf4de6b" - integrity sha512-AXI5OVppskrWxEAmCxuv8ovX+s2Br39CpCAgkGMNHQtjYT3IiVbSQTncEjFVGPgoH35ZygRm/mvUMBDWwhRxgg== +electron-log@^5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/electron-log/-/electron-log-5.4.1.tgz#700ddc6ef4b06c13a983468580ba7a7e579129d4" + integrity sha512-QvisA18Z++8E3Th0zmhUelys9dEv7aIeXJlbFw3UrxCc8H9qSRW0j8/ooTef/EtHui8tVmbKSL+EIQzP9GoRLg== electron-publish@26.0.13: version "26.0.13" @@ -1220,10 +1234,10 @@ electron-store@^8.2.0: conf "^10.2.0" type-fest "^2.17.0" -electron-updater@^6.6.3: - version "6.6.3" - resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-6.6.3.tgz#a1f53671ffbb08a475d495d48f0c0d971e665d5d" - integrity sha512-i448/SwMtqxy5wqAcXScnWjiFxZp+hmWA2jZCmojcdfodEGhi/DWTdRP01mE3lCILb8hmdE28SBaHf1oQW3+kw== +electron-updater@^6.6.5: + version "6.6.5" + resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-6.6.5.tgz#6614daa2f737c294471eee7ce7b61deda0d5543a" + integrity sha512-jnk38WfByl2Pb0cje02xls/pJkvkq3AQZI7usDCLriU23adkerLTkRrugbCPuUxUOa79nY1g/rokHPWHZFBKyA== dependencies: builder-util-runtime "9.3.2" fs-extra "^10.1.0" @@ -1234,10 +1248,10 @@ electron-updater@^6.6.3: semver "^7.6.3" tiny-typed-emitter "^2.1.0" -electron@^36.3.1: - version "36.3.1" - resolved "https://registry.yarnpkg.com/electron/-/electron-36.3.1.tgz#12a8c1b1cd9163a4bd0cb60f89816243b26ab788" - integrity sha512-LeOZ+tVahmctHaAssLCGRRUa2SAO09GXua3pKdG+WzkbSDMh+3iOPONNVPTqGp8HlWnzGj4r6mhsIbM2RgH+eQ== +electron@^37.1.0: + version "37.1.0" + resolved "https://registry.yarnpkg.com/electron/-/electron-37.1.0.tgz#6d6d1891f8add5d2d44007e2ee5d4542140fc4b4" + integrity sha512-Fcr3yfAw4oU392waVZSlrFUQx4P+h/k31+PRgkBY9tFx9E/zxzdPQQj0achZlG1HRDusw3ooQB+OXb9PvufdzA== dependencies: "@electron/get" "^2.0.0" "@types/node" "^22.7.7" @@ -1312,11 +1326,16 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint-visitor-keys@^4.0.0, eslint-visitor-keys@^4.2.0: +eslint-visitor-keys@^4.0.0: version "4.2.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45" integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw== +eslint-visitor-keys@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz#4cfea60fe7dd0ad8e816e1ed026c1d5251b512c1" + integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== + eslint@^9: version "9.9.1" resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.9.1.tgz#147ac9305d56696fb84cf5bdecafd6517ddc77ec" @@ -2260,11 +2279,11 @@ mimic-response@^3.1.0: integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== minimatch@^10.0.0: - version "10.0.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.1.tgz#ce0521856b453c86e25f2c4c0d03e6ff7ddc440b" - integrity sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ== + version "10.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.3.tgz#cf7a0314a16c4d9ab73a7730a0e8e3c3502d47aa" + integrity sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw== dependencies: - brace-expansion "^2.0.1" + "@isaacs/brace-expansion" "^5.0.0" minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" @@ -2664,13 +2683,13 @@ prettier-plugin-organize-imports@^4.1.0: resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz#f3d3764046a8e7ba6491431158b9be6ffd83b90f" integrity sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A== -prettier-plugin-packagejson@^2.5.14: - version "2.5.14" - resolved "https://registry.yarnpkg.com/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.14.tgz#8ada09114ff60c7f42c3f8755ffb2f8152f3624f" - integrity sha512-h+3tSpr2nVpp+YOK1MDIYtYhHVXr8/0V59UUbJpIJFaqi3w4fvUokJo6eV8W+vELrUXIZzJ+DKm5G7lYzrMcKQ== +prettier-plugin-packagejson@^2.5.15: + version "2.5.15" + resolved "https://registry.yarnpkg.com/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.15.tgz#7ea880d4bb1681b5331ea7044efd3d653776f469" + integrity sha512-2QSx6y4IT6LTwXtCvXAopENW5IP/aujC8fobEM2pDbs0IGkiVjW/ipPuYAHuXigbNe64aGWF7vIetukuzM3CBw== dependencies: sort-package-json "3.2.1" - synckit "0.11.6" + synckit "0.11.8" prettier@3.5.3: version "3.5.3" @@ -3108,10 +3127,10 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -synckit@0.11.6: - version "0.11.6" - resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.6.tgz#e742a0c27bbc1fbc96f2010770521015cca7ed5c" - integrity sha512-2pR2ubZSV64f/vqm9eLPz/KOvR9Dm+Co/5ChLgeHl0yEDRc6h5hXHoxEQH8Y5Ljycozd3p1k5TTSVdzYGkPvLw== +synckit@0.11.8: + version "0.11.8" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.8.tgz#b2aaae998a4ef47ded60773ad06e7cb821f55457" + integrity sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A== dependencies: "@pkgr/core" "^0.2.4" @@ -3235,14 +3254,14 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== -typescript-eslint@^8.32.1: - version "8.32.1" - resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.32.1.tgz#1784335c781491be528ff84ab666e2f0f7591fd1" - integrity sha512-D7el+eaDHAmXvrZBy1zpzSNIRqnCOrkwTgZxTu3MUqRWk8k0q9m9Ho4+vPf7iHtgUfrK/o8IZaEApsxPlHTFCg== +typescript-eslint@^8.34.1: + version "8.34.1" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.34.1.tgz#4bab64b298531b9f6f3ff59b41a7161321ef8cd6" + integrity sha512-XjS+b6Vg9oT1BaIUfkW3M3LvqZE++rbzAMEHuccCfO/YkP43ha6w3jTEMilQxMF92nVOYCcdjv1ZUhAa1D/0ow== dependencies: - "@typescript-eslint/eslint-plugin" "8.32.1" - "@typescript-eslint/parser" "8.32.1" - "@typescript-eslint/utils" "8.32.1" + "@typescript-eslint/eslint-plugin" "8.34.1" + "@typescript-eslint/parser" "8.34.1" + "@typescript-eslint/utils" "8.34.1" typescript@^5.4.3, typescript@^5.8.3: version "5.8.3" @@ -3405,7 +3424,7 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -zod@^3.25.23: - version "3.25.23" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.23.tgz#128fb02f3619a8bca6bbbf6b07b457236cf33391" - integrity sha512-Od2bdMosahjSrSgJtakrwjMDb1zM1A3VIHCPGveZt/3/wlrTWBya2lmEh2OYe4OIu8mPTmmr0gnLHIWQXdtWBg== +zod@^3.25.67: + version "3.25.67" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.67.tgz#62987e4078e2ab0f63b491ef0c4f33df24236da8" + integrity sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw== diff --git a/docs/docs/.vitepress/config.ts b/docs/docs/.vitepress/config.ts index a2df3c23a1..4914ab6251 100644 --- a/docs/docs/.vitepress/config.ts +++ b/docs/docs/.vitepress/config.ts @@ -8,13 +8,6 @@ export default defineConfig({ head: [["link", { rel: "icon", type: "image/png", href: "/favicon.png" }]], cleanUrls: true, ignoreDeadLinks: "localhostLinks", - vite: { - build: { - rollupOptions: { - external: ['client-museum-s3.png'] // Added to handle static asset import - } - } - }, themeConfig: { // We use the default theme (with some CSS color overrides). This // themeConfig block can be used to further customize the default theme. diff --git a/docs/docs/.vitepress/sidebar.ts b/docs/docs/.vitepress/sidebar.ts index 0a81c8efc6..a90caad19b 100644 --- a/docs/docs/.vitepress/sidebar.ts +++ b/docs/docs/.vitepress/sidebar.ts @@ -52,6 +52,10 @@ export const sidebar = [ link: "/photos/features/machine-learning", }, { text: "Map", link: "/photos/features/map" }, + { + text: "Notifications", + link: "/photos/features/notifications", + }, { text: "Passkeys", link: "/photos/features/passkeys", @@ -292,7 +296,7 @@ export const sidebar = [ }, { text: "Bucket CORS", - link: '/self-hosting/troubleshooting/bucket-cors' + link: "/self-hosting/troubleshooting/bucket-cors", }, { text: "Uploads", @@ -311,16 +315,16 @@ export const sidebar = [ { text: "Community Guides", collapsed: true, - items :[ + items: [ { text: "Ente via Tailscale", - link: "/self-hosting/guides/Tailscale", + link: "/self-hosting/guides/tailscale", }, { text: "Ente with External S3", link: "/self-hosting/guides/external-s3", - } - ] + }, + ], }, { text: "FAQ", @@ -347,12 +351,4 @@ export const sidebar = [ }, ], }, - { - text: "About", - link: "/about/", - }, - { - text: "Contribute", - link: "/about/contribute", - }, ]; diff --git a/docs/docs/about/contribute.md b/docs/docs/about/contribute.md deleted file mode 100644 index 3addd2e606..0000000000 --- a/docs/docs/about/contribute.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: Contribute -description: Details about how to contribute to Ente's docs ---- - -# Contributing - -To contribute to these docs, you can use the "Edit this page" button at the -bottom of each page. This will allow you to directly edit the markdown file that -is used to generate this documentation and open a quick pull request directly -from GitHub's UI. - -If you're more comfortable in contributing with your text editor, see the -`docs/` folder of our GitHub repository, -[github.com/ente-io/ente](https://github.com/ente-io/ente). diff --git a/docs/docs/about/index.md b/docs/docs/about/index.md deleted file mode 100644 index 18455f6b5a..0000000000 --- a/docs/docs/about/index.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: About Ente -description: > - An overview of Ente: the company, and the people behind it, and the products - that we make. ---- - -# About - -Ente is a end-to-end encrypted platform for privately, reliably, and securely -storing your data on the cloud. On top of this platform, Ente offers two -products: - -- **Ente Photos** - An alternative to Google Photos and Apple Photos - -- **Ente Auth** - A free 2FA alternative to Authy - -Both these apps are available for all desktop (Linux, Mac, Windows) and mobile -(Android, iOS and F-Droid) platforms. They also work directly in your web -browser without you needing to install anything. - -More products are in the pipeline. - -## History - -Ente was the founded by Vishnu Mohandas (he's also Ente's CEO) in response to -privacy concerns with major tech companies. The underlying motivation was the -understanding that big tech had no incentive to fix their act, but with -end-to-end encrypted cross platform apps, there was a way for people to take -back control over their own data without sacrificing on features. - -### What does Ente mean? - -In Malayalam, Vishnu's native language, "ente" means "mine". Thus "Ente Photos" -has the literal meaning "my photos". - -This was a good name, but still Vishnu looked around for better ones. But one -day, he discovered that "ente" means "duck" in German. This unexpected -connection sealed the deal. We should ask him why he likes ducks so much, but -apparently he does, so this dual meaning ("mine" / "duck") led him to finalize -the name, and also led to the adoption of "Ducky", Ente's mascot: - -
- -![Ente's mascot, Ducky](ducky.png){width=200px} - -
- -For the full origin story of Ducky you can check out -[this blog post](https://ente.io/blog/ducky/). - -### How do I pronounce Ente? - -en-_tay_. Like cafe. - -## Get in touch - -If you have a support query that is not answered by these docs, please reach out -to our Customer Support by sending an email to support@ente.io - -To stay up to date with new product launches, and behind the scenes details of -how we're building Ente, you can read our [blog](https://ente.io/blog) (or -subscribe to it via [RSS](https://ente.io/blog/rss.xml)) - -To suggest new features and/or offer your perspective on how we should design -planned and upcoming features, use our -[GitHub discussions](https://github.com/ente-io/ente/discussions) - -Or if you'd just like to hang out, join our -[Discord](https://discord.gg/z2YVKkycX3), follow us on -[Twitter](https://twitter.com/enteio) or give us a shout out on -[Mastodon](https://mstdn.social/@ente) diff --git a/docs/docs/auth/faq/index.md b/docs/docs/auth/faq/index.md index 5e631906aa..b731fa573e 100644 --- a/docs/docs/auth/faq/index.md +++ b/docs/docs/auth/faq/index.md @@ -41,6 +41,16 @@ Usually, this discrepancy occurs because the time in your browser might be incorrect. In particular, multiple users have reported that Firefox provides incorrect time when certain privacy settings are enabled. +> [!TIP] +> +> Newer Ente Auth clients (upcoming 4.4.0+) will automatically try to correct +> for incorrect system time, so you should be seeing correct codes even if your +> system time is out of sync. However, this automatic correction will not work +> if you're using Ente Auth in offline mode. +> +> If you've recently changed your system time and the codes are still incorrect, +> try to refresh / restart the app if needed. + ### Can I access my codes on web? You can access your codes on the web at [auth.ente.io](https://auth.ente.io). diff --git a/docs/docs/auth/migration-guides/authy/index.md b/docs/docs/auth/migration-guides/authy/index.md index 27baa97ab1..724fbdc1d2 100644 --- a/docs/docs/auth/migration-guides/authy/index.md +++ b/docs/docs/auth/migration-guides/authy/index.md @@ -10,8 +10,9 @@ A guide written by Green, an ente.io lover > [!WARNING] > > Authy has dropped all support for its desktop apps. It is no longer possible -> to export data from Authy using methods 1 and 2. You will need either an iOS device -> and computer (method 4) or a rooted Android phone (method 3) to follow this guide. +> to export data from Authy using methods 1 and 2. You will need either an iOS +> device and computer (method 4) or a rooted Android phone (method 3) to follow +> this guide. --- @@ -204,11 +205,24 @@ This uses the tool [Aegis Authenticator](https://getaegis.app/) from ## Method 4: Authy-iOS-MiTM -**Who should use this?** Technical iOS users of Authy that cannot export their tokens with methods 1 or 2 (due to those methods being patched) or method 3 (due to that method requiring a rooted Android device). +**Who should use this?** Technical iOS users of Authy that cannot export their +tokens with methods 1 or 2 (due to those methods being patched) or method 3 (due +to that method requiring a rooted Android device). -This method works by intercepting the data the Authy app receives while logging in for the first time, which contains your encrypted authenticator tokens. After the encrypted authenticator tokens are dumped, you can decrypt them using your backup password and convert them to an Ente token file. +This method works by intercepting the data the Authy app receives while logging +in for the first time, which contains your encrypted authenticator tokens. After +the encrypted authenticator tokens are dumped, you can decrypt them using your +backup password and convert them to an Ente token file. -For an up-to-date guide of how to retrieve the encrypted authenticator tokens and decrypt them, please see [Authy-iOS-MiTM](https://github.com/AlexTech01/Authy-iOS-MiTM). To convert the `decrypted_tokens.json` file from that guide into a format Ente Authenticator can recognize, use [this](https://gist.github.com/gboudreau/94bb0c11a6209c82418d01a59d958c93?permalink_comment_id=5317087#gistcomment-5317087) Python script. Once you have the `ente_auth_import.plain` file from that script, transfer it to your device and follow the instructions below to import it into Ente Authenticator. +For an up-to-date guide of how to retrieve the encrypted authenticator tokens +and decrypt them, please see +[Authy-iOS-MiTM](https://github.com/AlexTech01/Authy-iOS-MiTM). To convert the +`decrypted_tokens.json` file from that guide into a format Ente Authenticator +can recognize, use +[this](https://gist.github.com/gboudreau/94bb0c11a6209c82418d01a59d958c93?permalink_comment_id=5317087#gistcomment-5317087) +Python script. Once you have the `ente_auth_import.plain` file from that script, +transfer it to your device and follow the instructions below to import it into +Ente Authenticator. ## Importing to Ente Authenticator (Method 1, method 2.1, method 4) diff --git a/docs/docs/de/auth/index.md b/docs/docs/de/auth/index.md index 1948a9126d..cb96f33738 100644 --- a/docs/docs/de/auth/index.md +++ b/docs/docs/de/auth/index.md @@ -10,4 +10,4 @@ Ende-zu-Ende-verschlüsselte Authenticator-App für jedermann. Wir sind froh, da du hier bist! **Please note that this German translation is currently just a placeholder.** -Know German? [Help us fill this in!](/about/contribute). +Know German? [Help us fill this in!](/#contribute). diff --git a/docs/docs/index.md b/docs/docs/index.md index af5fd2cddf..6bf6d18275 100644 --- a/docs/docs/index.md +++ b/docs/docs/index.md @@ -1,15 +1,82 @@ --- title: Home +description: > + Introduction to Ente: Products, Community and Support --- # Welcome! -This site contains documentation and help for Ente Photos and Ente Auth. It -describes various features, and also offers various troubleshooting suggestions. +![Ducky: Ente's Mascot](/public/ducky.png){width=50% style="margin: 0 auto"} -Use the **sidebar** menu to navigate to information about the product (Photos or -Auth) you'd like to know more about. Or use the **search** at the top to try and -jump directly to page that might contain the information you need. +## Introduction -To know more about Ente, see [about](/about/) or visit our website -[ente.io](https://ente.io). +Ente (pronounced en-_tay_) is a end-to-end encrypted platform for privately, +reliably, and securely storing your data on the cloud, over which 2 applications +have been developed and made available for mobile, web and desktop, namely: + +- **Ente Photos** - An alternative to Google Photos and Apple Photos +- **Ente Auth** - A free 2FA alternative to Authy + +## History + +Ente was the founded by Vishnu Mohandas (he's also Ente's CEO) in response to +privacy concerns with major tech companies. The underlying motivation was the +understanding that big tech had no incentive to fix their act, but with +end-to-end encrypted cross platform apps, there was a way for people to take +back control over their own data without sacrificing on features. + +### Origin of the name + +In Malayalam, Vishnu's native language, "ente" means "mine", thus "Ente Photos" +literally means "my photos". + +But one day, he discovered that "ente" means "duck" in German. This unexpected +connection sealed the deal after looking for alternative names and led to the +adoption of ["Ducky"](https://ente.io/blog/ducky/), representing the playfulness +and friendly nature of the community and team. + +## Getting Started + +We recommend reading the documentation for [Ente Photos](/photos/) or +[Ente Auth](/auth/) to get started with installation on the desired platform, +explore available features and usage. + +If you are looking to self-host Ente, we recommend you to read the +[official documentation](/self-hosting/) for updated information on getting +started, installation, administration and maintenance. + +## Contributing + +There are many ways to support Ente and you don't have to be a programmer for +that. You can spread the word, give feedback, report bugs, help us with +translations, contribute documentation and community guides and more. + +To suggest new features and/or offer your perspective on how we should design +(planned and upcoming features), use our +[GitHub discussions](https://github.com/ente-io/ente/discussions) + +You can find our contribution guidelines +[here](https://github.com/ente-io/ente/blob/main/CONTRIBUTING.md). + +You can always engage with our community and team to hang out, answer queries +and stay updated: + +- Chat: [Discord](https://ente.io/discord) +- Discussions: [GitHub](https://github.com/ente-io/ente/discussions) +- Socials: + - Twitter: [enteio](https://twitter.com/enteio) + - Mastodon: [@ente@fosstodon.org](https://fosstodon.org/@ente) + - Bluesky: [ente.io](https://bsky.app/profile/ente.io) + - Instagram: [ente.app](https://www.instagram.com/ente.app) +- Website: + - [Blog](https://ente.io/blog) + - [RSS](https://ente.io/blog/rss.xml) + +## Getting Help + +If you encounter any issues with any of the products that's not answered by our +documentation, please reach out to our team by sending an email to +[support@ente.io](mailto:support@ente.io) + +For community support, please post your queries on +[Discord](https://discord.gg/z2YVKkycX3) diff --git a/docs/docs/photos/faq/desktop.md b/docs/docs/photos/faq/desktop.md index 71a575bdfb..c0ef805584 100644 --- a/docs/docs/photos/faq/desktop.md +++ b/docs/docs/photos/faq/desktop.md @@ -1,6 +1,7 @@ --- title: Desktop app FAQ -description: An assortment of frequently asked questions about Ente Photos desktop app +description: + An assortment of frequently asked questions about Ente Photos desktop app --- # Desktop app FAQ @@ -15,7 +16,8 @@ to manually update the software. ### Upload errors -**How do I identify which files experienced upload issues within the desktop app?** +**How do I identify which files experienced upload issues within the desktop +app?** Check the sections within the upload progress bar for "Failed Uploads," "Ignored Uploads," and "Unsuccessful Uploads." @@ -33,6 +35,5 @@ be specific to your distro (e.g. `xdg-desktop-menu forceupdate`). > [!NOTE] > -> If you're using an AppImage and not seeing the icon, you'll need to [enable -> AppImage desktop -> integration](/photos/troubleshooting/desktop-install/#appimage-desktop-integration). +> If you're using an AppImage and not seeing the icon, you'll need to +> [enable AppImage desktop integration](/photos/troubleshooting/desktop-install/#appimage-desktop-integration). diff --git a/docs/docs/photos/faq/export.md b/docs/docs/photos/faq/export.md index e6ed64b4fa..5f37640f83 100644 --- a/docs/docs/photos/faq/export.md +++ b/docs/docs/photos/faq/export.md @@ -7,9 +7,10 @@ description: Frequently asked questions about keeping extra backups of your data ## How can I backup my data in a local drive outside Ente? -You can use our CLI tool or our desktop app to set up exports of your data -to your local drive. This way, you can use Ente in your day to day use, with an additional guarantee that a copy of your original photos and videos are -always available on your machine. +You can use our CLI tool or our desktop app to set up exports of your data to +your local drive. This way, you can use Ente in your day to day use, with an +additional guarantee that a copy of your original photos and videos are always +available on your machine. - You can use [Ente's CLI](https://github.com/ente-io/ente/tree/main/cli#export) to export your data in a cron job to a location of your choice. The exports diff --git a/docs/docs/photos/faq/face-recognition.md b/docs/docs/photos/faq/face-recognition.md index 24c9650345..8559bf310d 100644 --- a/docs/docs/photos/faq/face-recognition.md +++ b/docs/docs/photos/faq/face-recognition.md @@ -1,7 +1,6 @@ --- title: Face recognition -description: - Frequently asked questions about Ente's face recognition +description: Frequently asked questions about Ente's face recognition --- # Face recognition diff --git a/docs/docs/photos/faq/general.md b/docs/docs/photos/faq/general.md index aaf1451efd..040a7e1bfa 100644 --- a/docs/docs/photos/faq/general.md +++ b/docs/docs/photos/faq/general.md @@ -26,7 +26,6 @@ unsupported file format and we will do our best to help you out. Yes, we currently do not support files larger than 4 GB. - ## Does Ente support videos? Ente supports backing up and downloading of videos in their original format and @@ -101,29 +100,53 @@ clicking on "Your map" under "Locations" on the search screen. ## How to reset my password if I lost it? -On the login page, enter your email and click on Forgot Password. Then, enter your recovery key and create a new password. +On the login page, enter your email and click on Forgot Password. Then, enter +your recovery key and create a new password. - # iOS Album Backup and Organization in Ente +## Can I search for photos using the descriptions I’ve added? - ### How does Ente handle photos that are part of multiple iOS albums? -When you select multiple albums for backup, Ente prioritizes uploading each photo to the album with the fewest photos. This means a photo will only be uploaded once, even if it exists in multiple albums on your device. If you create new albums on your device after the initial backup, those photos may not appear in the corresponding Ente album if they were already uploaded to a different album. +Yes, descriptions are searchable, making it easier to find specific photos +later. To do this, open the photo, tap the (i) button, and enter your +description. +## How does the deduplication feature work on the desktop app? -### Why don’t all photos from a new iOS album appear in the corresponding Ente album? -If you create a new album on your device after the initial backup, the photos in that album may have already been uploaded to another album in Ente. To fix this, go to the "On Device" album in Ente, select all photos, and manually add them to the corresponding album in Ente. +If the app finds exact duplicates, it will show them in the deduplication. When +you delete a duplicate, the app keeps one copy and creates a symlink for the +other duplicate. This helps save storage space. -### What happens if I reorganize my photos in the iOS Photos app after backing up? -Reorganizing photos in the iOS Photos app (e.g., moving photos to new albums) won’t automatically reflect in Ente. You’ll need to manually add those photos to the corresponding albums in Ente to maintain consistency. +## What happens if I lose access to my email address? Can I use my recovery key to bypass email verification? -### Can I search for photos using the descriptions I’ve added? -Yes, descriptions are searchable, making it easier to find specific photos later. -To do this, open the photo, tap the (i) button, and enter your description. - -### How does the deduplication feature work on the desktop app? -If the app finds exact duplicates, it will show them in the deduplication. When you delete a duplicate, the app keeps one copy and creates a symlink for the other duplicate. This helps save storage space. - -### What happens if I lose access to my email address? Can I use my recovery key to bypass email verification? -No, the recovery key does not bypass email verification. For security reasons, we do not disable or bypass email verification unless the account owner reaches out to us and successfully verifies their identity by providing details about their account. +No, the recovery key does not bypass email verification. For security reasons, +we do not disable or bypass email verification unless the account owner reaches +out to us and successfully verifies their identity by providing details about +their account. If you lose access to your email, please contact our support team at support@ente.io + +--- + +# iOS Album Backup and Organization in Ente + +## How does Ente handle photos that are part of multiple iOS albums? + +When you select multiple albums for backup, Ente prioritizes uploading each +photo to the album with the fewest photos. This means a photo will only be +uploaded once, even if it exists in multiple albums on your device. If you +create new albums on your device after the initial backup, those photos may not +appear in the corresponding Ente album if they were already uploaded to a +different album. + +## Why don’t all photos from a new iOS album appear in the corresponding Ente album? + +If you create a new album on your device after the initial backup, the photos in +that album may have already been uploaded to another album in Ente. To fix this, +go to the "On Device" album in Ente, select all photos, and manually add them to +the corresponding album in Ente. + +## What happens if I reorganize my photos in the iOS Photos app after backing up? + +Reorganizing photos in the iOS Photos app (e.g., moving photos to new albums) +won’t automatically reflect in Ente. You’ll need to manually add those photos to +the corresponding albums in Ente to maintain consistency. diff --git a/docs/docs/photos/faq/metadata.md b/docs/docs/photos/faq/metadata.md index 03cf10da65..c7e122301b 100644 --- a/docs/docs/photos/faq/metadata.md +++ b/docs/docs/photos/faq/metadata.md @@ -62,6 +62,7 @@ the upload time as the photo's creation time. ## Modifications Ente supports modifications to the following metadata: + - File name - Date & time - Location diff --git a/docs/docs/photos/faq/video-streaming.md b/docs/docs/photos/faq/video-streaming.md index 91b2db1001..62d9764dbb 100644 --- a/docs/docs/photos/faq/video-streaming.md +++ b/docs/docs/photos/faq/video-streaming.md @@ -1,7 +1,6 @@ --- title: Video streaming FAQ -description: - Frequently asked questions about Ente's video streaming feature +description: Frequently asked questions about Ente's video streaming feature --- # Video streaming @@ -16,7 +15,7 @@ description: #### On mobile - Open Settings -> General -> Advanced -- Switch on the toggle for `Video streaming` +- Enable the toggle for `Streamable videos` #### On desktop @@ -78,6 +77,7 @@ generated stream. While this feature is in beta, we will not count the storage consumed by your streams against your storage quota. This may change in the future. If it does, we will provide an option to opt-in to one of the following: + 1. Original videos only 2. Compressed streams only 3. Both diff --git a/docs/docs/photos/features/background.md b/docs/docs/photos/features/background.md index ffed413f74..2decf9cb65 100644 --- a/docs/docs/photos/features/background.md +++ b/docs/docs/photos/features/background.md @@ -43,8 +43,8 @@ need to disable this "Optimize battery usage" mode in the system settings for Ente if you wish for Ente to automatically back up your photos in the background. -On Android versions 15 and later, if an app is in private space and the private -space is locked, Android doesn’t allow the app to run any background processes. +On Android versions 15 and later, if an app is in private space and the private +space is locked, Android doesn’t allow the app to run any background processes. As a result, background sync will not work. ### Desktop diff --git a/docs/docs/photos/features/deduplicate.md b/docs/docs/photos/features/deduplicate.md index c1b55e4cc7..ea931d174d 100644 --- a/docs/docs/photos/features/deduplicate.md +++ b/docs/docs/photos/features/deduplicate.md @@ -52,6 +52,11 @@ Ente also provides a tool for manual de-duplication in _Settings → Backup → Remove duplicates_. This is useful if you have an existing library with duplicates across different albums, but wish to keep only one copy. +During this operation, Ente will discard duplicates across all albums, retain a +single copy, and add symlinks to this copy within all existing albums. So your +existing album structure remains unchanged, while the space consumed by the +duplicate data is freed up. + ## Adding to Ente album creates symlinks Note that once a file is in Ente, adding it to another Ente album will create a diff --git a/docs/docs/photos/features/family-plans.md b/docs/docs/photos/features/family-plans.md index 711b9e3094..cc5ee52aff 100644 --- a/docs/docs/photos/features/family-plans.md +++ b/docs/docs/photos/features/family-plans.md @@ -24,19 +24,19 @@ In brief, ## Storage Limits -If you're an admin of a family, you will be able to set storage limits for the +If you're an admin of a family, you will be able to set storage limits for the members in your family plan. -In brief, +In brief, -- For example, once you set a limit of 10GB for a member, their Storage - quota for uploading photos will be limited to 10GB. +- For example, once you set a limit of 10GB for a member, their Storage quota + for uploading photos will be limited to 10GB. -- Once the invited member accepts the Family invite, you will be able to see - an edit icon in the Members List. Click on it to setup a family limit. +- Once the invited member accepts the Family invite, you will be able to see an + edit icon in the Members List. Click on it to setup a family limit. - If the admin has set a limit for any user, that limit value will be prefilled - in the input box. + in the input box. -- If you want to remove any storage limit from a members account, you - can click on the "Remove Limit" and they can upload photos without any limit. +- If you want to remove any storage limit from a members account, you can click + on the "Remove Limit" and they can upload photos without any limit. diff --git a/docs/docs/photos/features/machine-learning.md b/docs/docs/photos/features/machine-learning.md index 215c1d98a8..e43edd5b43 100644 --- a/docs/docs/photos/features/machine-learning.md +++ b/docs/docs/photos/features/machine-learning.md @@ -47,8 +47,20 @@ device. The indexes are synced across all your devices automatically using the same end-to-end encrypted security that we use for syncing your photos. -Note that the desktop app does not currently support modifying the face -groupings, that is only supported by the mobile app. +--- + +#### Local indexing on mobile + +In general the machine learning is optimized to work well on most mobile device. +However, devices with low RAM (4-6GB) and large photo libraries might struggle +to complete the indexing without affecting performance of the app. In such case, +you might want to disable local indexing and let the desktop run it instead. + +You can disable local indexing from the settings, under +`General > Advanced > Machine learning > Configuration`. This way, you can +continue to use the ML features without your phone performance taking any hit. + +--- For more information on how to use Machine Learning for face recognition please check out [the FAQ](../faq/face-recognition). diff --git a/docs/docs/photos/features/notifications.md b/docs/docs/photos/features/notifications.md new file mode 100644 index 0000000000..0cf33a6e0e --- /dev/null +++ b/docs/docs/photos/features/notifications.md @@ -0,0 +1,33 @@ +--- +title: Notifications +description: Details about notifications in Ente +--- + +# Notifications + +The Ente app can send notifications to notify you of an update, or just to +remind you of some sweet or helpful memory at the right time. + +## New shared photos + +Receive notifications when someone adds a photo to a shared album that you're a +part of. + +## "On this day" memories + +Receive reminders about memories from this day in previous years. These +reminders will only be shown if there are enough photos taken across previous +years of the specific day. + +## Birthday notifications + +Receive reminders when it's someone's birthday. Tapping on the notification will +take you to photos of the birthday person. This requires you to first add a +birthday to a person, and will only be shown if there are enough photos of that +person. + +## Notification permission + +By default all notification categories are enabled if you give notification +permission. You can disable all of the above notification categories from +`Settings > Notifications`. Notifications currently only work on mobile. diff --git a/docs/docs/photos/migration/export/index.md b/docs/docs/photos/migration/export/index.md index 39d14984ed..1e00623e54 100644 --- a/docs/docs/photos/migration/export/index.md +++ b/docs/docs/photos/migration/export/index.md @@ -66,5 +66,4 @@ If you run into any issues during your data export, please reach out to Note that we also provide a [CLI tool](https://github.com/ente-io/ente/tree/main/cli#export) to export your -data. You can find more information about the export in the -[export FAQ](/photos/faq/export). +data. diff --git a/docs/docs/about/ducky.png b/docs/docs/public/ducky.png similarity index 100% rename from docs/docs/about/ducky.png rename to docs/docs/public/ducky.png diff --git a/docs/docs/self-hosting/creating-accounts.md b/docs/docs/self-hosting/creating-accounts.md index 5c3a53d3a3..550409106e 100644 --- a/docs/docs/self-hosting/creating-accounts.md +++ b/docs/docs/self-hosting/creating-accounts.md @@ -3,7 +3,7 @@ title: Creating accounts description: Creating accounts on your deployment --- -# Creating accounts +# Creating accounts Once Ente is up and running, the Ente Photos web app will be accessible on `http://localhost:3000`. Open this URL in your browser and proceed with creating @@ -20,7 +20,7 @@ This code can be found in the server logs, which should already be shown in your quickstart terminal. Alternatively, you can open the server logs with the following command from inside the `my-ente` folder: -```sh +```sh sudo docker compose logs ``` diff --git a/docs/docs/self-hosting/faq/environment.md b/docs/docs/self-hosting/faq/environment.md index b086c07b3f..a8dcf18d06 100644 --- a/docs/docs/self-hosting/faq/environment.md +++ b/docs/docs/self-hosting/faq/environment.md @@ -1,10 +1,14 @@ --- title: "Environment Variables and Ports" -description: "Information about all the Environment Variables needed to run Ente" +description: + "Information about all the Environment Variables needed to run Ente" --- # Environment variables and ports -A self-hosted Ente instance requires specific endpoints in both Museum (the server) and web apps. This document outlines the essential environment variables and port mappings of the web apps. + +A self-hosted Ente instance requires specific endpoints in both Museum (the +server) and web apps. This document outlines the essential environment variables +and port mappings of the web apps. Here's the list of important variables that a self hoster should know about: @@ -12,34 +16,33 @@ Here's the list of important variables that a self hoster should know about: 1. `NEXT_PUBLIC_ENTE_ENDPOINT` -The above environment variable is used to configure Museums endpoint. Where Museum is -running and which port it is listening on. This endpoint should be configured for -all the apps to connect to your self hosted endpoint. +The above environment variable is used to configure Museums endpoint. Where +Museum is running and which port it is listening on. This endpoint should be +configured for all the apps to connect to your self hosted endpoint. -All the apps (regardless of platform) by default connect to api.ente.io - which is -our production instance of Museum. +All the apps (regardless of platform) by default connect to api.ente.io - which +is our production instance of Museum. ### Web Apps -> [!IMPORTANT] -> Web apps don't need to be configured with the below endpoints. Web app environment -> variables are being documented here just so that the users know everything in detail. -> Checkout [Configuring your Server](/self-hosting/museum) to configure endpoints for +> [!IMPORTANT] Web apps don't need to be configured with the below endpoints. +> Web app environment variables are being documented here just so that the users +> know everything in detail. Checkout +> [Configuring your Server](/self-hosting/museum) to configure endpoints for > particular app. -In Ente, all the web apps are separate NextJS applications. Therefore, they are all -configured via environment variables. The photos app (Ente Photos) has information -about and connects to other web apps like albums, cast, etc. - +In Ente, all the web apps are separate NextJS applications. Therefore, they are +all configured via environment variables. The photos app (Ente Photos) has +information about and connects to other web apps like albums, cast, etc. 1. `NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT` -This environment variable is used to configure and declare the endpoint for the Albums -web app. +This environment variable is used to configure and declare the endpoint for the +Albums web app. ## Ports -The below format is according to how ports are mapped in Docker. +The below format is according to how ports are mapped in Docker. Typically,`:` 1. `8080:8080`: Museum (Ente's server) diff --git a/docs/docs/self-hosting/guides/admin.md b/docs/docs/self-hosting/guides/admin.md index 3f80d1478e..10d05fb4d0 100644 --- a/docs/docs/self-hosting/guides/admin.md +++ b/docs/docs/self-hosting/guides/admin.md @@ -14,7 +14,7 @@ explicit whitelist of admins. > [!NOTE] > -> The first user is only treated as the admin if the list of admins in the +> The first user is only treated as the admin if the list of admins in the > configuration is empty. > > Also, if at some point you delete the first user, then you will need to define @@ -54,11 +54,10 @@ command to find the user id of any account. # Administering your custom server -> [!NOTE] -> For the first user (admin) to perform administrative actions using the CLI, their -> userID must be whitelisted in the `museum.yaml` configuration file under -> `internal.admins`. While the first user is automatically granted admin privileges -> on the server, this additional step is required for CLI operations. +> [!NOTE] For the first user (admin) to perform administrative actions using the +> CLI, their userID must be whitelisted in the `museum.yaml` configuration file +> under `internal.admins`. While the first user is automatically granted admin +> privileges on the server, this additional step is required for CLI operations. You can use [Ente's CLI](https://github.com/ente-io/ente/releases?q=tag%3Acli-v0) to diff --git a/docs/docs/self-hosting/guides/configuring-s3.md b/docs/docs/self-hosting/guides/configuring-s3.md index f4095db2eb..55f2f3b356 100644 --- a/docs/docs/self-hosting/guides/configuring-s3.md +++ b/docs/docs/self-hosting/guides/configuring-s3.md @@ -29,7 +29,7 @@ A file upload flows as follows: The upshot of this is that _both_ the client and museum should be able to reach your S3 bucket. -## Configuring S3 +## Configuring S3 The URL for the S3 bucket is configured in [scripts/compose/credentials.yaml](https://github.com/ente-io/ente/blob/main/server/scripts/compose/credentials.yaml#L10). @@ -38,9 +38,8 @@ You can edit this file directly while testing, though it is more robust to create a `museum.yaml` (in the same folder as the Docker compose file) and to setup your custom configuration there. -> [!TIP] -> For more details about these configuration objects, see the documentation for -> the `s3` object in +> [!TIP] For more details about these configuration objects, see the +> documentation for the `s3` object in > [configurations/local.yaml](https://github.com/ente-io/ente/blob/main/server/configurations/local.yaml). By default, you only need to configure the endpoint for the first bucket. @@ -56,13 +55,14 @@ components of the setup to communicate with each other seamlessly. The same principle applies if you're deploying to your custom domain. -## Replication +## Replication ![Replication](/replication.png) +

Community contributed diagram of Ente's replication process

> [!IMPORTANT] -> +> > As of now, replication works only if all the 3 storage type needs are > fulfilled (1 hot, 1 cold and 1 glacier storage). > @@ -72,10 +72,10 @@ If you're wondering why there are 3 buckets on the MinIO UI - that's because our production instance uses these to perform [replication](https://ente.io/reliability/). -If you're also wondering about why the bucket names are specifically what they are, -it's because that is exactly what we are using on our production instance. -We use `b2-eu-cen` as hot, `wasabi-eu-central-2-v3` as cold (also the secondary hot) -and `scw-eu-fr-v3` as glacier storage. As of now, all of this is hardcoded. +If you're also wondering about why the bucket names are specifically what they +are, it's because that is exactly what we are using on our production instance. +We use `b2-eu-cen` as hot, `wasabi-eu-central-2-v3` as cold (also the secondary +hot) and `scw-eu-fr-v3` as glacier storage. As of now, all of this is hardcoded. Hence, the same hardcoded configuration is applied when you self host Ente. In a self hosted Ente instance replication is turned off by default. When @@ -84,16 +84,15 @@ other two are ignored. Only the names here are specifically fixed, but in the configuration body you can put any other keys. It does not have any relation with `b2`, `wasabi` or even `scaleway`. -Use the `s3.hot_storage.primary` option if you'd like to set one of the other +Use the `s3.hot_storage.primary` option if you'd like to set one of the other predefined buckets as the primary bucket. -## SSL Configuration +## SSL Configuration > [!NOTE] > > If you need to configure SSL, you'll need to turn off `s3.are_local_buckets` > (which disables SSL in the default starter compose template). -> Disabling `s3.are_local_buckets` also switches to the subdomain style URLs for the buckets. However, not all S3 providers support these. In particular, MinIO @@ -121,4 +120,4 @@ s3: endpoint: http://:3200 region: eu-central-2 bucket: b2-eu-cen -``` \ No newline at end of file +``` diff --git a/docs/docs/self-hosting/guides/custom-server/index.md b/docs/docs/self-hosting/guides/custom-server/index.md index 86060ba909..63ba371eb8 100644 --- a/docs/docs/self-hosting/guides/custom-server/index.md +++ b/docs/docs/self-hosting/guides/custom-server/index.md @@ -111,5 +111,5 @@ network, you need to use the public IP or hostname. > [!TIP] > > If you're having trouble uploading from your mobile app, it is likely that -> museum is not able to connect to your S3 storage. See the [Configuring -> S3](/self-hosting/guides/configuring-s3) guide for more details. +> museum is not able to connect to your S3 storage. See the +> [Configuring S3](/self-hosting/guides/configuring-s3) guide for more details. diff --git a/docs/docs/self-hosting/guides/from-source.md b/docs/docs/self-hosting/guides/from-source.md index df3ec7e5fb..9d010190dc 100644 --- a/docs/docs/self-hosting/guides/from-source.md +++ b/docs/docs/self-hosting/guides/from-source.md @@ -3,13 +3,12 @@ title: Ente from Source description: Getting started self hosting Ente Photos and/or Ente Auth --- - # Ente from Source -> [!WARNING] NOTE -> The below documentation will cover instructions about self-hosting the web app manually. If you -> want to deploy Ente hassle free, use the [one line](https://ente.io/blog/self-hosting-quickstart/) -> command to setup Ente. This guide might be deprecated in the near future. +> [!WARNING] NOTE The below documentation will cover instructions about +> self-hosting the web app manually. If you want to deploy Ente hassle free, use +> the [one line](https://ente.io/blog/self-hosting-quickstart/) command to setup +> Ente. This guide might be deprecated in the near future. ## Installing Docker @@ -63,8 +62,9 @@ apps and configure them to use your ## Web app with Docker and Compose -The instructoins in previous section were just a temporary way to run the web app locally. -To run the web apps as services, the user has to build a docker image manually. +The instructoins in previous section were just a temporary way to run the web +app locally. To run the web apps as services, the user has to build a docker +image manually. > [!IMPORTANT] > @@ -144,7 +144,7 @@ docker build -t : --no-cache --progress plain . You can always edit the Dockerfile and remove the steps for apps which you do not intend to install on your system (like auth or cast) and opt out of those. -Regarding Albums App, take a note that they are not apps with navigable pages, +Regarding Albums App, take a note that they are not apps with navigable pages, if accessed on the web-browser they will simply redirect to ente.web.io. ## compose.yaml @@ -175,17 +175,17 @@ docker compose up -d # --build docker compose logs ``` -## Configure App Endpoints +## Configure App Endpoints -> [!NOTE] -> Previously, this was dependent on the env variables `NEXT_ENTE_PUBLIC_ACCOUNTS_ENDPOINT` -> and etc. Please check the below documentation to update your setup configurations +> [!NOTE] Previously, this was dependent on the env variables +> `NEXT_ENTE_PUBLIC_ACCOUNTS_ENDPOINT` and etc. Please check the below +> documentation to update your setup configurations -You can configure the web endpoints for the other apps including Accounts, Albums -Family and Cast in your `museum.yaml` configuration file. Checkout +You can configure the web endpoints for the other apps including Accounts, +Albums Family and Cast in your `museum.yaml` configuration file. Checkout [`local.yaml`](https://github.com/ente-io/ente/blob/543411254b2bb55bd00a0e515dcafa12d12d3b35/server/configurations/local.yaml#L76-L89) -to configure the endpoints. Make sure to setup up your DNS Records accordingly to the -similar URL's you set up in `museum.yaml`. +to configure the endpoints. Make sure to setup up your DNS Records accordingly +to the similar URL's you set up in `museum.yaml`. Next part is to configure the web server. @@ -197,7 +197,7 @@ ports). The web server of choice in this guide is [Caddy](https://caddyserver.com) because with caddy you don't have to manually configure/setup SSL ceritifcates as caddy will take care of that. -```sh +```groovy photos.yourdomain.com { reverse_proxy http://localhost:3001 # for logging @@ -219,6 +219,7 @@ Next, start the caddy server :). sudo systemctl enable caddy sudo systemctl daemon-reload + sudo systemctl start caddy ``` diff --git a/docs/docs/self-hosting/guides/Tailscale.md b/docs/docs/self-hosting/guides/tailscale.md similarity index 60% rename from docs/docs/self-hosting/guides/Tailscale.md rename to docs/docs/self-hosting/guides/tailscale.md index 1f0a7593ed..de3cc6fdf0 100644 --- a/docs/docs/self-hosting/guides/Tailscale.md +++ b/docs/docs/self-hosting/guides/tailscale.md @@ -2,39 +2,56 @@ title: Self Hosting with Tailscale (Community) description: Guides for self-hosting Ente Photos and/or Ente Auth with Tailscale --- + # Guide -This guide aims to achieve self-hosting Ente photos or Ente-Auth with tailscale (TSDPROXY) without exposing any port OR if someone is behind CGNAT and cannot open any port on the internet but want to run their own selfhosted service for themselves, friends and family only. +This guide aims to achieve self-hosting Ente photos or Ente-Auth with tailscale +(TSDPROXY) without exposing any port OR if someone is behind CGNAT and cannot +open any port on the internet but want to run their own selfhosted service for +themselves, friends and family only. Before getting start keep the following NOTE in mind. -> [!NOTE] -> If someone is behind double or triple CGNAT; must install tailscale system wide by running `curl -fsSL https://tailscale.com/install.sh | sh` in your linux terminal and `sudo tailscale up` otherwise dns resolver will fail and uploading will not work. This is not necessary for those who are not behing CGNAT. -> This guide also work on docker rootless and normal. +> [!NOTE] If someone is behind double or triple CGNAT; must install tailscale +> system wide by running `curl -fsSL https://tailscale.com/install.sh | sh` in +> your linux terminal and `sudo tailscale up` otherwise dns resolver will fail +> and uploading will not work. This is not necessary for those who are not +> behing CGNAT. This guide also work on docker rootless and normal. -> [!CAUTION] -Remember that current docker update 28.0.0 has some bug and cannot connect to external network. Make sure to install docker-ce 27.5.0, docker-ce-rootless-extras 27.5.0 and docker-ce-cli 27.5.0. Hopefully docker 28.1.0 will resolve this issue in next week. Refrence links are [Moby Github Repo Issues 49511](https://github.com/moby/moby/issues/49511) and [Moby Github Repo Issues 49519](https://github.com/moby/moby/issues/49519) - -> [!IMPORTANT] -> For Docker rootless, the user must have local permissions for all directories required by the Ente-photos self-hosted server. This can be achieved by running `sudo chown -R 1000:1000 /home/ubuntu/docker/ente`. In the Linux terminal, you can check the UID with `id -u` or simply `id`. The first user typically has UID 1000. -> To allow listening and pinging on any port without root privileges, create a file called `/etc/sysctl.d/99-rootless.conf` with the following content: +> [!IMPORTANT] For Docker rootless, the user must have local permissions for all +> directories required by the Ente-photos self-hosted server. This can be +> achieved by running `sudo chown -R 1000:1000 /home/ubuntu/docker/ente`. In the +> Linux terminal, you can check the UID with `id -u` or simply `id`. The first +> user typically has UID 1000. To allow listening and pinging on any port +> without root privileges, create a file called `/etc/sysctl.d/99-rootless.conf` +> with the following content: +> > ``` > net.ipv4.ip_unprivileged_port_start=0 > net.ipv4.ping_group_range = 0 2147483647 > ``` -> than run `sudo sysctl --system`. -> Create `~/.config/systemd/user/docker.service.d/override.conf` with the following content: +> +> then run `sudo sysctl --system`. Create +> `~/.config/systemd/user/docker.service.d/override.conf` with the following +> content: +> > ``` > [Service] > Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_NET=slirp4netns" > Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=slirp4netns" > ``` -> and Restart the docker daemon -> `systemctl --user restart docker` -> Instead of `--volume /var/run/docker.sock:/var/run/docker.sock` in TSDPROXY compose.yaml, use `--volume $XDG_RUNTIME_DIR/docker.sock:/var/run/docker.sock` +> +> and Restart the docker daemon `systemctl --user restart docker` Instead of +> `--volume /var/run/docker.sock:/var/run/docker.sock` in TSDPROXY compose.yaml, +> use `--volume $XDG_RUNTIME_DIR/docker.sock:/var/run/docker.sock` + +## GETTING START WITH SETUP + +First of all create a directory +`sudo mkdir -p /home/ubuntu/docker/tsdproxy/config` then `cd docker/tsdproxy` +and create compose.yaml file by running `sudo nano compose.yaml`. Populate it +with the following: -## GETTING START WITH SETUP ## -First of all create a directory `sudo mkdir -p /home/ubuntu/docker/tsdproxy/config` than `cd docker/tsdproxy` and create compose.yaml file by running `sudo nano compose.yaml`. Populate it with the following: ``` services: tsdproxy: @@ -62,9 +79,18 @@ networks: proxy: name: proxy ``` -Now login into your tailscale account admin counsle > settings > keys > Generate authkey. Give any description and must select resuable, because the key get purged if not selected after rebooting machine. It is advisable to create **Tags** in **ACLs settings** `tag: tsdproxy` `tag: ente` `tag: minio` as well. This will create a tag nodes with no key expirory. One is safe to reboot restart docker or machine. -> Copy the generated authkey as it is shown only once. -Make tsdproxy.yaml file in `cd docker/tsdproxy/config` by running `sudo nano tsdproxy.yaml` and pupolate it with the following contant: + +Now login into your tailscale account admin counsle > settings > keys > Generate +authkey. Give any description and must select resuable, because the key get +purged if not selected after rebooting machine. It is advisable to create +**Tags** in **ACLs settings** `tag: tsdproxy` `tag: ente` `tag: minio` as well. +This will create a tag nodes with no key expirory. One is safe to reboot restart +docker or machine. + +> Copy the generated authkey as it is shown only once. Make tsdproxy.yaml file +> in `cd docker/tsdproxy/config` by running `sudo nano tsdproxy.yaml` and +> pupolate it with the following contant: + ``` defaultproxyprovider: default docker: @@ -87,12 +113,20 @@ log: json: false proxyaccesslog: true ``` -In the same directory run `sudo nano authkey` and paste the authkey just copied earlier from tailscale admin counsel. -> Here Tailscale (TSDPROXY) setup is complet in all respect. Just run `docker compose up -d`. Check your tailscale amdin counsel and you will see tsdproxy node up and running. Make sure that **HTTPS** is enabled in tailscale DNS settings. -> You can visit the TSDPROXY web GUI by https://tsdproxy.xyz.ts.net. (xyz is change value for everyone) -## ente Part ## +In the same directory run `sudo nano authkey` and paste the authkey just copied +earlier from tailscale admin counsel. + +> Here Tailscale (TSDPROXY) setup is complet in all respect. Just run +> `docker compose up -d`. Check your tailscale amdin counsel and you will see +> tsdproxy node up and running. Make sure that **HTTPS** is enabled in tailscale +> DNS settings. You can visit the TSDPROXY web GUI by +> https://tsdproxy.xyz.ts.net. (xyz is change value for everyone) + +## ente Part + First make the following necessary files/directories: + ``` sudo mkdir -p /home/ubuntu/docker/ente/custom-logs sudo mkdir -p /home/ubuntu/docker/ente/data @@ -100,9 +134,14 @@ sudo mkdir -p /home/ubuntu/docker/ente/minio-data sudo mkdir -p /home/ubuntu/docker/ente/postgres-data sudo mkdir -p /home/ubuntu/docker/ente/scripts/compose ``` -Than give user permission for each of the above directory. `sudo chown -R 1000:1000 /home/ubuntu/docker/ente/custom-logs` etc etc. Make sure not to skip `/home/ubuntu/docker/tsdproxy/config` -`cd docker/ente/script/compose` and run `sudo nano credentials.yaml` than populate it with the following: +Than give user permission for each of the above directory. +`sudo chown -R 1000:1000 /home/ubuntu/docker/ente/custom-logs` etc etc. Make +sure not to skip `/home/ubuntu/docker/tsdproxy/config` + +`cd docker/ente/script/compose` and run `sudo nano credentials.yaml` than +populate it with the following: + ``` db: host: postgres @@ -134,7 +173,9 @@ s3: bucket: scw-eu-fr-v3 ``` -In the same directory run `sudo nano minio-provision.sh` and populate it with the following contant: +In the same directory run `sudo nano minio-provision.sh` and populate it with +the following contant: + ``` #!/bin/sh @@ -154,7 +195,9 @@ mc mb -p wasabi-eu-central-2-v3 mc mb -p scw-eu-fr-v3 ``` -Now `cd docker/ente` and run `sudo nano docker-compose.yaml` and populate it with the following: +Now `cd docker/ente` and run `sudo nano docker-compose.yaml` and populate it +with the following: + ``` services: museum: @@ -255,32 +298,52 @@ services: networks: ente: name: ente - + proxy: external: true ``` -> Thats it. Run `docker compose up -d`. Wait till every container become healthy. Open web browser. Make sure tailscale is installed on the machine. Visit https://ente.xyz.ts.net/ping. It will pong. All good if you see it. First time it will take minute or two to get SSL cert. Downnload Desktop or mobile app. Tap 7 time on the screen, which will prompt developer mode. Add https://ente.xyz.ts.net. Add new user. When asked for OTP. Just go to linux terminal and run `docker logs ente-museum-1`. Search for userauth. Feed the six digit and Done. +> Thats it. Run `docker compose up -d`. Wait till every container become +> healthy. Open web browser. Make sure tailscale is installed on the machine. +> Visit https://ente.xyz.ts.net/ping. It will pong. All good if you see it. +> First time it will take minute or two to get SSL cert. Downnload Desktop or +> mobile app. Tap 7 time on the screen, which will prompt developer mode. Add +> https://ente.xyz.ts.net. Add new user. When asked for OTP. Just go to linux +> terminal and run `docker logs ente-museum-1`. Search for userauth. Feed the +> six digit and Done. + +> For getting 100TB (limitless) storage. Just Install ente-cli for windows. +> Extract it and add folder. Name it **export**. Add config.yaml file along and +> populate it with the following: -> For getting 100TB (limitless) storage. Just Install ente-cli for windows. Extract it and add folder. Name it **export**. Add config.yaml file along and populate it with the following: ``` endpoint: api: "https://ente.xyz.ts.net" accounts: "http://localhost:3001" - + log: false ``` -Right-Click in the directory where you have extracted ente-cli. Select `open in terminal`. Run + +Right-Click in the directory where you have extracted ente-cli. Select +`open in terminal`. Run + ``` .\ente.exe account bob # change bob to yours ``` -Hit Enter twice. -For export directory, just write export. As already created **export** folder earlier. -**Write email. The one which is already used befor when creating ente account in ente desktop app.** -Type the same Password used before for the account.Run + +Hit Enter twice. For export directory, just write export. As already created +**export** folder earlier. **Write email. The one which is already used befor +when creating ente account in ente desktop app.** Type the same Password used +before for the account.Run + ``` .\ente.ext account list ``` + This will list all account details. Copy Acount ID. -> Navigate to museum.yaml file. `cd docker/ente`. Run `sudo nano museum.yaml` and add the account ID under Admins. Delete any previous entries. -Restart ente-museum-1 container from linux terminal. Run `docker restart ente-museum-1`. All well, now you will have 100TB storage. Repeat if for any other accounts you want to give unlimited storage access. + +> Navigate to museum.yaml file. `cd docker/ente`. Run `sudo nano museum.yaml` +> and add the account ID under Admins. Delete any previous entries. Restart +> ente-museum-1 container from linux terminal. Run +> `docker restart ente-museum-1`. All well, now you will have 100TB storage. +> Repeat if for any other accounts you want to give unlimited storage access. diff --git a/docs/docs/self-hosting/guides/web-app.md b/docs/docs/self-hosting/guides/web-app.md index 015cb7d986..a3061e3004 100644 --- a/docs/docs/self-hosting/guides/web-app.md +++ b/docs/docs/self-hosting/guides/web-app.md @@ -5,22 +5,20 @@ description: server --- - -> [!WARNING] NOTE -> This page covers documentation around self-hosting the web app manually. If you -> want to deploy Ente hassle free, please use the [one line](https://ente.io/blog/self-hosting-quickstart/) -> command to setup Ente. This guide might be deprecated in the near future. +> [!WARNING] NOTE This page covers documentation around self-hosting the web app +> manually. If you want to deploy Ente hassle free, please use the +> [one line](https://ente.io/blog/self-hosting-quickstart/) command to setup +> Ente. This guide might be deprecated in the near future. # Web app The getting started instructions mention using `yarn dev` (which is an alias of `yarn dev:photos`) to serve your web app. ->[!IMPORTANT] -> Please note that Ente's Web App supports the Yarn version 1.22.xx or 1.22.22 specifically. -> Make sure to install the right version or modify your yarn installation to meet the requirements. -> The user might end up into unknown version and dependency related errors if yarn -> is on different version. +> [!IMPORTANT] Please note that Ente's Web App supports the Yarn version 1.22.xx +> or 1.22.22 specifically. Make sure to install the right version or modify your +> yarn installation to meet the requirements. The user might end up into unknown +> version and dependency related errors if yarn is on different version. ```sh cd ente/web @@ -146,15 +144,15 @@ docker compose logs ## Configure App Endpoints -> [!NOTE] -> Previously, this was dependent on the env variables `NEXT_ENTE_PUBLIC_ACCOUNTS_ENDPOINT` -> and etc. Please check the below documentation to update your setup configurations +> [!NOTE] Previously, this was dependent on the env variables +> `NEXT_ENTE_PUBLIC_ACCOUNTS_ENDPOINT` and etc. Please check the below +> documentation to update your setup configurations -You can configure the web endpoints for the other apps including Accounts, Albums -Family and Cast in your `museum.yaml` configuration file. Checkout +You can configure the web endpoints for the other apps including Accounts, +Albums Family and Cast in your `museum.yaml` configuration file. Checkout [`local.yaml`](https://github.com/ente-io/ente/blob/543411254b2bb55bd00a0e515dcafa12d12d3b35/server/configurations/local.yaml#L76-L89) -to configure the endpoints. Make sure to setup up your DNS Records accordingly to the -similar URL's you set up in `museum.yaml`. +to configure the endpoints. Make sure to setup up your DNS Records accordingly +to the similar URL's you set up in `museum.yaml`. Next part is to configure the web server. diff --git a/docs/docs/self-hosting/index.md b/docs/docs/self-hosting/index.md index c0eef22f2c..f371747114 100644 --- a/docs/docs/self-hosting/index.md +++ b/docs/docs/self-hosting/index.md @@ -5,20 +5,32 @@ description: Getting started self hosting Ente Photos and/or Ente Auth # Self Hosting -The entire source code for Ente is open source, including the servers. This is +The entire source code for Ente is open source, +[including the servers](https://ente.io/blog/open-sourcing-our-server/). This is the same code we use for our own cloud service. -> [!TIP] -> -> You might find our [blog post](https://ente.io/blog/open-sourcing-our-server/) -> announcing the open sourcing of our server useful. +## Requirements -## System requirements +### Hardware -The server has minimal resource requirements, running as a lightweight Go -binary. It performs well on small cloud instances, old laptops, and even +The server is capable of running on minimal resource requirements as a +lightweight Go binary, since most of the intensive computational tasks are done +on the client. It performs well on small cloud instances, old laptops, and even [low-end embedded devices](https://github.com/ente-io/ente/discussions/594). +### Software + +#### Operating System + +Any Linux or \*nix operating system, Ubuntu or Debian is recommended to have a +good Docker experience. Non-Linux operating systems tend to provide poor +experience with Docker and difficulty with troubleshooting and assistance. + +#### Docker + +Required for running Ente's server, web application and dependent services +(database and object storage) + ## Getting started Run this command on your terminal to setup Ente. @@ -28,12 +40,17 @@ sh -c "$(curl -fsSL https://raw.githubusercontent.com/ente-io/ente/main/server/q ``` The above `curl` command pulls the Docker image, creates a directory `my-ente` -in the current working directory and starts all containers required to run Ente. +in the current working directory, prompts to start the cluster and starts all the containers required to run Ente. ![quickstart](/quickstart.png) ![self-hosted-ente](/web-app.webp) +> [!TIP] Important: +> If you have used quickstart for self-hosting Ente and are facing issues while > trying to run the cluster due to MinIO buckets not being created, please check [troubleshooting MinIO](/self-hosting/troubleshooting/docker#minio-provisioning-error) +> +> + ## Queries? If you need support, please ask on our community diff --git a/docs/docs/self-hosting/museum.md b/docs/docs/self-hosting/museum.md index 515616ac32..cb5263104f 100644 --- a/docs/docs/self-hosting/museum.md +++ b/docs/docs/self-hosting/museum.md @@ -16,10 +16,10 @@ If you used our quickstart script, your `my-ente` directory will include a PostgreSQL and MinIO. > [!TIP] -> +> > Always do `docker compose down` inside your `my-ente` directory. If you've -> made changes to `museum.yaml`, restart the containers with `docker compose up -> -d ` to see your changes in action. +> made changes to `museum.yaml`, restart the containers with +> `docker compose up -d ` to see your changes in action. ## S3 buckets @@ -33,19 +33,20 @@ Check out [Configuring S3](/self-hosting/guides/configuring-s3.md) to understand more about configuring S3 buckets. MinIO uses the port `3200` for API Endpoints and their web app runs over -`:3201`. You can login to MinIO Web Console by opening `localhost:3201` in your browser. +`:3201`. You can login to MinIO Web Console by opening `localhost:3201` in your +browser. -If you face any issues related to uploads then checkout [Troubleshooting bucket -CORS](/self-hosting/troubleshooting/bucket-cors) and [Frequently encountered S3 -errors](/self-hosting/guides/configuring-s3#frequently-encountered-errors). +If you face any issues related to uploads then checkout +[Troubleshooting bucket CORS](/self-hosting/troubleshooting/bucket-cors) and +[Frequently encountered S3 errors](/self-hosting/guides/configuring-s3#frequently-encountered-errors). ## Web apps The web apps for Ente Photos is divided into multiple sub-apps like albums, -cast, auth, etc. These endpoints are configurable in the museum.yaml under the +cast, auth, etc. These endpoints are configurable in `museum.yaml` under the `apps.*` section. -For example, +For example, ```yaml apps: @@ -55,17 +56,16 @@ apps: family: https://family.myente.xyz ``` ->[!IMPORTANT] ->By default, all the values redirect to our publicly hosted production services. ->For example, if `public-albums` is not configured your shared album will ->use the `albums.ente.io` URL. +> [!IMPORTANT] By default, all the values redirect to our publicly hosted +> production services. For example, if `public-albums` is not configured your +> shared album will use the `albums.ente.io` URL. After you are done with filling the values, restart museum and the app will start utilizing those endpoints instead of Ente's production instances. Once you have configured all the necessary endpoints, `cd` into `my-ente` and stop all the Docker containers with `docker compose down` and restart them with -`docker compose up -d`. +`docker compose up -d`. Similarly, you can use the default [`local.yaml`](https://github.com/ente-io/ente/tree/main/server/configurations/local.yaml) diff --git a/docs/docs/self-hosting/reverse-proxy.md b/docs/docs/self-hosting/reverse-proxy.md index 7ef79ac412..97ef7da570 100644 --- a/docs/docs/self-hosting/reverse-proxy.md +++ b/docs/docs/self-hosting/reverse-proxy.md @@ -22,28 +22,32 @@ server on your machine. Setting up a reverse proxy with Caddy is easy and straightforward. -Firstly, install Caddy on your server. +Firstly, install Caddy on your server. ```sh sudo apt install caddy -``` +``` After the installation is complete, a `Caddyfile` is created on the path `/etc/caddy/`. This file is used to configure reverse proxies among other things. -```yaml +```groovy # Caddyfile - myente.xyz is just an example. + api.myente.xyz { reverse_proxy http://localhost:8080 } + ente.myente.xyz { reverse_proxy http://localhost:3000 } + #...and so on for other endpoints ``` -After a hard-reload, the Ente Photos web app should be up on https://ente.myente.xyz. +After a hard-reload, the Ente Photos web app should be up on +https://ente.myente.xyz. If you are using a different tool for reverse proxy (like nginx), please check out their documentation. diff --git a/docs/docs/self-hosting/troubleshooting/bucket-cors.md b/docs/docs/self-hosting/troubleshooting/bucket-cors.md index 19c1dbff47..8bab1f7012 100644 --- a/docs/docs/self-hosting/troubleshooting/bucket-cors.md +++ b/docs/docs/self-hosting/troubleshooting/bucket-cors.md @@ -37,13 +37,21 @@ aws s3api put-bucket-cors --bucket YOUR_S3_BUCKET --cors-configuration /path/to/ ## For Self-hosted Minio Instance -> Important: MinIO does not take JSON CORS file as the input, instead you will -> have to build a CORS.xml file or just convert the above `cors.json` to XML. +::: warning + +- MinIO does not support bucket CORS in the community edition which is used by + default. For more information, check + [this discussion](https://github.com/minio/minio/discussions/20841). However, + global CORS configuration is possible. +- MinIO does not take JSON CORS file as the input, instead you will have to + build a CORS.xml file or just convert the above `cors.json` to XML. + +::: A minor requirement here is the tool `mc` for managing buckets via command line interface. Checkout the `mc set alias` document to configure alias for your instance and bucket. After this you will be prompted for your AccessKey and -Secret, which is your username and password, go ahead and enter that. +Secret, which is your username and password. ```sh mc cors set // api cors_allow_origin="*" You can create also `.csv` file and dump the list of origins you would like to allow and replace the `*` with `path` to the CSV file. -Now, uploads should be working fine. \ No newline at end of file +Now, uploads should be working fine. diff --git a/docs/docs/self-hosting/troubleshooting/docker.md b/docs/docs/self-hosting/troubleshooting/docker.md index 6c80070b34..158b8a63fc 100644 --- a/docs/docs/self-hosting/troubleshooting/docker.md +++ b/docs/docs/self-hosting/troubleshooting/docker.md @@ -1,5 +1,5 @@ --- -title: Docker errors +title: Docker Errors description: Fixing docker related errors when trying to self host Ente --- @@ -34,30 +34,30 @@ perform the same configuration by removing the "post_start" hook, and adding a new service definition: ```yaml - minio-provision: +minio-provision: image: minio/mc depends_on: - - minio + - minio volumes: - - minio-data:/data + - minio-data:/data networks: - - internal + - internal entrypoint: | - sh -c ' - #!/bin/sh + sh -c ' + #!/bin/sh - while ! mc config host add h0 http://minio:3200 changeme changeme1234 - do - echo "waiting for minio..." - sleep 0.5 - done + while ! mc alias set h0 http://minio:3200 your_minio_user your_minio_pass + do + echo "waiting for minio..." + sleep 0.5 + done - cd /data + cd /data - mc mb -p b2-eu-cen - mc mb -p wasabi-eu-central-2-v3 - mc mb -p scw-eu-fr-v3 - ' + mc mb -p b2-eu-cen + mc mb -p wasabi-eu-central-2-v3 + mc mb -p scw-eu-fr-v3 + ' ``` ## start_interval @@ -114,7 +114,7 @@ volumes. If you're sure of what you're doing, the volumes can be deleted by -``` +```sh docker volume ls ``` @@ -124,7 +124,54 @@ to list them, and then delete the ones that begin with `my-ente` using that'll delete all volumes (Ente or otherwise) on your machine that are not currently in use by a running docker container. +An alternative way is to delete the volumes along with removal of cluster's +containers using `docker compose` inside `my-ente` directory. + +```sh +docker compose down --volumes +``` + If you're unsure about removing volumes, another alternative is to rename your `my-ente` folder. Docker uses the folder name to determine the volume name prefix, so giving it a different name will cause Docker to create a volume afresh for it. + +## MinIO provisioning error + +If you have used our quickstart script for self-hosting Ente (new users will be unaffected) and are using the default MinIO container for object storage, you may run into issues while starting the cluster after pulling latest images with provisioning MinIO and creating buckets. + +You may encounter similar logs while trying to start the cluster: + +``` +my-ente-minio-1 -> | Waiting for minio... +my-ente-minio-1 -> | Waiting for minio... +my-ente-minio-1 -> | Waiting for minio... +``` + +MinIO has deprecated the `mc config` command in favor of `mc alias set` resulting in failure in execution of the command for creating bucket using `post_start` hook. + +This can be resolved by changing `mc config host h0 add http://minio:3200 $minio_user $minio_pass` to `mc alias set h0 http://minio:3200 $minio_user $minio_pass` + +Thus the updated `post_start` will look as follows for `minio` service: + +``` yaml + minio: + ... + post_start: + - command: | + sh -c ' + #!/bin/sh + + while ! mc alias set h0 http://minio:3200 your_minio_user your_minio_pass 2>/dev/null + do + echo "Waiting for minio..." + sleep 0.5 + done + + cd /data + + mc mb -p b2-eu-cen + mc mb -p wasabi-eu-central-2-v3 + mc mb -p scw-eu-fr-v3 + ' +``` \ No newline at end of file diff --git a/docs/docs/self-hosting/troubleshooting/keyring.md b/docs/docs/self-hosting/troubleshooting/keyring.md index 399595ba3f..56a5807fa5 100644 --- a/docs/docs/self-hosting/troubleshooting/keyring.md +++ b/docs/docs/self-hosting/troubleshooting/keyring.md @@ -5,8 +5,8 @@ description: A quick hotfix for keyring errors while running Ente CLI. # Ente CLI Secrets -Ente CLI makes use of keyring for storing sensitive information like your -passwords. And running the cli straight out of the box might give you some +Ente CLI makes use of system keyring for storing sensitive information like your +passwords. And running the CLI straight out of the box might give you some errors related to keyrings in some case. Follow the below steps to run Ente CLI and also avoid keyrings errors. diff --git a/docs/docs/self-hosting/troubleshooting/misc.md b/docs/docs/self-hosting/troubleshooting/misc.md index 65c1e7ffd1..ff6ceda762 100644 --- a/docs/docs/self-hosting/troubleshooting/misc.md +++ b/docs/docs/self-hosting/troubleshooting/misc.md @@ -3,14 +3,14 @@ title: General troubleshooting cases description: Fixing various errors when trying to self host Ente --- -## Functionality not working on self hosted +## Functionality not working on self hosted instance If some specific functionality (e.g. album listing, video playback) does not work on your self hosted instance, it is possible that you have set _some_, but not _all_ needed CSP headers (by default, CSP is not enabled). To expand on it - by default, currently the generated build does not enable CSP -headers. The generated build includes a _headers file that Cloudflare will use +headers. The generated build includes a \_headers file that Cloudflare will use to set HTTP response headers, but even these do not enable CSP, it is set to a report only mode. @@ -18,7 +18,7 @@ However, your web server might be setting some CSP policy. If so, then you will need to ensure that all necessary CSP headers are set. You can see the current -[_headers](https://github.com/ente-io/ente/blob/main/web/apps/photos/public/_headers) +[\_headers](https://github.com/ente-io/ente/blob/main/web/apps/photos/public/_headers) file contents to use a template for your CSP policy. The `Content-Security-Policy-Report-Only` value will show you the CSP headers in "dry run" report-only mode we're setting - you can use that as a template, @@ -28,8 +28,8 @@ How do you know if this is the problem you're facing? The browser console _might_ be giving you errors when you try to open the page and perform the corresponding function. -> Refused to load https://subdomain.example.org/... because it does not appear -> in the script-src directive of the Content Security Policy. +> Refused to load https://subdomain.example.org/... because it does not appear +> in the script-src directive of the Content Security Policy. This is not guaranteed, each browsers handles CSP errors differently, and some may silently swallow it. diff --git a/docs/docs/self-hosting/troubleshooting/uploads.md b/docs/docs/self-hosting/troubleshooting/uploads.md index 3dbc7454f4..6cad97f201 100644 --- a/docs/docs/self-hosting/troubleshooting/uploads.md +++ b/docs/docs/self-hosting/troubleshooting/uploads.md @@ -10,27 +10,27 @@ context and potential fixes. Fundamentally in most situations, the problem is because of minor mistakes or misconfiguration. Please make sure to reverse proxy museum and MinIO API -endpoint to a domain and check your S3 credentials and whole configuration -file for any minor misconfigurations. +endpoint to a domain and check your S3 credentials and whole configuration file +for any minor misconfigurations. -It is also suggested that the user setups bucket CORS on MinIO or any external -S3 service provider they are connecting to. To setup bucket CORS, please [read -this](/self-hosting/troubleshooting/bucket-cors). +It is also suggested that the user setups bucket CORS or global CORS on MinIO or +any external S3 service provider they are connecting to. To setup bucket CORS, +please [read this](/self-hosting/troubleshooting/bucket-cors). ## What is S3 and how is it incorporated in Ente ? -S3 is an cloud storage protocol made by Amazon (specifically AWS). S3 is designed to store -files and data as objects inside Buckets and it is mostly used for Online -Backups and storing different types of files. +S3 is an cloud storage protocol made by Amazon (specifically AWS). S3 is +designed to store files and data as objects inside buckets and it is mostly used +for online backups and storing different types of files. -Ente's Docker setup is shipped with [MinIO](https://min.io/) as its default S3 provider. -MinIO supports the Amazon S3 protocol and leverages your disk storage to -dump all the uploaded files as encrypted object blobs. +Ente's Docker setup is shipped with [MinIO](https://min.io/) as its default S3 +provider. MinIO supports the Amazon S3 protocol and leverages your disk storage +to dump all the uploaded files as encrypted object blobs. ## 403 Forbidden -If museum is able to make a network connection to your S3 bucket but -uploads are still failing, it could be a credentials or permissions issue. +If museum is able to make a network connection to your S3 bucket but uploads are +still failing, it could be a credentials or permissions issue. A telltale sign of this is that in the museum logs you can see `403 Forbidden` errors about it not able to find the size of a file even though the @@ -41,14 +41,15 @@ This could be because 1. The bucket CORS rules do not allow museum to access these objects. For uploading files from the browser, you will need to set `allowedOrigins` to `*`, and allow the `X-Auth-Token`, `X-Client-Package`, `X-Client-Version` - headers configuration too. [Here is an example of a working - configuration](https://github.com/ente-io/ente/discussions/1764#discussioncomment-9478204). + headers configuration too. + [Here is an example of a working configuration](https://github.com/ente-io/ente/discussions/1764#discussioncomment-9478204). 2. The credentials are not being picked up (you might be setting the correct credentials, but not in the place where museum reads them from). ## Mismatch in file size -The "Mismatch in file size" error mostly occurs in a situation where the client is re-uploading a file which is already in the bucket with a different -file size. The reason for re-upload could be anything including network issue, -sudden killing of app before the upload is complete and etc. +The "Mismatch in file size" error mostly occurs in a situation where the client +is re-uploading a file which is already in the bucket with a different file +size. The reason for re-upload could be anything including network issue, sudden +killing of app before the upload is complete and etc. diff --git a/docs/docs/self-hosting/troubleshooting/yarn.md b/docs/docs/self-hosting/troubleshooting/yarn.md index b4205beb0e..4cc62c405b 100644 --- a/docs/docs/self-hosting/troubleshooting/yarn.md +++ b/docs/docs/self-hosting/troubleshooting/yarn.md @@ -5,8 +5,8 @@ description: Fixing yarn install errors when trying to self host Ente # Yarn -If your `yarn install` is failing, make sure you are using Yarn v1 (also known -as "Yarn Classic"): +If `yarn install` is failing, make sure you are using Yarn v1 (also known as +"Yarn Classic"): - https://classic.yarnpkg.com/lang/en/docs/install diff --git a/docs/package.json b/docs/package.json index bd7635b126..a714aea110 100644 --- a/docs/package.json +++ b/docs/package.json @@ -5,7 +5,8 @@ "dev": "vitepress dev docs", "build": "vitepress build docs", "preview": "vitepress preview docs", - "pretty": "prettier --write ." + "pretty": "prettier --write .", + "pretty:check": "prettier -c ." }, "devDependencies": { "prettier": "^3.3.4", diff --git a/infra/workers/cast-albums/src/index.ts b/infra/workers/cast-albums/src/index.ts index 5111d446cd..fc93d93443 100644 --- a/infra/workers/cast-albums/src/index.ts +++ b/infra/workers/cast-albums/src/index.ts @@ -22,7 +22,8 @@ const handleOPTIONS = (request: Request) => { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, OPTIONS", "Access-Control-Max-Age": "86400", - "Access-Control-Allow-Headers": "X-Cast-Access-Token", + "Access-Control-Allow-Headers": + "X-Cast-Access-Token, X-Client-Package, X-Client-Version", }, }); }; @@ -60,8 +61,15 @@ const handleGET = async (request: Request) => { const pathname = url.pathname; const params = new URLSearchParams({ castToken }); + const headers = { + "X-Client-Package": request.headers.get("X-Client-Package") ?? "", + "X-Client-Version": request.headers.get("X-Client-Version") ?? "", + "User-Agent": request.headers.get("User-Agent") ?? "", + }; + let response = await fetch( `https://api.ente.io/cast/files${pathname}${fileID}?${params.toString()}`, + { headers }, ); if (!response.ok) console.log("Upstream error", response.status); diff --git a/infra/workers/cast-albums/wrangler.toml b/infra/workers/cast-albums/wrangler.toml index f81f8b52bf..3496aebe7a 100644 --- a/infra/workers/cast-albums/wrangler.toml +++ b/infra/workers/cast-albums/wrangler.toml @@ -1,6 +1,6 @@ name = "cast-albums" main = "src/index.ts" -compatibility_date = "2024-06-14" +compatibility_date = "2025-06-03" routes = [ { pattern = "cast-albums.ente.io", custom_domain = true } diff --git a/infra/workers/files/src/index.ts b/infra/workers/files/src/index.ts index 5b9452a450..904a669acc 100644 --- a/infra/workers/files/src/index.ts +++ b/infra/workers/files/src/index.ts @@ -21,7 +21,8 @@ const handleOPTIONS = (request: Request) => { headers: { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, OPTIONS", - "Access-Control-Allow-Headers": "X-Auth-Token, X-Client-Package, X-Client-Version", + "Access-Control-Allow-Headers": + "X-Auth-Token, X-Client-Package, X-Client-Version, Range", "Access-Control-Max-Age": "86400", }, }); @@ -71,13 +72,16 @@ const handleGET = async (request: Request) => { const params = new URLSearchParams(); if (token) params.set("token", token); + const headers = { + "X-Client-Package": request.headers.get("X-Client-Package") ?? "", + "X-Client-Version": request.headers.get("X-Client-Version") ?? "", + "User-Agent": request.headers.get("User-Agent") ?? "", + "Range": request.headers.get("Range") ?? "", + }; + let response = await fetch( `https://api.ente.io/files/download/${fileID}?${params.toString()}`, - { - headers: { - "User-Agent": request.headers.get("User-Agent") ?? "", - }, - }, + { headers }, ); if (!response.ok) console.log("Upstream error", response.status); diff --git a/infra/workers/files/wrangler.toml b/infra/workers/files/wrangler.toml index 52349d8d03..12e27ade88 100644 --- a/infra/workers/files/wrangler.toml +++ b/infra/workers/files/wrangler.toml @@ -1,6 +1,6 @@ name = "files" main = "src/index.ts" -compatibility_date = "2024-06-14" +compatibility_date = "2025-06-03" routes = [ { pattern = "files.ente.io", custom_domain = true } diff --git a/infra/workers/package.json b/infra/workers/package.json index e9e27cde23..7b61f25bd8 100644 --- a/infra/workers/package.json +++ b/infra/workers/package.json @@ -2,9 +2,9 @@ "name": "workers", "private": true, "devDependencies": { - "@cloudflare/workers-types": "^4.20250519.0", + "@cloudflare/workers-types": "^4.20250603.0", "typescript": "^5.8.3", - "wrangler": "^4.15.2", + "wrangler": "^4.18.0", "prettier": "^3.5.3" }, "workspaces": [ diff --git a/infra/workers/public-albums/src/index.ts b/infra/workers/public-albums/src/index.ts index 48fed6e38f..75751a867a 100644 --- a/infra/workers/public-albums/src/index.ts +++ b/infra/workers/public-albums/src/index.ts @@ -70,8 +70,15 @@ const handleGET = async (request: Request) => { if (accessToken) params.set("accessToken", accessToken); if (accessTokenJWT) params.set("accessTokenJWT", accessTokenJWT); + const headers = { + "X-Client-Package": request.headers.get("X-Client-Package") ?? "", + "X-Client-Version": request.headers.get("X-Client-Version") ?? "", + "User-Agent": request.headers.get("User-Agent") ?? "", + }; + let response = await fetch( `https://api.ente.io/public-collection/files${pathname}${fileID}?${params.toString()}`, + { headers }, ); if (!response.ok) console.log("Upstream error", response.status); diff --git a/infra/workers/public-albums/wrangler.toml b/infra/workers/public-albums/wrangler.toml index 9adad20f04..4643736fd6 100644 --- a/infra/workers/public-albums/wrangler.toml +++ b/infra/workers/public-albums/wrangler.toml @@ -1,6 +1,6 @@ name = "public-albums" main = "src/index.ts" -compatibility_date = "2024-06-14" +compatibility_date = "2025-06-03" routes = [ { pattern = "public-albums.ente.io", custom_domain = true } diff --git a/infra/workers/thumbnails/src/index.ts b/infra/workers/thumbnails/src/index.ts index 2108e50258..2e2bd89733 100644 --- a/infra/workers/thumbnails/src/index.ts +++ b/infra/workers/thumbnails/src/index.ts @@ -21,7 +21,8 @@ const handleOPTIONS = (request: Request) => { headers: { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, OPTIONS", - "Access-Control-Allow-Headers": "X-Auth-Token, X-Client-Package, X-Client-Version", + "Access-Control-Allow-Headers": + "X-Auth-Token, X-Client-Package, X-Client-Version", "Access-Control-Max-Age": "86400", }, }); @@ -64,8 +65,15 @@ const handleGET = async (request: Request) => { const params = new URLSearchParams(); if (token) params.set("token", token); + const headers = { + "X-Client-Package": request.headers.get("X-Client-Package") ?? "", + "X-Client-Version": request.headers.get("X-Client-Version") ?? "", + "User-Agent": request.headers.get("User-Agent") ?? "", + }; + let response = await fetch( `https://api.ente.io/files/preview/${fileID}?${params.toString()}`, + { headers }, ); if (!response.ok) console.log("Upstream error", response.status); diff --git a/infra/workers/thumbnails/wrangler.toml b/infra/workers/thumbnails/wrangler.toml index 8f45b859e8..8c7117c848 100644 --- a/infra/workers/thumbnails/wrangler.toml +++ b/infra/workers/thumbnails/wrangler.toml @@ -1,6 +1,6 @@ name = "thumbnails" main = "src/index.ts" -compatibility_date = "2024-06-14" +compatibility_date = "2025-06-03" routes = [ { pattern = "thumbnails.ente.io", custom_domain = true } diff --git a/mobile/android/app/build.gradle b/mobile/android/app/build.gradle index 8c3148fae8..e96f0456e1 100644 --- a/mobile/android/app/build.gradle +++ b/mobile/android/app/build.gradle @@ -142,4 +142,14 @@ dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + + + constraints { + implementation("androidx.work:work-runtime:2.8.1") { + because("Align work-runtime versions") + } + implementation("androidx.work:work-runtime-ktx:2.8.1") { + because("Align work-runtime-ktx versions") + } + } } \ No newline at end of file diff --git a/mobile/android/app/src/main/res/xml/network_security_config.xml b/mobile/android/app/src/main/res/xml/network_security_config.xml index 5d942a942e..a7a11ec732 100644 --- a/mobile/android/app/src/main/res/xml/network_security_config.xml +++ b/mobile/android/app/src/main/res/xml/network_security_config.xml @@ -1,5 +1,5 @@ - + diff --git a/mobile/android/build.gradle b/mobile/android/build.gradle index 236cc5f28f..012656ea4c 100644 --- a/mobile/android/build.gradle +++ b/mobile/android/build.gradle @@ -9,9 +9,6 @@ allprojects { jcenter() mavenCentral() mavenLocal() // for FDroid -// maven { -// url "${project(':background_fetch').projectDir}/libs" -// } // maven { // url "${project(':ffmpeg_kit_flutter').projectDir}/libs" // } diff --git a/mobile/assets/icons/list_view_icon_dark.svg b/mobile/assets/icons/list_view_icon_dark.svg new file mode 100644 index 0000000000..2e6c9e945f --- /dev/null +++ b/mobile/assets/icons/list_view_icon_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/mobile/assets/icons/list_view_icon_light.svg b/mobile/assets/icons/list_view_icon_light.svg new file mode 100644 index 0000000000..3f62c7ad02 --- /dev/null +++ b/mobile/assets/icons/list_view_icon_light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/mobile/assets/icons/search_icon_dark.svg b/mobile/assets/icons/search_icon_dark.svg new file mode 100644 index 0000000000..785e84064a --- /dev/null +++ b/mobile/assets/icons/search_icon_dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/mobile/assets/icons/search_icon_light.svg b/mobile/assets/icons/search_icon_light.svg new file mode 100644 index 0000000000..13d557692a --- /dev/null +++ b/mobile/assets/icons/search_icon_light.svg @@ -0,0 +1,3 @@ + + + diff --git a/mobile/docs/vscode/launch.json b/mobile/docs/vscode/launch.json index 437d6ac30a..80d910083b 100644 --- a/mobile/docs/vscode/launch.json +++ b/mobile/docs/vscode/launch.json @@ -10,7 +10,12 @@ "type": "dart", "flutterMode": "debug", "program": "mobile/lib/main.dart", - "args": ["--flavor", "independent"] + "args": [ + "--flavor", + "independent", + "--dart-define", + "cronetHttpNoPlay=true" + ] }, { "name": "Photos Android Local", @@ -24,7 +29,9 @@ "--dart-define", "endpoint=http://localhost:8080", "--dart-define", - "web-family=http://localhost:3003" + "web-family=http://localhost:3003", + "--dart-define", + "cronetHttpNoPlay=true" ] }, { diff --git a/mobile/fastlane/metadata/android/ku/full_description.txt b/mobile/fastlane/metadata/android/ku/full_description.txt new file mode 100644 index 0000000000..9ba4fe3143 --- /dev/null +++ b/mobile/fastlane/metadata/android/ku/full_description.txt @@ -0,0 +1,36 @@ +ente is a simple app to backup and share your photos and videos. + +If you've been looking for a privacy-friendly alternative to Google Photos, you've come to the right place. With ente, they are stored end-to-end encrypted (e2ee). This means that only you can view them. + +We have open-source apps across Android, iOS, web and desktop, and your photos will seamlessly sync between all of them in an end-to-end encrypted (e2ee) manner. + +ente also makes it simple to share your albums with your loved ones, even if they aren't on ente. You can share publicly viewable links, where they can view your album and collaborate by adding photos to it, even without an account or app. + +Your encrypted data is replicated to 3 different locations, including a fall-out shelter in Paris. We take posterity seriously and make it easy to ensure that your memories outlive you. + +We are here to make the safest photos app ever, come join our journey! + +FEATURES +- Original quality backups, because every pixel is important +- Family plans, so you can share storage with your family +- Collaborative albums, so you can pool together photos after a trip +- Shared folders, in case you want your partner to enjoy your "Camera" clicks +- Album links, that can be protected with a password +- Ability to free up space, by removing files that have been safely backed up +- Human support, because you're worth it +- Descriptions, so you can caption your memories and find them easily +- Image editor, to add finishing touches +- Favorite, hide and relive your memories, for they are precious +- One-click import from Google, Apple, your hard drive and more +- Dark theme, because your photos look good in it +- 2FA, 3FA, biometric auth +- and a LOT more! + +PERMISSIONS +ente requests for certain permissions to serve the purpose of a photo storage provider, which can be reviewed here: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md + +PRICING +We don't offer forever free plans, because it is important to us that we remain sustainable and withstand the test of time. Instead we offer affordable plans that you can freely share with your family. You can find more information at ente.io. + +SUPPORT +We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours. diff --git a/mobile/fastlane/metadata/android/ku/short_description.txt b/mobile/fastlane/metadata/android/ku/short_description.txt new file mode 100644 index 0000000000..7a5fe973db --- /dev/null +++ b/mobile/fastlane/metadata/android/ku/short_description.txt @@ -0,0 +1 @@ +ente is an end-to-end encrypted photo storage app \ No newline at end of file diff --git a/mobile/fastlane/metadata/android/ku/title.txt b/mobile/fastlane/metadata/android/ku/title.txt new file mode 100644 index 0000000000..3a4fed48fe --- /dev/null +++ b/mobile/fastlane/metadata/android/ku/title.txt @@ -0,0 +1 @@ +ente - encrypted photo storage \ No newline at end of file diff --git a/mobile/fastlane/metadata/android/pt_PT/full_description.txt b/mobile/fastlane/metadata/android/pt_PT/full_description.txt index 38a7c1b83f..9cd11069c4 100644 --- a/mobile/fastlane/metadata/android/pt_PT/full_description.txt +++ b/mobile/fastlane/metadata/android/pt_PT/full_description.txt @@ -4,33 +4,33 @@ Se busca por uma alternativa do Google Fotos baseada em privacidade, chegaste ao Temos aplicações de fonte aberta para Android, iOS, sítio web e desktop, e as fotos serão perfeitamente sincronizadas entre todas elas numa maneira de encriptação de ponta a ponta (e2ee). -Ente também simplifica a partilha dos seus álbuns com os seus entes queridos, mesmo que estes não estejam no ente. Pode partilhar ligações visíveis publicamente, onde podem ver o seu álbum e colaborar adicionando fotografias ao mesmo, mesmo sem uma conta ou aplicação. +Ente facilita o partilhamento dos seus álbuns com entes queridos, mesmo se não estiverem no ente. Pode partilhar ligações visíveis a público, onde eles podem ver o seu álbum e colaborar a adicionar fotos, mesmo sem uma conta ou a aplicação. -Os seus dados encriptados são replicados em 3 locais diferentes, incluindo um abrigo de emergência em Paris. Levamos a posteridade a sério e facilitamos a tarefa de garantir que as suas memórias perdurem para além de si. +Os dados são replicados em 3 localizações diferentes, incluindo um posto em Paris. Levamos a nossa postura a sério e facilitamos para certificarmos que as suas memórias revivam-no. -Estamos aqui para criar a aplicação de fotografias mais segura de sempre, junte-se à nossa viagem! +Estamos aqui para fazer a aplicação mais segura do mundo, venha e adere a nossa jornada! -RECURSOS -- Cópias de segurança de qualidade original, porque cada pixel é importante -- Planos familiares, para que possa partilhar o armazenamento com a sua família -- Álbuns colaborativos, para que possa reunir fotos depois de uma viagem -- Pastas partilhadas, caso queira que o seu parceiro desfrute dos seus cliques na “Câmara” -- Links para álbuns, que podem ser protegidas com uma palavra-passe -- Capacidade de libertar espaço, removendo ficheiros dos quais foi feita uma cópia de segurança segura -- Apoio humano, porque vale a pena -- Descrições, para que possa legendar as suas memórias e encontrá-las facilmente -- Editor de imagens, para dar os retoques finais -- Favoritar, ocultar e reviver suas memórias, pois elas são preciosas -- Importação com um clique do Google, da Apple, do seu disco rígido e muito mais -- Tema escuro, porque as suas fotos ficam bem com ele +FUNCIONALIDADES +- Backups com qualidade original, por cada píxel valer a pena +- Planos em família, para poder partilhar armazenamento com familiares +- Álbuns de colaboração, para unir fotos depois de uma caminhada +- Pastas partilhadas, se quiser que o seu parceiro desfrute dos seus cliques na "Câmara" +- Ligações para álbuns, que podem ser protegidos com uma palavra-passe +- Possibilidade de liberar espaço, removendo ficheiros que já foram feitos backup +- Suporte físico, por valer a pena +- Descrições, para entender as suas memórias e encontrá-las facilmente +- Editor de imagens, para dar retoques finais +- Adicionar aos favoritos, obscurecer e reviver as suas memórias, para aqueles tão preciosos +- Importar num só clique do Google, Apple, e o seu disco rígido e mais +- Tema escuro, para as suas fotos encaixarem melhor - 2FA, 3FA, autenticação biométrica -- e MUITO mais! +- e MAIS além! PERMISSÕES -ente solicita determinadas permissões para servir o objetivo de um fornecedor de armazenamento de fotografias, que pode ser consultado aqui: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md +Ente pede por certas permissões para servir o propósito dum provedor de armazenamento de foto, onde pode ser revisto aqui: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md PREÇO -Não oferecemos planos gratuitos para sempre, porque é importante para nós mantermo-nos sustentáveis e resistirmos ao teste do tempo. Em vez disso, oferecemos planos acessíveis que pode partilhar livremente com a sua família. Pode encontrar mais informações em ente.io. +Não garantimos planos gratuitos para sempre, já que é importante a nós mantermo-nos sustentáveis e conseguirmos superar o desafio do tempo. Ao invés, garantimos planos acessíveis para poder partilhar livremente com os seus familiares. Para mais informações, consulte "ente.io" -SUPPORT -Orgulhamo-nos de oferecer um apoio humano Se for nosso cliente pago, pode contactar team@ente.io e esperar uma resposta da nossa equipa no prazo de 24 horas. +SUPORTE +Estamos orgulhosos ao oferecer suporte físico. Se for um cliente pago, pode contactar a nossa equipa através de "team@ente.io" e esperar uma resposta nossa dentro de um dia. diff --git a/mobile/fastlane/metadata/android/sr/full_description.txt b/mobile/fastlane/metadata/android/sr/full_description.txt new file mode 100644 index 0000000000..9ba4fe3143 --- /dev/null +++ b/mobile/fastlane/metadata/android/sr/full_description.txt @@ -0,0 +1,36 @@ +ente is a simple app to backup and share your photos and videos. + +If you've been looking for a privacy-friendly alternative to Google Photos, you've come to the right place. With ente, they are stored end-to-end encrypted (e2ee). This means that only you can view them. + +We have open-source apps across Android, iOS, web and desktop, and your photos will seamlessly sync between all of them in an end-to-end encrypted (e2ee) manner. + +ente also makes it simple to share your albums with your loved ones, even if they aren't on ente. You can share publicly viewable links, where they can view your album and collaborate by adding photos to it, even without an account or app. + +Your encrypted data is replicated to 3 different locations, including a fall-out shelter in Paris. We take posterity seriously and make it easy to ensure that your memories outlive you. + +We are here to make the safest photos app ever, come join our journey! + +FEATURES +- Original quality backups, because every pixel is important +- Family plans, so you can share storage with your family +- Collaborative albums, so you can pool together photos after a trip +- Shared folders, in case you want your partner to enjoy your "Camera" clicks +- Album links, that can be protected with a password +- Ability to free up space, by removing files that have been safely backed up +- Human support, because you're worth it +- Descriptions, so you can caption your memories and find them easily +- Image editor, to add finishing touches +- Favorite, hide and relive your memories, for they are precious +- One-click import from Google, Apple, your hard drive and more +- Dark theme, because your photos look good in it +- 2FA, 3FA, biometric auth +- and a LOT more! + +PERMISSIONS +ente requests for certain permissions to serve the purpose of a photo storage provider, which can be reviewed here: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md + +PRICING +We don't offer forever free plans, because it is important to us that we remain sustainable and withstand the test of time. Instead we offer affordable plans that you can freely share with your family. You can find more information at ente.io. + +SUPPORT +We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours. diff --git a/mobile/fastlane/metadata/android/sr/short_description.txt b/mobile/fastlane/metadata/android/sr/short_description.txt new file mode 100644 index 0000000000..7a5fe973db --- /dev/null +++ b/mobile/fastlane/metadata/android/sr/short_description.txt @@ -0,0 +1 @@ +ente is an end-to-end encrypted photo storage app \ No newline at end of file diff --git a/mobile/fastlane/metadata/android/sr/title.txt b/mobile/fastlane/metadata/android/sr/title.txt new file mode 100644 index 0000000000..3a4fed48fe --- /dev/null +++ b/mobile/fastlane/metadata/android/sr/title.txt @@ -0,0 +1 @@ +ente - encrypted photo storage \ No newline at end of file diff --git a/mobile/fastlane/metadata/ios/ku/description.txt b/mobile/fastlane/metadata/ios/ku/description.txt new file mode 100644 index 0000000000..a98a74300a --- /dev/null +++ b/mobile/fastlane/metadata/ios/ku/description.txt @@ -0,0 +1,33 @@ +Ente is a simple app to automatically backup and organize your photos and videos. + +If you've been looking for a privacy-friendly alternative to preserve your memories, you've come to the right place. With Ente, they are stored end-to-end encrypted (e2ee). This means that only you can view them. + +We have apps across all platforms, and your photos will seamlessly sync between all your devices in an end-to-end encrypted (e2ee) manner. + +Ente also makes it simple to share your albums with your loved ones. You can either share them directly with other Ente users, end-to-end encrypted; or with publicly viewable links. + +Your encrypted data is stored across multiple locations, including a fall-out shelter in Paris. We take posterity seriously and make it easy to ensure that your memories outlive you. + +We are here to make the safest photos app ever, come join our journey! + +FEATURES +- Original quality backups, because every pixel is important +- Family plans, so you can share storage with your family +- Shared folders, in case you want your partner to enjoy your "Camera" clicks +- Album links, that can be protected with a password and set to expire +- Ability to free up space, by removing files that have been safely backed up +- Image editor, to add finishing touches +- Favorite, hide and relive your memories, for they are precious +- One-click import from all major storage providers +- Dark theme, because your photos look good in it +- 2FA, 3FA, biometric auth +- and a LOT more! + +PRICING +We don't offer forever free plans, because it is important to us that we remain sustainable and withstand the test of time. Instead we offer affordable plans that you can freely share with your family. You can find more information at ente.io. + +SUPPORT +We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours. + +TERMS +https://ente.io/terms diff --git a/mobile/fastlane/metadata/ios/ku/keywords.txt b/mobile/fastlane/metadata/ios/ku/keywords.txt new file mode 100644 index 0000000000..e1462baf51 --- /dev/null +++ b/mobile/fastlane/metadata/ios/ku/keywords.txt @@ -0,0 +1 @@ +photos,photography,family,privacy,cloud,backup,videos,photo,encryption,storage,album,alternative diff --git a/mobile/fastlane/metadata/ios/ku/name.txt b/mobile/fastlane/metadata/ios/ku/name.txt new file mode 100644 index 0000000000..3a991c4abc --- /dev/null +++ b/mobile/fastlane/metadata/ios/ku/name.txt @@ -0,0 +1 @@ +Ente Photos diff --git a/mobile/fastlane/metadata/ios/ku/subtitle.txt b/mobile/fastlane/metadata/ios/ku/subtitle.txt new file mode 100644 index 0000000000..958a35f1c9 --- /dev/null +++ b/mobile/fastlane/metadata/ios/ku/subtitle.txt @@ -0,0 +1 @@ +Encrypted photo storage diff --git a/mobile/fastlane/metadata/ios/sr/description.txt b/mobile/fastlane/metadata/ios/sr/description.txt new file mode 100644 index 0000000000..a98a74300a --- /dev/null +++ b/mobile/fastlane/metadata/ios/sr/description.txt @@ -0,0 +1,33 @@ +Ente is a simple app to automatically backup and organize your photos and videos. + +If you've been looking for a privacy-friendly alternative to preserve your memories, you've come to the right place. With Ente, they are stored end-to-end encrypted (e2ee). This means that only you can view them. + +We have apps across all platforms, and your photos will seamlessly sync between all your devices in an end-to-end encrypted (e2ee) manner. + +Ente also makes it simple to share your albums with your loved ones. You can either share them directly with other Ente users, end-to-end encrypted; or with publicly viewable links. + +Your encrypted data is stored across multiple locations, including a fall-out shelter in Paris. We take posterity seriously and make it easy to ensure that your memories outlive you. + +We are here to make the safest photos app ever, come join our journey! + +FEATURES +- Original quality backups, because every pixel is important +- Family plans, so you can share storage with your family +- Shared folders, in case you want your partner to enjoy your "Camera" clicks +- Album links, that can be protected with a password and set to expire +- Ability to free up space, by removing files that have been safely backed up +- Image editor, to add finishing touches +- Favorite, hide and relive your memories, for they are precious +- One-click import from all major storage providers +- Dark theme, because your photos look good in it +- 2FA, 3FA, biometric auth +- and a LOT more! + +PRICING +We don't offer forever free plans, because it is important to us that we remain sustainable and withstand the test of time. Instead we offer affordable plans that you can freely share with your family. You can find more information at ente.io. + +SUPPORT +We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours. + +TERMS +https://ente.io/terms diff --git a/mobile/fastlane/metadata/ios/sr/keywords.txt b/mobile/fastlane/metadata/ios/sr/keywords.txt new file mode 100644 index 0000000000..e1462baf51 --- /dev/null +++ b/mobile/fastlane/metadata/ios/sr/keywords.txt @@ -0,0 +1 @@ +photos,photography,family,privacy,cloud,backup,videos,photo,encryption,storage,album,alternative diff --git a/mobile/fastlane/metadata/ios/sr/name.txt b/mobile/fastlane/metadata/ios/sr/name.txt new file mode 100644 index 0000000000..3a991c4abc --- /dev/null +++ b/mobile/fastlane/metadata/ios/sr/name.txt @@ -0,0 +1 @@ +Ente Photos diff --git a/mobile/fastlane/metadata/ios/sr/subtitle.txt b/mobile/fastlane/metadata/ios/sr/subtitle.txt new file mode 100644 index 0000000000..958a35f1c9 --- /dev/null +++ b/mobile/fastlane/metadata/ios/sr/subtitle.txt @@ -0,0 +1 @@ +Encrypted photo storage diff --git a/mobile/fastlane/metadata/playstore/ku/full_description.txt b/mobile/fastlane/metadata/playstore/ku/full_description.txt new file mode 100644 index 0000000000..ec999a783c --- /dev/null +++ b/mobile/fastlane/metadata/playstore/ku/full_description.txt @@ -0,0 +1,30 @@ +Ente is a simple app to automatically backup and organize your photos and videos. + +If you've been looking for a privacy-friendly alternative to preserve your memories, you've come to the right place. With Ente, they are stored end-to-end encrypted (e2ee). This means that only you can view them. + +We have apps across Android, iOS, web and Desktop, and your photos will seamlessly sync between all your devices in an end-to-end encrypted (e2ee) manner. + +Ente also makes it simple to share your albums with your loved ones. You can either share them directly with other Ente users, end-to-end encrypted; or with publicly viewable links. + +Your encrypted data is stored across multiple locations, including a fall-out shelter in Paris. We take posterity seriously and make it easy to ensure that your memories outlive you. + +We are here to make the safest photos app ever, come join our journey! + +✨ FEATURES +- Original quality backups, because every pixel is important +- Family plans, so you can share storage with your family +- Shared folders, in case you want your partner to enjoy your "Camera" clicks +- Album links, that can be protected with a password and set to expire +- Ability to free up space, by removing files that have been safely backed up +- Image editor, to add finishing touches +- Favorite, hide and relive your memories, for they are precious +- One-click import from Google, Apple, your hard drive and more +- Dark theme, because your photos look good in it +- 2FA, 3FA, biometric auth +- and a LOT more! + +💲 PRICING +We don't offer forever free plans, because it is important to us that we remain sustainable and withstand the test of time. Instead we offer affordable plans that you can freely share with your family. You can find more information at ente.io. + +🙋 SUPPORT +We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours. \ No newline at end of file diff --git a/mobile/fastlane/metadata/playstore/ku/short_description.txt b/mobile/fastlane/metadata/playstore/ku/short_description.txt new file mode 100644 index 0000000000..6c00229894 --- /dev/null +++ b/mobile/fastlane/metadata/playstore/ku/short_description.txt @@ -0,0 +1 @@ +Encrypted photo storage - backup, organize and share your photos and videos \ No newline at end of file diff --git a/mobile/fastlane/metadata/playstore/ku/title.txt b/mobile/fastlane/metadata/playstore/ku/title.txt new file mode 100644 index 0000000000..97fdef3be7 --- /dev/null +++ b/mobile/fastlane/metadata/playstore/ku/title.txt @@ -0,0 +1 @@ +Ente Photos \ No newline at end of file diff --git a/mobile/fastlane/metadata/playstore/pt_PT/full_description.txt b/mobile/fastlane/metadata/playstore/pt_PT/full_description.txt index f1757bf090..618f0cc718 100644 --- a/mobile/fastlane/metadata/playstore/pt_PT/full_description.txt +++ b/mobile/fastlane/metadata/playstore/pt_PT/full_description.txt @@ -2,29 +2,29 @@ Ente é uma aplicação simples feita para fazer backup automaticamente e organi Se busca por uma alternativa mais privada para preservar as suas memórias, chegaste ao lugar correto. Com Ente, eles são armazenados em encriptação de ponta a ponta (e2ee). Isto significa que só vos podeis vê-las. -Temos aplicações para Android, iOS, Web e ambiente de trabalho, e as suas fotografias serão perfeitamente sincronizadas entre todos os seus dispositivos de uma forma encriptada de ponta a ponta (e2ee). +Nós temos aplicações em Android, iOS, Sítio Web e Desktop, todas as suas fotos são sincronizadas sem parar entre os aparelhos numa forma de encriptação (e2ee). -O Ente também simplifica a partilha dos seus álbuns com os seus entes queridos Pode partilhá-los diretamente com outros utilizadores do Ente, encriptados de ponta a ponta, ou com ligações publicamente visíveis. +Ente também facilita a partilha de álbuns com entes queridos. É possível partilhá-los diretamente com outros utilizadores, em encriptação ponta-a-ponta; ou com ligações visíveis a público. -Os seus dados encriptados são armazenados em vários locais, incluindo um abrigo de emergência em Paris. Levamos a posteridade a sério e facilitamos a tarefa de garantir que as suas memórias perdurem para além de si. +Os seus dados encriptados são armazenados em várias localizações, incluindo um abrigo avançado em Paris. Levamos a nossa postura a sério e facilitamos para certificarmos que as suas memórias revivam-no. -Estamos aqui para criar a aplicação de fotografias mais segura de sempre, junte-se à nossa viagem! +Estamos aqui para fazer a aplicação mais segura do mundo, venha e adere a nossa jornada! -✨ RECURSOS -- Cópias de segurança de qualidade original, porque cada pixel é importante -- Planos familiares, para que possa partilhar o armazenamento com a sua família -- Pastas partilhadas, caso queira que o seu parceiro desfrute dos seus cliques na “Câmara” -- Links para álbuns, que podem ser protegidas com uma palavra-passe e definidas para expirar -- Capacidade de libertar espaço, removendo ficheiros dos quais foi feita uma cópia de segurança segura -- Editor de imagens, para dar os retoques finais -- Favoritar, ocultar e reviver suas memórias, pois elas são preciosas -- Importação com um clique do Google, da Apple, do seu disco rígido e muito mais -- Tema escuro, porque as suas fotografias ficam bem com ele +✨ FUNCIONALIDADES +- Backups com qualidade original, por cada píxel valer a pena +- Planos em família, para poder partilhar armazenamento com familiares +- Pastas partilhadas, para que o seu parceiro desfrute de cliques na "Câmara" +- Links de álbuns, para poder ser protegido por uma palavra-passe e definido para expiração +- Possibilidade de liberar espaço, removendo ficheiros que já foram feitos backup +- Editor de imagens, para dar retoques finais +- Adicionar aos favoritos, obscurecer e reviver as suas memórias, para aqueles tão preciosos +- Importar num só clique do Google, Apple, e o seu disco rígido e mais +- Tema escuro, para as suas fotos encaixarem melhor - 2FA, 3FA, autenticação biométrica -- and a LOT more! +- e MAIS além! 💲 PREÇOS -Não oferecemos planos gratuitos para sempre, porque é importante para nós mantermo-nos sustentáveis e resistirmos ao teste do tempo. Em vez disso, oferecemos planos acessíveis que pode partilhar livremente com a sua família. Pode encontrar mais informações em ente.io. +Não garantimos planos gratuitos para sempre, já que é importante a nós mantermo-nos sustentáveis e conseguirmos superar o desafio do tempo. Ao invés, garantimos planos acessíveis para poder partilhar livremente com os seus familiares. Para mais informações, consulte "ente.io" -🙋 SUPPORT -Orgulhamo-nos de oferecer um apoio humano. Se for nosso cliente pago, pode contactar team@ente.io e esperar uma resposta da nossa equipa no prazo de 24 horas. \ No newline at end of file +🙋 SUPORTE +Estamos orgulhosos ao oferecer suporte físico. Se for um cliente pago, pode contactar a nossa equipa através de "team@ente.io" e esperar uma resposta nossa dentro de um dia. \ No newline at end of file diff --git a/mobile/fastlane/metadata/playstore/sr/full_description.txt b/mobile/fastlane/metadata/playstore/sr/full_description.txt new file mode 100644 index 0000000000..ec999a783c --- /dev/null +++ b/mobile/fastlane/metadata/playstore/sr/full_description.txt @@ -0,0 +1,30 @@ +Ente is a simple app to automatically backup and organize your photos and videos. + +If you've been looking for a privacy-friendly alternative to preserve your memories, you've come to the right place. With Ente, they are stored end-to-end encrypted (e2ee). This means that only you can view them. + +We have apps across Android, iOS, web and Desktop, and your photos will seamlessly sync between all your devices in an end-to-end encrypted (e2ee) manner. + +Ente also makes it simple to share your albums with your loved ones. You can either share them directly with other Ente users, end-to-end encrypted; or with publicly viewable links. + +Your encrypted data is stored across multiple locations, including a fall-out shelter in Paris. We take posterity seriously and make it easy to ensure that your memories outlive you. + +We are here to make the safest photos app ever, come join our journey! + +✨ FEATURES +- Original quality backups, because every pixel is important +- Family plans, so you can share storage with your family +- Shared folders, in case you want your partner to enjoy your "Camera" clicks +- Album links, that can be protected with a password and set to expire +- Ability to free up space, by removing files that have been safely backed up +- Image editor, to add finishing touches +- Favorite, hide and relive your memories, for they are precious +- One-click import from Google, Apple, your hard drive and more +- Dark theme, because your photos look good in it +- 2FA, 3FA, biometric auth +- and a LOT more! + +💲 PRICING +We don't offer forever free plans, because it is important to us that we remain sustainable and withstand the test of time. Instead we offer affordable plans that you can freely share with your family. You can find more information at ente.io. + +🙋 SUPPORT +We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours. \ No newline at end of file diff --git a/mobile/fastlane/metadata/playstore/sr/short_description.txt b/mobile/fastlane/metadata/playstore/sr/short_description.txt new file mode 100644 index 0000000000..6c00229894 --- /dev/null +++ b/mobile/fastlane/metadata/playstore/sr/short_description.txt @@ -0,0 +1 @@ +Encrypted photo storage - backup, organize and share your photos and videos \ No newline at end of file diff --git a/mobile/fastlane/metadata/playstore/sr/title.txt b/mobile/fastlane/metadata/playstore/sr/title.txt new file mode 100644 index 0000000000..97fdef3be7 --- /dev/null +++ b/mobile/fastlane/metadata/playstore/sr/title.txt @@ -0,0 +1 @@ +Ente Photos \ No newline at end of file diff --git a/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetDefault.imageset/AlbumsWidgetDefault.png b/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetDefault.imageset/AlbumsWidgetDefault.png new file mode 100644 index 0000000000..7ffe666ae9 Binary files /dev/null and b/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetDefault.imageset/AlbumsWidgetDefault.png differ diff --git a/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetDefault.imageset/Contents.json b/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetDefault.imageset/Contents.json new file mode 100644 index 0000000000..4ed24e6d76 --- /dev/null +++ b/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetDefault.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "AlbumsWidgetDefault.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetPreview.imageset/AlbumsWidgetPreview.png b/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetPreview.imageset/AlbumsWidgetPreview.png new file mode 100644 index 0000000000..a0ad77e39c Binary files /dev/null and b/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetPreview.imageset/AlbumsWidgetPreview.png differ diff --git a/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetPreview.imageset/Contents.json b/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetPreview.imageset/Contents.json new file mode 100644 index 0000000000..de3cb3c542 --- /dev/null +++ b/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetPreview.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "AlbumsWidgetPreview.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/mobile/ios/EnteAlbumWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json b/mobile/ios/EnteAlbumWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json index eb87897008..c47b5f2f12 100644 --- a/mobile/ios/EnteAlbumWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json +++ b/mobile/ios/EnteAlbumWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json @@ -1,11 +1,6 @@ { - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 + "info": { + "author": "xcode", + "version": 1 } -} +} \ No newline at end of file diff --git a/mobile/ios/EnteAlbumWidget/EnteAlbumWidget.swift b/mobile/ios/EnteAlbumWidget/EnteAlbumWidget.swift index 0a4f9d6e76..c6712c7289 100644 --- a/mobile/ios/EnteAlbumWidget/EnteAlbumWidget.swift +++ b/mobile/ios/EnteAlbumWidget/EnteAlbumWidget.swift @@ -1,10 +1,6 @@ // // EnteAlbumWidget.swift // EnteAlbumWidget -// -// Created by Prateek Sunal on 5/15/25. -// Copyright © 2025 The Chromium Authors. All rights reserved. -// import SwiftUI import UIKit @@ -92,11 +88,6 @@ struct FileEntry: TimelineEntry { struct EnteAlbumWidgetEntryView: View { var entry: Provider.Entry - let defaultBase64Image = - "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" - let defaultBase64Preview = - "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" - let data = UserDefaults.init(suiteName: widgetGroupId) var body: some View { @@ -139,11 +130,7 @@ struct EnteAlbumWidgetEntryView: View { alignment: .bottomLeading ) } else if entry.index == -2 { - if let data = Data( - base64Encoded: defaultBase64Preview - ), - let uiImage = UIImage(data: data) - { + if let uiImage = UIImage(named: "AlbumsWidgetPreview") { Image(uiImage: uiImage) .resizable() .backwardWidgetFullColorRenderingMode() @@ -180,10 +167,7 @@ struct EnteAlbumWidgetEntryView: View { alignment: .bottomLeading ) } - } else if let imgData = Data( - base64Encoded: defaultBase64Image), - let uiImage = UIImage(data: imgData) - { + } else if let uiImage = UIImage(named: "AlbumsWidgetDefault") { VStack(spacing: 8) { Spacer() Image(uiImage: uiImage) diff --git a/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetDefault.imageset/Contents.json b/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetDefault.imageset/Contents.json new file mode 100644 index 0000000000..6939b024f5 --- /dev/null +++ b/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetDefault.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "MemoriesWidgetDefault.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetDefault.imageset/MemoriesWidgetDefault.png b/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetDefault.imageset/MemoriesWidgetDefault.png new file mode 100644 index 0000000000..616d6f3148 Binary files /dev/null and b/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetDefault.imageset/MemoriesWidgetDefault.png differ diff --git a/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetPreview.imageset/Contents.json b/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetPreview.imageset/Contents.json new file mode 100644 index 0000000000..b0162fa9b2 --- /dev/null +++ b/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetPreview.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "MemoriesWidgetPreview.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetPreview.imageset/MemoriesWidgetPreview.png b/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetPreview.imageset/MemoriesWidgetPreview.png new file mode 100644 index 0000000000..b32ee34731 Binary files /dev/null and b/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetPreview.imageset/MemoriesWidgetPreview.png differ diff --git a/mobile/ios/EnteMemoryWidget/EnteMemoryWidget.swift b/mobile/ios/EnteMemoryWidget/EnteMemoryWidget.swift index 4382deab9b..8a5e06abe8 100644 --- a/mobile/ios/EnteMemoryWidget/EnteMemoryWidget.swift +++ b/mobile/ios/EnteMemoryWidget/EnteMemoryWidget.swift @@ -1,10 +1,6 @@ // // EnteMemoryWidget.swift // EnteMemoryWidget -// -// Created by Prateek Sunal on 3/7/25. -// Copyright © 2025 The Chromium Authors. All rights reserved. -// import SwiftUI import UIKit @@ -89,12 +85,6 @@ struct FileEntry: TimelineEntry { struct EnteMemoryWidgetEntryView: View { var entry: Provider.Entry - let defaultBase64Image = - "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" - - let defaultBase64Preview = - "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" - let data = UserDefaults.init(suiteName: widgetGroupId) var body: some View { @@ -137,11 +127,7 @@ struct EnteMemoryWidgetEntryView: View { alignment: .bottomLeading ) } else if entry.index == -2 { - if let data = Data( - base64Encoded: defaultBase64Preview - ), - let uiImage = UIImage(data: data) - { + if let uiImage = UIImage(named: "MemoriesWidgetPreview") { Image(uiImage: uiImage) .resizable() .backwardWidgetFullColorRenderingMode() @@ -178,10 +164,7 @@ struct EnteMemoryWidgetEntryView: View { alignment: .bottomLeading ) } - } else if let data = Data( - base64Encoded: defaultBase64Image), - let uiImage = UIImage(data: data) - { + } else if let uiImage = UIImage(named: "MemoriesWidgetDefault") { VStack(spacing: 8) { Spacer() Image(uiImage: uiImage) diff --git a/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetDefault.imageset/Contents.json b/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetDefault.imageset/Contents.json new file mode 100644 index 0000000000..69d59a1081 --- /dev/null +++ b/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetDefault.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "PeopleWidgetDefault.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetDefault.imageset/PeopleWidgetDefault.png b/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetDefault.imageset/PeopleWidgetDefault.png new file mode 100644 index 0000000000..f935479c04 Binary files /dev/null and b/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetDefault.imageset/PeopleWidgetDefault.png differ diff --git a/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetPreview.imageset/Contents.json b/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetPreview.imageset/Contents.json new file mode 100644 index 0000000000..47b392a1ff --- /dev/null +++ b/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetPreview.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "PeopleWidgetPreview.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetPreview.imageset/PeopleWidgetPreview.png b/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetPreview.imageset/PeopleWidgetPreview.png new file mode 100644 index 0000000000..b2e27c654c Binary files /dev/null and b/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetPreview.imageset/PeopleWidgetPreview.png differ diff --git a/mobile/ios/EntePeopleWidget/EntePeopleWidget.swift b/mobile/ios/EntePeopleWidget/EntePeopleWidget.swift index 951c75767f..35537c5c1a 100644 --- a/mobile/ios/EntePeopleWidget/EntePeopleWidget.swift +++ b/mobile/ios/EntePeopleWidget/EntePeopleWidget.swift @@ -1,10 +1,6 @@ // // EntePeopleWidget.swift // EntePeopleWidget -// -// Created by Prateek Sunal on 5/15/25. -// Copyright © 2025 The Chromium Authors. All rights reserved. -// import SwiftUI import UIKit @@ -92,11 +88,6 @@ struct FileEntry: TimelineEntry { struct EntePeopleWidgetEntryView: View { var entry: Provider.Entry - let defaultBase64Image = - "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" - let defaultBase64Preview = - "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" - let data = UserDefaults.init(suiteName: widgetGroupId) var body: some View { @@ -139,11 +130,7 @@ struct EntePeopleWidgetEntryView: View { alignment: .bottomLeading ) } else if entry.index == -2 { - if let data = Data( - base64Encoded: defaultBase64Preview - ), - let uiImage = UIImage(data: data) - { + if let uiImage = UIImage(named: "PeopleWidgetPreview") { Image(uiImage: uiImage) .resizable() .backwardWidgetFullColorRenderingMode() @@ -180,10 +167,7 @@ struct EntePeopleWidgetEntryView: View { alignment: .bottomLeading ) } - } else if let data = Data( - base64Encoded: defaultBase64Image), - let uiImage = UIImage(data: data) - { + } else if let uiImage = UIImage(named: "PeopleWidgetDefault") { VStack(spacing: 8) { Spacer() Image(uiImage: uiImage) diff --git a/mobile/ios/Podfile.lock b/mobile/ios/Podfile.lock index ff5d2071ac..612dc72301 100644 --- a/mobile/ios/Podfile.lock +++ b/mobile/ios/Podfile.lock @@ -1,8 +1,6 @@ PODS: - app_links (0.0.2): - Flutter - - background_fetch (1.3.7): - - Flutter - battery_info (0.0.1): - Flutter - connectivity_plus (0.0.1): @@ -82,28 +80,28 @@ PODS: - GoogleDataTransport (10.1.0): - nanopb (~> 3.30910.0) - PromisesObjC (~> 2.4) - - GoogleUtilities/AppDelegateSwizzler (8.0.2): + - GoogleUtilities/AppDelegateSwizzler (8.1.0): - GoogleUtilities/Environment - GoogleUtilities/Logger - GoogleUtilities/Network - GoogleUtilities/Privacy - - GoogleUtilities/Environment (8.0.2): + - GoogleUtilities/Environment (8.1.0): - GoogleUtilities/Privacy - - GoogleUtilities/Logger (8.0.2): + - GoogleUtilities/Logger (8.1.0): - GoogleUtilities/Environment - GoogleUtilities/Privacy - - GoogleUtilities/Network (8.0.2): + - GoogleUtilities/Network (8.1.0): - GoogleUtilities/Logger - "GoogleUtilities/NSData+zlib" - GoogleUtilities/Privacy - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (8.0.2)": + - "GoogleUtilities/NSData+zlib (8.1.0)": - GoogleUtilities/Privacy - - GoogleUtilities/Privacy (8.0.2) - - GoogleUtilities/Reachability (8.0.2): + - GoogleUtilities/Privacy (8.1.0) + - GoogleUtilities/Reachability (8.1.0): - GoogleUtilities/Logger - GoogleUtilities/Privacy - - GoogleUtilities/UserDefaults (8.0.2): + - GoogleUtilities/UserDefaults (8.1.0): - GoogleUtilities/Logger - GoogleUtilities/Privacy - home_widget (0.0.1): @@ -156,7 +154,7 @@ PODS: - nanopb/encode (= 3.30910.0) - nanopb/decode (3.30910.0) - nanopb/encode (3.30910.0) - - native_video_player (1.0.0): + - native_video_player (4.0.0): - Flutter - objective_c (0.0.1): - Flutter @@ -186,14 +184,14 @@ PODS: - PromisesObjC (2.4.0) - receive_sharing_intent (1.8.1): - Flutter - - SDWebImage (5.21.0): - - SDWebImage/Core (= 5.21.0) - - SDWebImage/Core (5.21.0) + - SDWebImage (5.21.1): + - SDWebImage/Core (= 5.21.1) + - SDWebImage/Core (5.21.1) - SDWebImageWebPCoder (0.14.6): - libwebp (~> 1.0) - SDWebImage/Core (~> 5.17) - Sentry/HybridSDK (8.46.0) - - sentry_flutter (8.14.1): + - sentry_flutter (8.14.2): - Flutter - FlutterMacOS - Sentry/HybridSDK (= 8.46.0) @@ -205,16 +203,16 @@ PODS: - sqflite_darwin (0.0.4): - Flutter - FlutterMacOS - - sqlite3 (3.49.1): - - sqlite3/common (= 3.49.1) - - sqlite3/common (3.49.1) - - sqlite3/dbstatvtab (3.49.1): + - sqlite3 (3.49.2): + - sqlite3/common (= 3.49.2) + - sqlite3/common (3.49.2) + - sqlite3/dbstatvtab (3.49.2): - sqlite3/common - - sqlite3/fts5 (3.49.1): + - sqlite3/fts5 (3.49.2): - sqlite3/common - - sqlite3/perf-threadsafe (3.49.1): + - sqlite3/perf-threadsafe (3.49.2): - sqlite3/common - - sqlite3/rtree (3.49.1): + - sqlite3/rtree (3.49.2): - sqlite3/common - sqlite3_flutter_libs (0.0.1): - Flutter @@ -226,6 +224,8 @@ PODS: - sqlite3/rtree - system_info_plus (0.0.1): - Flutter + - thermal (0.0.1): + - Flutter - ua_client_hints (1.4.1): - Flutter - url_launcher_ios (0.0.1): @@ -240,10 +240,11 @@ PODS: - Flutter - wakelock_plus (0.0.1): - Flutter + - workmanager (0.0.1): + - Flutter DEPENDENCIES: - app_links (from `.symlinks/plugins/app_links/ios`) - - background_fetch (from `.symlinks/plugins/background_fetch/ios`) - battery_info (from `.symlinks/plugins/battery_info/ios`) - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - cupertino_http (from `.symlinks/plugins/cupertino_http/darwin`) @@ -293,15 +294,17 @@ DEPENDENCIES: - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/darwin`) - system_info_plus (from `.symlinks/plugins/system_info_plus/ios`) + - thermal (from `.symlinks/plugins/thermal/ios`) - ua_client_hints (from `.symlinks/plugins/ua_client_hints/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`) - video_thumbnail (from `.symlinks/plugins/video_thumbnail/ios`) - volume_controller (from `.symlinks/plugins/volume_controller/ios`) - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) + - workmanager (from `.symlinks/plugins/workmanager/ios`) SPEC REPOS: - https://github.com/ente-io/ffmpeg-kit-custom-repo-ios: + https://github.com/ente-io/ffmpeg-kit-custom-repo-ios.git: - ffmpeg_kit_custom trunk: - Firebase @@ -326,8 +329,6 @@ SPEC REPOS: EXTERNAL SOURCES: app_links: :path: ".symlinks/plugins/app_links/ios" - background_fetch: - :path: ".symlinks/plugins/background_fetch/ios" battery_info: :path: ".symlinks/plugins/battery_info/ios" connectivity_plus: @@ -426,6 +427,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/sqlite3_flutter_libs/darwin" system_info_plus: :path: ".symlinks/plugins/system_info_plus/ios" + thermal: + :path: ".symlinks/plugins/thermal/ios" ua_client_hints: :path: ".symlinks/plugins/ua_client_hints/ios" url_launcher_ios: @@ -438,10 +441,11 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/volume_controller/ios" wakelock_plus: :path: ".symlinks/plugins/wakelock_plus/ios" + workmanager: + :path: ".symlinks/plugins/workmanager/ios" SPEC CHECKSUMS: app_links: f3e17e4ee5e357b39d8b95290a9b2c299fca71c6 - background_fetch: 39f11371c0dce04b001c4bfd5e782bcccb0a85e2 battery_info: b6c551049266af31556b93c9d9b9452cfec0219f connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d cupertino_http: 947a233f40cfea55167a49f2facc18434ea117ba @@ -458,17 +462,17 @@ SPEC CHECKSUMS: FirebaseInstallations: 6c963bd2a86aca0481eef4f48f5a4df783ae5917 FirebaseMessaging: 487b634ccdf6f7b7ff180fdcb2a9935490f764e8 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - flutter_email_sender: aa1e9772696691d02cd91fea829856c11efb8e58 - flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1 - flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99 - flutter_local_notifications: ad39620c743ea4c15127860f4b5641649a988100 - flutter_native_splash: 6cad9122ea0fad137d23137dd14b937f3e90b145 - flutter_secure_storage: 2c2ff13db9e0a5647389bff88b0ecac56e3f3418 - flutter_sodium: 7e4621538491834eba53bd524547854bcbbd6987 - flutter_timezone: 7c838e17ffd4645d261e87037e5bebf6d38fe544 - fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1 + flutter_email_sender: e03bdda7637bcd3539bfe718fddd980e9508efaa + flutter_image_compress_common: ec1d45c362c9d30a3f6a0426c297f47c52007e3e + flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 + flutter_local_notifications: ff50f8405aaa0ccdc7dcfb9022ca192e8ad9688f + flutter_native_splash: f71420956eb811e6d310720fee915f1d42852e7a + flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be + flutter_sodium: a00383520fc689c688b66fd3092984174712493e + flutter_timezone: ac3da59ac941ff1c98a2e1f0293420e020120282 + fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 - GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d + GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57 image_editor_common: d6f6644ae4a6de80481e89fe6d0a8c49e30b4b43 in_app_purchase_storekit: a1ce04056e23eecc666b086040239da7619cd783 @@ -486,7 +490,7 @@ SPEC CHECKSUMS: motionphoto: 8b65ce50c7d7ff3c767534fc3768b2eed9ac24e4 move_to_background: cd3091014529ec7829e342ad2d75c0a11f4378a5 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 - native_video_player: 5d36066807b680e181473e6890dde643ac85380d + native_video_player: 29ab24a926804ac8c4a57eb6d744c7d927c2bc3e objective_c: 77e887b5ba1827970907e10e832eec1683f3431d onnxruntime: e7c2ae44385191eaad5ae64c935a72debaddc997 onnxruntime-c: a909204639a1f035f575127ac406f781ac797c9c @@ -500,22 +504,24 @@ SPEC CHECKSUMS: privacy_screen: 1a131c052ceb3c3659934b003b0d397c2381a24e PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 receive_sharing_intent: 79c848f5b045674ad60b9fea3bafea59962ad2c1 - SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868 + SDWebImage: f29024626962457f3470184232766516dee8dfea SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380 Sentry: da60d980b197a46db0b35ea12cb8f39af48d8854 - sentry_flutter: 6a134f9d381e49f22ea25a67736cf0cf4d02ec9c + sentry_flutter: 2df8b0aab7e4aba81261c230cbea31c82a62dd1b share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d - sqlite3: fc1400008a9b3525f5914ed715a5d1af0b8f4983 + sqlite3: 3c950dc86011117c307eb0b28c4a7bb449dce9f1 sqlite3_flutter_libs: 069c435986dd4b63461aecd68f4b30be4a9e9daa system_info_plus: 5393c8da281d899950d751713575fbf91c7709aa + thermal: a9261044101ae8f532fa29cab4e8270b51b3f55c ua_client_hints: aeabd123262c087f0ce151ef96fa3ab77bfc8b38 url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3 video_thumbnail: 94ba6705afbaa120b77287080424930f23ea0c40 volume_controller: 2e3de73d6e7e81a0067310d17fb70f2f86d71ac7 wakelock_plus: 373cfe59b235a6dd5837d0fb88791d2f13a90d56 + workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6 PODFILE CHECKSUM: a8ef88ad74ba499756207e7592c6071a96756d18 diff --git a/mobile/ios/Runner.xcodeproj/project.pbxproj b/mobile/ios/Runner.xcodeproj/project.pbxproj index f91b1762c6..d1c1bff9f4 100644 --- a/mobile/ios/Runner.xcodeproj/project.pbxproj +++ b/mobile/ios/Runner.xcodeproj/project.pbxproj @@ -527,7 +527,6 @@ "${BUILT_PRODUCTS_DIR}/SDWebImageWebPCoder/SDWebImageWebPCoder.framework", "${BUILT_PRODUCTS_DIR}/Sentry/Sentry.framework", "${BUILT_PRODUCTS_DIR}/app_links/app_links.framework", - "${BUILT_PRODUCTS_DIR}/background_fetch/background_fetch.framework", "${BUILT_PRODUCTS_DIR}/battery_info/battery_info.framework", "${BUILT_PRODUCTS_DIR}/connectivity_plus/connectivity_plus.framework", "${BUILT_PRODUCTS_DIR}/cupertino_http/cupertino_http.framework", @@ -574,12 +573,14 @@ "${BUILT_PRODUCTS_DIR}/sqlite3/sqlite3.framework", "${BUILT_PRODUCTS_DIR}/sqlite3_flutter_libs/sqlite3_flutter_libs.framework", "${BUILT_PRODUCTS_DIR}/system_info_plus/system_info_plus.framework", + "${BUILT_PRODUCTS_DIR}/thermal/thermal.framework", "${BUILT_PRODUCTS_DIR}/ua_client_hints/ua_client_hints.framework", "${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework", "${BUILT_PRODUCTS_DIR}/video_player_avfoundation/video_player_avfoundation.framework", "${BUILT_PRODUCTS_DIR}/video_thumbnail/video_thumbnail.framework", "${BUILT_PRODUCTS_DIR}/volume_controller/volume_controller.framework", "${BUILT_PRODUCTS_DIR}/wakelock_plus/wakelock_plus.framework", + "${BUILT_PRODUCTS_DIR}/workmanager/workmanager.framework", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg_kit_custom/ffmpegkit.framework/ffmpegkit", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg_kit_custom/libavcodec.framework/libavcodec", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg_kit_custom/libavdevice.framework/libavdevice", @@ -622,7 +623,6 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sentry.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/app_links.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/background_fetch.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/battery_info.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity_plus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/cupertino_http.framework", @@ -669,12 +669,14 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3_flutter_libs.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/system_info_plus.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/thermal.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ua_client_hints.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_player_avfoundation.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_thumbnail.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/volume_controller.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wakelock_plus.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/workmanager.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ffmpegkit.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libavcodec.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libavdevice.framework", diff --git a/mobile/ios/Runner/AppDelegate.swift b/mobile/ios/Runner/AppDelegate.swift index f1a6bbe1bf..cbf287bc52 100644 --- a/mobile/ios/Runner/AppDelegate.swift +++ b/mobile/ios/Runner/AppDelegate.swift @@ -2,6 +2,7 @@ import AVFoundation import Flutter import UIKit import app_links +import workmanager @main @objc class AppDelegate: FlutterAppDelegate { @@ -15,6 +16,14 @@ import app_links } GeneratedPluginRegistrant.register(with: self) + WorkmanagerPlugin.setPluginRegistrantCallback { registry in + GeneratedPluginRegistrant.register(with: registry) + } + var freqInMinutes = 30 * 60 + // Register a periodic task in iOS 13+ + WorkmanagerPlugin.registerPeriodicTask( + withIdentifier: "io.ente.frame.iOSBackgroundAppRefresh", + frequency: NSNumber(value: freqInMinutes)) // Retrieve the link from parameters if let url = AppLinks.shared.getLink(launchOptions: launchOptions) { diff --git a/mobile/ios/Runner/Info.plist b/mobile/ios/Runner/Info.plist index 6443cc98c8..5e9b8a7005 100644 --- a/mobile/ios/Runner/Info.plist +++ b/mobile/ios/Runner/Info.plist @@ -4,7 +4,7 @@ BGTaskSchedulerPermittedIdentifiers - com.transistorsoft.fetch + io.ente.frame.iOSBackgroundAppRefresh CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) diff --git a/mobile/lib/app.dart b/mobile/lib/app.dart index a01071654e..c0f1b0950c 100644 --- a/mobile/lib/app.dart +++ b/mobile/lib/app.dart @@ -2,7 +2,6 @@ import "dart:async"; import 'dart:io'; import 'package:adaptive_theme/adaptive_theme.dart'; -import 'package:background_fetch/background_fetch.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; @@ -24,17 +23,15 @@ import "package:photos/services/people_home_widget_service.dart"; import 'package:photos/services/sync/sync_service.dart'; import 'package:photos/ui/tabs/home_widget.dart'; import "package:photos/ui/viewer/actions/file_viewer.dart"; +import "package:photos/utils/bg_task_utils.dart"; import "package:photos/utils/intent_util.dart"; +import "package:photos/utils/standalone/debouncer.dart"; class EnteApp extends StatefulWidget { - final Future Function(String) runBackgroundTask; - final Future Function(String) killBackgroundTask; final AdaptiveThemeMode? savedThemeMode; final Locale? locale; const EnteApp( - this.runBackgroundTask, - this.killBackgroundTask, this.locale, this.savedThemeMode, { super.key, @@ -50,10 +47,11 @@ class EnteApp extends StatefulWidget { } class _EnteAppState extends State with WidgetsBindingObserver { - final _logger = Logger("EnteAppState"); late Locale? locale; late StreamSubscription _memoriesChangedSubscription; + final _logger = Logger("EnteAppState"); late StreamSubscription _peopleChangedSubscription; + late Debouncer _changeCallbackDebouncer; @override void initState() { @@ -72,9 +70,13 @@ class _EnteAppState extends State with WidgetsBindingObserver { await MemoryHomeWidgetService.instance.memoryChanged(); }, ); + _changeCallbackDebouncer = Debouncer(const Duration(milliseconds: 1500)); _peopleChangedSubscription = Bus.instance.on().listen( (event) async { - await PeopleHomeWidgetService.instance.peopleChanged(); + _changeCallbackDebouncer.run( + () async => + unawaited(PeopleHomeWidgetService.instance.checkPeopleChanged()), + ); }, ); } @@ -106,7 +108,7 @@ class _EnteAppState extends State with WidgetsBindingObserver { : MediaExtentionAction(action: IntentAction.main); AppLifecycleService.instance.setMediaExtensionAction(mediaExtentionAction); if (mediaExtentionAction.action == IntentAction.main) { - _configureBackgroundFetch(); + await BgTaskUtils.configureWorkmanager(); } } @@ -115,7 +117,7 @@ class _EnteAppState extends State with WidgetsBindingObserver { if (Platform.isAndroid || kDebugMode) { return Listener( onPointerDown: (event) { - machineLearningController.onUserInteraction(); + computeController.onUserInteraction(); }, child: AdaptiveTheme( light: lightThemeData, @@ -150,7 +152,7 @@ class _EnteAppState extends State with WidgetsBindingObserver { } else { return Listener( onPointerDown: (event) { - machineLearningController.onUserInteraction(); + computeController.onUserInteraction(); }, child: MaterialApp( title: "ente", @@ -191,29 +193,4 @@ class _EnteAppState extends State with WidgetsBindingObserver { AppLifecycleService.instance.onAppInBackground(stateChangeReason); } } - - void _configureBackgroundFetch() { - BackgroundFetch.configure( - BackgroundFetchConfig( - minimumFetchInterval: 15, - forceAlarmManager: false, - stopOnTerminate: false, - startOnBoot: true, - enableHeadless: true, - requiresBatteryNotLow: true, - requiresCharging: false, - requiresStorageNotLow: false, - requiresDeviceIdle: false, - requiredNetworkType: NetworkType.ANY, - ), (String taskId) async { - await widget.runBackgroundTask(taskId); - }, (taskId) { - _logger.info("BG task timeout taskID: $taskId"); - widget.killBackgroundTask(taskId); - }).then((int status) { - _logger.info('[BackgroundFetch] configure success: $status'); - }).catchError((e) { - _logger.info('[BackgroundFetch] configure ERROR: $e'); - }); - } } diff --git a/mobile/lib/core/configuration.dart b/mobile/lib/core/configuration.dart index 32a9e6389e..304a9f931c 100644 --- a/mobile/lib/core/configuration.dart +++ b/mobile/lib/core/configuration.dart @@ -75,6 +75,7 @@ class Configuration { late FlutterSecureStorage _secureStorage; late String _tempDocumentsDirPath; late String _thumbnailCacheDirectory; + late String _personFaceThumbnailCacheDirectory; late String _sharedDocumentsMediaDirectory; String? _volatilePassword; @@ -95,6 +96,9 @@ class Configuration { final tempDirectoryPath = (await getTemporaryDirectory()).path; _thumbnailCacheDirectory = tempDirectoryPath + "/thumbnail-cache"; Directory(_thumbnailCacheDirectory).createSync(recursive: true); + _personFaceThumbnailCacheDirectory = + _documentsDirectory + "/person-face-thumbnail-cache"; + Directory(_personFaceThumbnailCacheDirectory).createSync(recursive: true); _sharedDocumentsMediaDirectory = _documentsDirectory + "/ente-shared-media"; Directory(_sharedDocumentsMediaDirectory).createSync(recursive: true); @@ -549,6 +553,10 @@ class Configuration { return _thumbnailCacheDirectory; } + String getPersonFaceThumbnailCacheDirectory() { + return _personFaceThumbnailCacheDirectory; + } + String getSharedMediaDirectory() { return _sharedDocumentsMediaDirectory; } diff --git a/mobile/lib/core/constants.dart b/mobile/lib/core/constants.dart index 24f8fade5b..6215ebc7d7 100644 --- a/mobile/lib/core/constants.dart +++ b/mobile/lib/core/constants.dart @@ -103,7 +103,7 @@ const blackThumbnailBase64 = '/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEB' const uploadTempFilePrefix = "upload_file_"; final tempDirCleanUpInterval = kDebugMode - ? const Duration(seconds: 30).inMicroseconds + ? const Duration(hours: 1).inMicroseconds : const Duration(hours: 6).inMicroseconds; const kFilterChipHeight = 32.0; diff --git a/mobile/lib/core/error-reporting/super_logging.dart b/mobile/lib/core/error-reporting/super_logging.dart index 31cd3d9137..f11f58b197 100644 --- a/mobile/lib/core/error-reporting/super_logging.dart +++ b/mobile/lib/core/error-reporting/super_logging.dart @@ -47,6 +47,14 @@ extension SuperLogRecord on LogRecord { var msg = "$header $message"; if (error != null) { + if (error is DioException) { + final String? id = (error as DioException) + .requestOptions + .headers['x-request-id'] as String?; + if (id != null) { + msg += "\n⤷ id: $id"; + } + } msg += "\n⤷ type: ${error.runtimeType}\n⤷ error: $error"; } if (stackTrace != null) { @@ -179,7 +187,7 @@ class SuperLogging { setupSentry().ignore(); } - Logger.root.level = Level.ALL; + Logger.root.level = kDebugMode ? Level.ALL : Level.INFO; Logger.root.onRecord.listen(onLogRecord); if (isFDroidClient) { diff --git a/mobile/lib/core/network/ente_interceptor.dart b/mobile/lib/core/network/ente_interceptor.dart index 676fe94cb3..1ca14ff0b6 100644 --- a/mobile/lib/core/network/ente_interceptor.dart +++ b/mobile/lib/core/network/ente_interceptor.dart @@ -1,10 +1,13 @@ +import "dart:io"; + import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import 'package:photos/core/configuration.dart'; -import 'package:uuid/uuid.dart'; +import "package:photos/models/base/id.dart"; class EnteRequestInterceptor extends Interceptor { final String enteEndpoint; + final String id = Platform.isIOS ? "ios" : "droid"; EnteRequestInterceptor(this.enteEndpoint); @@ -17,7 +20,7 @@ class EnteRequestInterceptor extends Interceptor { ); } // ignore: prefer_const_constructors - options.headers.putIfAbsent("x-request-id", () => Uuid().v4().toString()); + options.headers.putIfAbsent("x-request-id", () => newID(id)); final String? tokenValue = Configuration.instance.getToken(); if (tokenValue != null) { options.headers.putIfAbsent("X-Auth-Token", () => tokenValue); diff --git a/mobile/lib/core/network/network.dart b/mobile/lib/core/network/network.dart index 2179dc7850..b73f548b63 100644 --- a/mobile/lib/core/network/network.dart +++ b/mobile/lib/core/network/network.dart @@ -1,7 +1,7 @@ import 'dart:io'; import 'package:dio/dio.dart'; -import 'package:native_dio_adapter/native_dio_adapter.dart'; +import "package:native_dio_adapter/native_dio_adapter.dart"; import 'package:package_info_plus/package_info_plus.dart'; import "package:photos/core/configuration.dart"; import "package:photos/core/event_bus.dart"; diff --git a/mobile/lib/db/device_files_db.dart b/mobile/lib/db/device_files_db.dart index b464039f2c..0e56b1a73b 100644 --- a/mobile/lib/db/device_files_db.dart +++ b/mobile/lib/db/device_files_db.dart @@ -206,14 +206,14 @@ extension DeviceFiles on FilesDB { }); if (rowUpdated > 0) { - _logger.fine("Updated $rowUpdated rows for ${pathEntity.name}"); + _logger.info("Updated $rowUpdated rows for ${pathEntity.name}"); hasUpdated = true; } } else { hasUpdated = true; await db.execute( ''' - INSERT INTO device_collections (id, name, count, cover_id, should_backup) + INSERT INTO device_collections (id, name, count, cover_id, should_backup) VALUES (?, ?, ?, ?, ?); ''', [ @@ -267,8 +267,8 @@ extension DeviceFiles on FilesDB { final db = await sqliteAsyncDB; final rows = await db.getAll( ''' - SELECT collection_id FROM device_collections where should_backup = - $_sqlBoolTrue + SELECT collection_id FROM device_collections where should_backup = + $_sqlBoolTrue and collection_id != -1; ''', ); @@ -338,12 +338,12 @@ extension DeviceFiles on FilesDB { SELECT * FROM ${FilesDB.filesTable} WHERE ${FilesDB.columnLocalID} IS NOT NULL AND - ${FilesDB.columnCreationTime} >= $startTime AND + ${FilesDB.columnCreationTime} >= $startTime AND ${FilesDB.columnCreationTime} <= $endTime AND - (${FilesDB.columnOwnerID} IS NULL OR ${FilesDB.columnOwnerID} = - $ownerID ) AND - ${FilesDB.columnLocalID} IN - (SELECT id FROM device_files where path_id = '${deviceCollection.id}' ) + (${FilesDB.columnOwnerID} IS NULL OR ${FilesDB.columnOwnerID} = + $ownerID ) AND + ${FilesDB.columnLocalID} IN + (SELECT id FROM device_files where path_id = '${deviceCollection.id}' ) ORDER BY ${FilesDB.columnCreationTime} $order , ${FilesDB.columnModificationTime} $order ''' + (limit != null ? ' limit $limit;' : ';'); @@ -359,14 +359,14 @@ extension DeviceFiles on FilesDB { ) async { final db = await sqliteAsyncDB; const String rawQuery = ''' - SELECT ${FilesDB.columnLocalID}, ${FilesDB.columnUploadedFileID}, - ${FilesDB.columnFileSize} + SELECT ${FilesDB.columnLocalID}, ${FilesDB.columnUploadedFileID}, + ${FilesDB.columnFileSize} FROM ${FilesDB.filesTable} WHERE ${FilesDB.columnLocalID} IS NOT NULL AND (${FilesDB.columnOwnerID} IS NULL OR ${FilesDB.columnOwnerID} = ?) AND (${FilesDB.columnUploadedFileID} IS NOT NULL AND ${FilesDB.columnUploadedFileID} IS NOT -1) - AND - ${FilesDB.columnLocalID} IN + AND + ${FilesDB.columnLocalID} IN (SELECT id FROM device_files where path_id = ?) '''; final results = await db.getAll(rawQuery, [ownerID, pathID]); @@ -425,7 +425,7 @@ extension DeviceFiles on FilesDB { final EnteFile? result = await getDeviceCollectionThumbnail(deviceCollection.id); if (result == null) { - _logger.finest( + _logger.info( 'Failed to find coverThumbnail for deviceFolder', ); continue; @@ -453,7 +453,7 @@ extension DeviceFiles on FilesDB { debugPrint("Call fallback method to get potential thumbnail"); final db = await sqliteAsyncDB; final fileRows = await db.getAll( - '''SELECT * FROM FILES f JOIN device_files df on f.local_id = df.id + '''SELECT * FROM FILES f JOIN device_files df on f.local_id = df.id and df.path_id= ? order by f.creation_time DESC limit 1; ''', [pathID], diff --git a/mobile/lib/db/entities_db.dart b/mobile/lib/db/entities_db.dart index 3cd9d47639..fba74d98a5 100644 --- a/mobile/lib/db/entities_db.dart +++ b/mobile/lib/db/entities_db.dart @@ -77,6 +77,20 @@ extension EntitiesDB on FilesDB { ); } + Future> getCertainEntities( + EntityType type, + List ids, + ) async { + final db = await sqliteAsyncDB; + final List> maps = await db.getAll( + 'SELECT * FROM entities WHERE type = ? AND id IN (${List.filled(ids.length, '?').join(',')})', + [type.name, ...ids], + ); + return List.generate(maps.length, (i) { + return LocalEntityData.fromJson(maps[i]); + }); + } + Future> getEntities(EntityType type) async { final db = await sqliteAsyncDB; final List> maps = await db.getAll( @@ -99,4 +113,19 @@ extension EntitiesDB on FilesDB { } return LocalEntityData.fromJson(maps.first); } + + Future getPreHashForEntities( + EntityType type, + List ids, + ) async { + final db = await sqliteAsyncDB; + final maps = await db.get( + 'SELECT GROUP_CONCAT(id || \':\' || updatedAt, \',\') FROM entities WHERE type = ? AND id IN (${List.filled(ids.length, '?').join(',')})', + [type.name, ...ids], + ); + if (maps.isEmpty) { + return null; + } + return maps.values.first as String?; + } } diff --git a/mobile/lib/db/files_db.dart b/mobile/lib/db/files_db.dart index fb8cb72541..f8900f8912 100644 --- a/mobile/lib/db/files_db.dart +++ b/mobile/lib/db/files_db.dart @@ -1436,22 +1436,6 @@ class FilesDB with SqlDbBase { return convertToFiles(rows).first; } - Future markForReUploadIfLocationMissing(List localIDs) async { - if (localIDs.isEmpty) { - return; - } - final inParam = localIDs.map((id) => "'$id'").join(','); - final db = await instance.sqliteAsyncDB; - await db.execute( - ''' - UPDATE $filesTable - SET $columnUpdationTime = NULL - WHERE $columnLocalID IN ($inParam) - AND ($columnLatitude IS NULL OR $columnLongitude IS NULL OR $columnLongitude = 0.0 or $columnLongitude = 0.0); - ''', - ); - } - Future doesFileExistInCollection( int uploadedFileID, int collectionID, @@ -1586,25 +1570,6 @@ class FilesDB with SqlDbBase { return files; } - // For givenUserID, get List of unique LocalIDs for files which are - // uploaded by the given user and location is missing - Future> getLocalIDsForFilesWithoutLocation(int ownerID) async { - final db = await instance.sqliteAsyncDB; - final rows = await db.getAll( - ''' - SELECT DISTINCT $columnLocalID FROM $filesTable - WHERE $columnOwnerID = ? AND $columnLocalID IS NOT NULL AND - ($columnLatitude IS NULL OR $columnLongitude IS NULL OR $columnLatitude = 0.0 or $columnLongitude = 0.0) - ''', - [ownerID], - ); - final result = []; - for (final row in rows) { - result.add(row[columnLocalID].toString()); - } - return result; - } - // For a given userID, return unique uploadedFileId for the given userID Future> getUploadIDsWithMissingSize(int userId) async { final db = await instance.sqliteAsyncDB; @@ -1622,25 +1587,6 @@ class FilesDB with SqlDbBase { return result; } - Future> getLocalFilesBackedUpWithoutLocation(int userId) async { - final db = await instance.sqliteAsyncDB; - final rows = await db.getAll( - ''' - SELECT DISTINCT $columnLocalID FROM $filesTable - WHERE $columnOwnerID = ? AND $columnLocalID IS NOT NULL AND - ($columnUploadedFileID IS NOT NULL AND $columnUploadedFileID IS NOT -1) - AND ($columnLatitude IS NULL OR $columnLongitude IS NULL OR - $columnLatitude = 0.0 or $columnLongitude = 0.0) - ''', - [userId], - ); - final result = []; - for (final row in rows) { - result.add(row[columnLocalID] as String); - } - return result; - } - // updateSizeForUploadIDs takes a map of upploadedFileID and fileSize and // update the fileSize for the given uploadedFileID Future updateSizeForUploadIDs( @@ -1683,8 +1629,8 @@ class FilesDB with SqlDbBase { AND $columnUploadedFileID != -1 AND $columnOwnerID = $userID AND $columnLocalID IS NOT NULL - AND ($columnFileSize IS NULL OR $columnFileSize <= 524288000) - AND ($columnDuration IS NULL OR $columnDuration <= 60) + AND ($columnFileSize IS NOT NULL AND $columnFileSize <= 524288000) + AND ($columnDuration IS NOT NULL AND ($columnDuration <= 60 AND $columnDuration > 0)) ORDER BY $columnCreationTime DESC ''', [getInt(fileType), beginDate.microsecondsSinceEpoch], diff --git a/mobile/lib/db/ml/base.dart b/mobile/lib/db/ml/base.dart index 5e2879d463..5bac0233d6 100644 --- a/mobile/lib/db/ml/base.dart +++ b/mobile/lib/db/ml/base.dart @@ -13,6 +13,7 @@ abstract class IMLDataDB { Future getFaceIndexedFileCount({int minimumMlVersion}); Future> clusterIdToFaceCount(); Future> getPersonIgnoredClusters(String personID); + Future>> getPersonToRejectedSuggestions(); Future> getPersonClusterIDs(String personID); Future> getPersonsClusterIDs(List personID); Future clearTable(); @@ -40,6 +41,7 @@ abstract class IMLDataDB { Future>> getAllClusterIdToFaceIDs(); Future> getFaceIDsForCluster(String clusterID); Future>>> getPersonToClusterIdToFaceIds(); + Future>> getPersonToClusterIDs(); Future>> getClusterIdToFaceIdsForPerson( String personID, ); diff --git a/mobile/lib/db/ml/db.dart b/mobile/lib/db/ml/db.dart index 0186ead274..851e349d00 100644 --- a/mobile/lib/db/ml/db.dart +++ b/mobile/lib/db/ml/db.dart @@ -35,6 +35,8 @@ import 'package:sqlite_async/sqlite_async.dart'; /// /// [clipTable] - Stores the embeddings of the CLIP model /// [fileDataTable] - Stores data about the files that are already processed by the ML models +/// +/// [faceCacheTable] - Stores a all the mappings from personID or clusterID to the faceID that has been used as cover face. class MLDataDB with SqlDbBase implements IMLDataDB { static final Logger _logger = Logger("MLDataDB"); @@ -57,6 +59,7 @@ class MLDataDB with SqlDbBase implements IMLDataDB { fcClusterIDIndex, createClipEmbeddingsTable, createFileDataTable, + createFaceCacheTable, ]; // only have a single app-wide reference to the database @@ -100,9 +103,9 @@ class MLDataDB with SqlDbBase implements IMLDataDB { const String sql = ''' INSERT INTO $facesTable ( - $fileIDColumn, $faceIDColumn, $faceDetectionColumn, $embeddingColumn, $faceScore, $faceBlur, $isSideways, $imageHeight, $imageWidth, $mlVersionColumn + $fileIDColumn, $faceIDColumn, $faceDetectionColumn, $embeddingColumn, $faceScore, $faceBlur, $isSideways, $imageHeight, $imageWidth, $mlVersionColumn ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - ON CONFLICT($fileIDColumn, $faceIDColumn) DO UPDATE SET $faceIDColumn = excluded.$faceIDColumn, $faceDetectionColumn = excluded.$faceDetectionColumn, $embeddingColumn = excluded.$embeddingColumn, $faceScore = excluded.$faceScore, $faceBlur = excluded.$faceBlur, $isSideways = excluded.$isSideways, $imageHeight = excluded.$imageHeight, $imageWidth = excluded.$imageWidth, $mlVersionColumn = excluded.$mlVersionColumn + ON CONFLICT($fileIDColumn, $faceIDColumn) DO UPDATE SET $faceIDColumn = excluded.$faceIDColumn, $faceDetectionColumn = excluded.$faceDetectionColumn, $embeddingColumn = excluded.$embeddingColumn, $faceScore = excluded.$faceScore, $faceBlur = excluded.$faceBlur, $isSideways = excluded.$isSideways, $imageHeight = excluded.$imageHeight, $imageWidth = excluded.$imageWidth, $mlVersionColumn = excluded.$mlVersionColumn '''; final parameterSets = batch.map((face) { final map = mapRemoteToFaceDB(face); @@ -155,7 +158,7 @@ class MLDataDB with SqlDbBase implements IMLDataDB { final db = await instance.asyncDB; final String query = ''' SELECT $fileIDColumn, $mlVersionColumn - FROM $facesTable + FROM $facesTable WHERE $mlVersionColumn >= $minimumMlVersion '''; final List> maps = await db.getAll(query); @@ -209,6 +212,21 @@ class MLDataDB with SqlDbBase implements IMLDataDB { return ignoredClusterIDs.union(rejectClusterIDs); } + @override + Future>> getPersonToRejectedSuggestions() async { + final db = await instance.asyncDB; + final List> rejectMaps = await db.getAll( + 'SELECT $personIdColumn, $clusterIDColumn FROM $notPersonFeedback', + ); + final Map> result = {}; + for (final map in rejectMaps) { + final personID = map[personIdColumn] as String; + final clusterID = map[clusterIDColumn] as String; + result.putIfAbsent(personID, () => {}).add(clusterID); + } + return result; + } + @override Future> getPersonClusterIDs(String personID) async { final db = await instance.asyncDB; @@ -264,9 +282,9 @@ class MLDataDB with SqlDbBase implements IMLDataDB { final Map> result = {}; final selectQuery = ''' - SELECT fc.$clusterIDColumn, fe.$embeddingColumn - FROM $faceClustersTable fc - INNER JOIN $facesTable fe ON fc.$faceIDColumn = fe.$faceIDColumn + SELECT fc.$clusterIDColumn, fe.$embeddingColumn + FROM $faceClustersTable fc + INNER JOIN $facesTable fe ON fc.$faceIDColumn = fe.$faceIDColumn WHERE fc.$clusterIDColumn IN (${List.filled(clusterIDs.length, '?').join(',')}) ${limit != null ? 'LIMIT ?' : ''} '''; @@ -320,10 +338,10 @@ class MLDataDB with SqlDbBase implements IMLDataDB { final List> faceMaps = await db.getAll( ''' - SELECT * FROM $facesTable + SELECT * FROM $facesTable WHERE $faceIDColumn IN ( - SELECT $faceIDColumn - FROM $faceClustersTable + SELECT $faceIDColumn + FROM $faceClustersTable WHERE $clusterIDColumn IN (${List.filled(clusterIDs.length, '?').join(',')}) ) AND $fileIDColumn IN (${List.filled(fileId.length, '?').join(',')}) @@ -417,8 +435,8 @@ class MLDataDB with SqlDbBase implements IMLDataDB { final List> maps = await db.getAll( ''' - SELECT $clusterIDColumn, $faceIDColumn - FROM $faceClustersTable + SELECT $clusterIDColumn, $faceIDColumn + FROM $faceClustersTable WHERE $clusterIDColumn IN (${List.filled(clusterIDs.length, '?').join(',')}) ''', [...clusterIDs], @@ -471,6 +489,22 @@ class MLDataDB with SqlDbBase implements IMLDataDB { return maps.map((e) => e[faceIDColumn] as String).toSet(); } + Future> getFaceIDsForClusterOrderedByScore( + String clusterID, { + int limit = 10, + }) async { + final db = await instance.asyncDB; + final faceIdsResult = await db.getAll( + 'SELECT $facesTable.$faceIDColumn FROM $facesTable ' + 'JOIN $faceClustersTable ON $facesTable.$faceIDColumn = $faceClustersTable.$faceIDColumn ' + 'WHERE $faceClustersTable.$clusterIDColumn = ? ' + 'ORDER BY $facesTable.$faceScore DESC ' + 'LIMIT ?', + [clusterID, limit], + ); + return faceIdsResult.map((e) => e[faceIDColumn] as String).toList(); + } + // Get Map of personID to Map of clusterID to faceIDs @override Future>>> @@ -493,6 +527,21 @@ class MLDataDB with SqlDbBase implements IMLDataDB { return result; } + @override + Future>> getPersonToClusterIDs() async { + final db = await instance.asyncDB; + final List> maps = await db.getAll( + 'SELECT $personIdColumn, $clusterIDColumn FROM $clusterPersonTable', + ); + final Map> result = {}; + for (final map in maps) { + final personID = map[personIdColumn] as String; + final clusterID = map[clusterIDColumn] as String; + result.putIfAbsent(personID, () => {}).add(clusterID); + } + return result; + } + Future> getFaceIdToPersonIdForFaces( Iterable faceIDs, ) async { @@ -541,13 +590,30 @@ class MLDataDB with SqlDbBase implements IMLDataDB { return faceIdsResult.map((e) => e[faceIDColumn] as String).toSet(); } + Future> getFaceIDsForPersonOrderedByScore( + String personID, { + int limit = 10, + }) async { + final db = await instance.asyncDB; + final faceIdsResult = await db.getAll( + 'SELECT $facesTable.$faceIDColumn FROM $facesTable ' + 'JOIN $faceClustersTable ON $facesTable.$faceIDColumn = $faceClustersTable.$faceIDColumn ' + 'JOIN $clusterPersonTable ON $faceClustersTable.$clusterIDColumn = $clusterPersonTable.$clusterIDColumn ' + 'WHERE $clusterPersonTable.$personIdColumn = ? ' + 'ORDER BY $facesTable.$faceScore DESC ' + 'LIMIT ?', + [personID, limit], + ); + return faceIdsResult.map((e) => e[faceIDColumn] as String).toList(); + } + @override Future> getBlurValuesForCluster(String clusterID) async { final db = await instance.asyncDB; const String query = ''' - SELECT $facesTable.$faceBlur - FROM $facesTable - JOIN $faceClustersTable ON $facesTable.$faceIDColumn = $faceClustersTable.$faceIDColumn + SELECT $facesTable.$faceBlur + FROM $facesTable + JOIN $faceClustersTable ON $facesTable.$faceIDColumn = $faceClustersTable.$faceIDColumn WHERE $faceClustersTable.$clusterIDColumn = ? '''; // const String query2 = ''' @@ -721,11 +787,11 @@ class MLDataDB with SqlDbBase implements IMLDataDB { while (true) { // Query a batch of rows final String query = ''' - SELECT $faceIDColumn, $embeddingColumn - FROM $facesTable - WHERE $faceIDColumn IN (${faceIDs.map((id) => "'$id'").join(",")}) - ORDER BY $faceIDColumn DESC - LIMIT $batchSize OFFSET $offset + SELECT $faceIDColumn, $embeddingColumn + FROM $facesTable + WHERE $faceIDColumn IN (${faceIDs.map((id) => "'$id'").join(",")}) + ORDER BY $faceIDColumn DESC + LIMIT $batchSize OFFSET $offset '''; final List> maps = await db.getAll(query); // Break the loop if no more rows @@ -949,8 +1015,8 @@ class MLDataDB with SqlDbBase implements IMLDataDB { return db.then((db) async { final List> maps = await db.getAll( ''' - SELECT $clusterIDColumn, $faceIDColumn - FROM $faceClustersTable + SELECT $clusterIDColumn, $faceIDColumn + FROM $faceClustersTable WHERE $clusterIDColumn IN (${List.filled(clusterIDs.length, '?').join(',')}) ''', [...clusterIDs], @@ -973,7 +1039,7 @@ class MLDataDB with SqlDbBase implements IMLDataDB { final db = await instance.asyncDB; const String sql = ''' - INSERT INTO $clusterSummaryTable ($clusterIDColumn, $avgColumn, $countColumn) VALUES (?, ?, ?) ON CONFLICT($clusterIDColumn) DO UPDATE SET $avgColumn = excluded.$avgColumn, $countColumn = excluded.$countColumn + INSERT INTO $clusterSummaryTable ($clusterIDColumn, $avgColumn, $countColumn) VALUES (?, ?, ?) ON CONFLICT($clusterIDColumn) DO UPDATE SET $avgColumn = excluded.$avgColumn, $countColumn = excluded.$countColumn '''; final List> parameterSets = []; int batchCounter = 0; @@ -1122,7 +1188,7 @@ class MLDataDB with SqlDbBase implements IMLDataDB { final result = await db.getAll( ''' SELECT DISTINCT $facesTable.$fileIDColumn - FROM $faceClustersTable + FROM $faceClustersTable JOIN $facesTable ON $faceClustersTable.$faceIDColumn = $facesTable.$faceIDColumn WHERE $faceClustersTable.$clusterIDColumn = ? ''', @@ -1153,8 +1219,8 @@ class MLDataDB with SqlDbBase implements IMLDataDB { final notInParam = exceptClusters?.map((e) => "'$e'").join(',') ?? ''; final db = await instance.asyncDB; final result = await db.getAll(''' - SELECT DISTINCT $facesTable.$fileIDColumn - FROM $facesTable + SELECT DISTINCT $facesTable.$fileIDColumn + FROM $facesTable JOIN $faceClustersTable on $faceClustersTable.$faceIDColumn = $facesTable.$faceIDColumn WHERE $faceClustersTable.$clusterIDColumn NOT IN ($notInParam); '''); @@ -1249,4 +1315,49 @@ class MLDataDB with SqlDbBase implements IMLDataDB { embedding.version, ]; } + + /// WARNING: Better to use the similarly named [putFaceIdCachedForPersonOrCluster] + /// method from face_thumbnail_cache instead! + Future putFaceIdCachedForPersonOrCluster( + String personOrClusterId, + String faceID, + ) async { + final db = await instance.asyncDB; + await db.execute( + ''' + INSERT OR REPLACE INTO $faceCacheTable ($personOrClusterIdColumn, $faceIDColumn) + VALUES (?, ?) + ''', + [personOrClusterId, faceID], + ); + } + + Future getFaceIdUsedForPersonOrCluster( + String personOrClusterId, + ) async { + final db = await instance.asyncDB; + final List> maps = await db.getAll( + ''' + SELECT $faceIDColumn FROM $faceCacheTable + WHERE $personOrClusterIdColumn = ? + ''', + [personOrClusterId], + ); + if (maps.isNotEmpty) { + return maps.first[faceIDColumn] as String; + } + return null; + } + + Future removeFaceIdCachedForPersonOrCluster( + String personOrClusterID, + ) async { + final db = await instance.asyncDB; + const String sql = ''' + DELETE FROM $faceCacheTable + WHERE $personOrClusterIdColumn = ?' + '''; + final List params = [personOrClusterID]; + await db.execute(sql, params); + } } diff --git a/mobile/lib/db/ml/schema.dart b/mobile/lib/db/ml/schema.dart index 5968215cf5..d2306cd5d2 100644 --- a/mobile/lib/db/ml/schema.dart +++ b/mobile/lib/db/ml/schema.dart @@ -15,6 +15,7 @@ const imageHeight = 'height'; const mlVersionColumn = 'ml_version'; const personIdColumn = 'person_id'; const clusterIDColumn = 'cluster_id'; +const personOrClusterIdColumn = 'person_or_cluster_id'; const createFacesTable = '''CREATE TABLE IF NOT EXISTS $facesTable ( $fileIDColumn INTEGER NOT NULL, @@ -123,3 +124,16 @@ CREATE TABLE IF NOT EXISTS $fileDataTable ( '''; const deleteFileDataTable = 'DELETE FROM $fileDataTable'; + +// ## FACE CACHE TABLE +const faceCacheTable = 'face_cache'; + +const createFaceCacheTable = ''' +CREATE TABLE IF NOT EXISTS $faceCacheTable ( + $personOrClusterIdColumn TEXT NOT NULL UNIQUE, + $faceIDColumn TEXT NOT NULL UNIQUE, + PRIMARY KEY ($personOrClusterIdColumn) +); +'''; + +const deleteFaceCacheTable = 'DELETE FROM $faceCacheTable'; diff --git a/mobile/lib/events/compute_control_event.dart b/mobile/lib/events/compute_control_event.dart new file mode 100644 index 0000000000..9f49f46420 --- /dev/null +++ b/mobile/lib/events/compute_control_event.dart @@ -0,0 +1,7 @@ +import "package:photos/events/event.dart"; + +class ComputeControlEvent extends Event { + final bool shouldRun; + + ComputeControlEvent(this.shouldRun); +} diff --git a/mobile/lib/events/create_new_album_event.dart b/mobile/lib/events/create_new_album_event.dart new file mode 100644 index 0000000000..2dbf3b72fa --- /dev/null +++ b/mobile/lib/events/create_new_album_event.dart @@ -0,0 +1,8 @@ +import "package:photos/events/event.dart"; +import "package:photos/models/collection/collection.dart"; + +class CreateNewAlbumEvent extends Event { + final Collection collection; + + CreateNewAlbumEvent(this.collection); +} \ No newline at end of file diff --git a/mobile/lib/events/details_sheet_event.dart b/mobile/lib/events/details_sheet_event.dart new file mode 100644 index 0000000000..a3fa6fbcb3 --- /dev/null +++ b/mobile/lib/events/details_sheet_event.dart @@ -0,0 +1,20 @@ +import "package:photos/events/event.dart"; + +class DetailsSheetEvent extends Event { + final int? uploadedFileID; + final String? localID; + final bool opened; + + DetailsSheetEvent({ + required this.localID, + required this.uploadedFileID, + required this.opened, + }); + + bool isSameFile({required int? uploadedFileID, required String? localID}) { + if (this.uploadedFileID == uploadedFileID && this.localID == localID) { + return true; + } + return false; + } +} diff --git a/mobile/lib/events/machine_learning_control_event.dart b/mobile/lib/events/machine_learning_control_event.dart deleted file mode 100644 index be39ec5e35..0000000000 --- a/mobile/lib/events/machine_learning_control_event.dart +++ /dev/null @@ -1,7 +0,0 @@ -import "package:photos/events/event.dart"; - -class MachineLearningControlEvent extends Event { - final bool shouldRun; - - MachineLearningControlEvent(this.shouldRun); -} diff --git a/mobile/lib/events/people_changed_event.dart b/mobile/lib/events/people_changed_event.dart index 7106421ff2..bb23f010cf 100644 --- a/mobile/lib/events/people_changed_event.dart +++ b/mobile/lib/events/people_changed_event.dart @@ -4,12 +4,14 @@ import "package:photos/models/ml/face/person.dart"; class PeopleChangedEvent extends Event { final List? relevantFiles; + final List? relevantFaceIDs; final PeopleEventType type; final String source; final PersonEntity? person; PeopleChangedEvent({ this.relevantFiles, + this.relevantFaceIDs, this.type = PeopleEventType.defaultType, this.source = "", this.person, @@ -22,6 +24,8 @@ class PeopleChangedEvent extends Event { enum PeopleEventType { defaultType, removedFilesFromCluster, + removedFaceFromCluster, syncDone, saveOrEditPerson, + addedClusterToPerson, } diff --git a/mobile/lib/events/preview_updated_event.dart b/mobile/lib/events/preview_updated_event.dart deleted file mode 100644 index 8e9cb65aaa..0000000000 --- a/mobile/lib/events/preview_updated_event.dart +++ /dev/null @@ -1,10 +0,0 @@ -import "dart:collection"; - -import "package:photos/events/event.dart"; -import "package:photos/models/preview/preview_item.dart"; - -class PreviewUpdatedEvent extends Event { - final LinkedHashMap items; - - PreviewUpdatedEvent(this.items); -} diff --git a/mobile/lib/events/reset_zoom_of_photo_view_event.dart b/mobile/lib/events/reset_zoom_of_photo_view_event.dart new file mode 100644 index 0000000000..fd25ad6917 --- /dev/null +++ b/mobile/lib/events/reset_zoom_of_photo_view_event.dart @@ -0,0 +1,18 @@ +import "package:photos/events/event.dart"; + +class ResetZoomOfPhotoView extends Event { + final int? uploadedFileID; + final String? localID; + + ResetZoomOfPhotoView({ + required this.localID, + required this.uploadedFileID, + }); + + bool isSamePhoto({required int? uploadedFileID, required String? localID}) { + if (this.uploadedFileID == uploadedFileID && this.localID == localID) { + return true; + } + return false; + } +} diff --git a/mobile/lib/generated/intl/messages_all.dart b/mobile/lib/generated/intl/messages_all.dart index 5d4e637e74..ed4269d223 100644 --- a/mobile/lib/generated/intl/messages_all.dart +++ b/mobile/lib/generated/intl/messages_all.dart @@ -39,6 +39,7 @@ import 'messages_it.dart' as messages_it; import 'messages_ja.dart' as messages_ja; import 'messages_km.dart' as messages_km; import 'messages_ko.dart' as messages_ko; +import 'messages_ku.dart' as messages_ku; import 'messages_lt.dart' as messages_lt; import 'messages_lv.dart' as messages_lv; import 'messages_ml.dart' as messages_ml; @@ -52,6 +53,7 @@ import 'messages_pt_PT.dart' as messages_pt_pt; import 'messages_ro.dart' as messages_ro; import 'messages_ru.dart' as messages_ru; import 'messages_sl.dart' as messages_sl; +import 'messages_sr.dart' as messages_sr; import 'messages_sv.dart' as messages_sv; import 'messages_ta.dart' as messages_ta; import 'messages_te.dart' as messages_te; @@ -87,6 +89,7 @@ Map _deferredLibraries = { 'ja': () => new SynchronousFuture(null), 'km': () => new SynchronousFuture(null), 'ko': () => new SynchronousFuture(null), + 'ku': () => new SynchronousFuture(null), 'lt': () => new SynchronousFuture(null), 'lv': () => new SynchronousFuture(null), 'ml': () => new SynchronousFuture(null), @@ -100,6 +103,7 @@ Map _deferredLibraries = { 'ro': () => new SynchronousFuture(null), 'ru': () => new SynchronousFuture(null), 'sl': () => new SynchronousFuture(null), + 'sr': () => new SynchronousFuture(null), 'sv': () => new SynchronousFuture(null), 'ta': () => new SynchronousFuture(null), 'te': () => new SynchronousFuture(null), @@ -159,6 +163,8 @@ MessageLookupByLibrary? _findExact(String localeName) { return messages_km.messages; case 'ko': return messages_ko.messages; + case 'ku': + return messages_ku.messages; case 'lt': return messages_lt.messages; case 'lv': @@ -185,6 +191,8 @@ MessageLookupByLibrary? _findExact(String localeName) { return messages_ru.messages; case 'sl': return messages_sl.messages; + case 'sr': + return messages_sr.messages; case 'sv': return messages_sv.messages; case 'ta': diff --git a/mobile/lib/generated/intl/messages_ar.dart b/mobile/lib/generated/intl/messages_ar.dart index df9e5f3e96..1f53f875e9 100644 --- a/mobile/lib/generated/intl/messages_ar.dart +++ b/mobile/lib/generated/intl/messages_ar.dart @@ -23,16 +23,16 @@ class MessageLookup extends MessageLookupByLibrary { static String m0(title) => "${title} (أنا)"; static String m1(count) => - "${Intl.plural(count, zero: 'إضافة متعاون', one: 'إضافة متعاون', two: 'إضافة متعاونين', few: 'إضافة ${count} متعاونين', many: 'إضافة ${count} متعاونًا', other: 'إضافة ${count} متعاونًا')}"; + "${Intl.plural(count, zero: 'إضافة متعاون', one: 'إضافة متعاون', two: 'إضافة متعاونين', other: 'إضافة ${count} متعاونًا')}"; static String m2(count) => - "${Intl.plural(count, one: 'إضافة عنصر', two: 'إضافة عنصرين', few: 'إضافة ${count} عناصر', many: 'إضافة ${count} عنصرًا', other: 'إضافة ${count} عنصرًا')}"; + "${Intl.plural(count, one: 'إضافة عنصر', two: 'إضافة عنصرين', other: 'إضافة ${count} عنصرًا')}"; static String m3(storageAmount, endDate) => "إضافتك بسعة ${storageAmount} صالحة حتى ${endDate}"; static String m4(count) => - "${Intl.plural(count, zero: 'إضافة مشاهد', one: 'إضافة مشاهد', two: 'إضافة مشاهدين', few: 'إضافة ${count} مشاهدين', many: 'إضافة ${count} مشاهدًا', other: 'إضافة ${count} مشاهدًا')}"; + "${Intl.plural(count, zero: 'إضافة مشاهد', one: 'إضافة مشاهد', two: 'إضافة مشاهدين', other: 'إضافة ${count} مشاهدًا')}"; static String m5(emailOrName) => "تمت الإضافة بواسطة ${emailOrName}"; @@ -41,7 +41,7 @@ class MessageLookup extends MessageLookupByLibrary { static String m7(name) => "الإعجاب بـ ${name}"; static String m8(count) => - "${Intl.plural(count, zero: 'لا يوجد مشاركون', one: 'مشارك واحد', two: 'مشاركان', few: '${count} مشاركين', many: '${count} مشاركًا', other: '${count} مشارك')}"; + "${Intl.plural(count, zero: 'لا يوجد مُشاركون', one: 'مُشارك واحد', other: '${count} مُشاركين')}"; static String m9(versionValue) => "الإصدار: ${versionValue}"; @@ -66,7 +66,7 @@ class MessageLookup extends MessageLookupByLibrary { static String m15(albumName) => "تم إنشاء رابط تعاوني لـ ${albumName}"; static String m16(count) => - "${Intl.plural(count, zero: 'تمت إضافة 0 متعاونين', one: 'تمت إضافة متعاون واحد', two: 'تمت إضافة متعاونين', few: 'تمت إضافة ${count} متعاونين', many: 'تمت إضافة ${count} متعاونًا', other: 'تمت إضافة ${count} متعاونًا')}"; + "${Intl.plural(count, zero: 'تمت إضافة 0 متعاونين', one: 'تمت إضافة متعاون واحد', two: 'تمت إضافة متعاونين', other: 'تمت إضافة ${count} متعاونًا')}"; static String m17(email, numOfDays) => "أنت على وشك إضافة ${email} كجهة اتصال موثوقة. سيكون بإمكانهم استعادة حسابك إذا كنت غائبًا لمدة ${numOfDays} أيام."; @@ -80,241 +80,248 @@ class MessageLookup extends MessageLookupByLibrary { static String m20(endpoint) => "متصل بـ ${endpoint}"; static String m21(count) => - "${Intl.plural(count, one: 'حذف عنصر واحد', two: 'حذف عنصرين', few: 'حذف ${count} عناصر', many: 'حذف ${count} عنصرًا', other: 'حذف ${count} عنصرًا')}"; + "${Intl.plural(count, one: 'حذف عنصر واحد', two: 'حذف عنصرين', other: 'حذف ${count} عنصرًا')}"; - static String m22(currentlyDeleting, totalCount) => + static String m22(count) => + "هل تريد أيضًا حذف الصور (والمقاطع) الموجودة في هذه الألبومات ${count} من كافة الألبومات الأخرى التي تشترك فيها؟"; + + static String m23(currentlyDeleting, totalCount) => "جارٍ الحذف ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "سيؤدي هذا إلى إزالة الرابط العام للوصول إلى \"${albumName}\"."; - static String m24(supportEmail) => - "يرجى إرسال بريد إلكتروني إلى ${supportEmail} من عنوان بريدك الإلكتروني المسجل."; + static String m25(supportEmail) => + "يرجى إرسال بريد إلكتروني إلى ${supportEmail} من عنوان بريدك الإلكتروني المسجل"; - static String m25(count, storageSaved) => - "لقد قمت بتنظيف ${Intl.plural(count, one: 'ملف مكرر واحد', two: 'ملفين مكررين', few: '${count} ملفات مكررة', many: '${count} ملفًا مكررًا', other: '${count} ملفًا مكررًا')}، مما وفر ${storageSaved}!"; + static String m26(count, storageSaved) => + "لقد قمت بتنظيف ${Intl.plural(count, one: 'ملف مكرر واحد', two: 'ملفين مكررين', other: '${count} ملفًا مكررًا')}، مما وفر ${storageSaved}!"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} ملفات، ${formattedSize} لكل منها"; - static String m27(name) => "هذا البريد الإلكتروني مرتبط مسبقاً بـ ${name}."; + static String m28(name) => "هذا البريد الإلكتروني مرتبط مسبقاً بـ ${name}."; - static String m28(newEmail) => "تم تغيير البريد الإلكتروني إلى ${newEmail}"; + static String m29(newEmail) => "تم تغيير البريد الإلكتروني إلى ${newEmail}"; - static String m29(email) => "${email} لا يملك حساب Ente."; + static String m30(email) => "${email} لا يملك حساب Ente."; - static String m30(email) => + static String m31(email) => "${email} لا يملك حسابًا على Ente.\n\nأرسل له دعوة لمشاركة الصور."; - static String m31(name) => "معانقة ${name}"; + static String m32(name) => "معانقة ${name}"; - static String m32(text) => "تم العثور على صور إضافية لـ ${text}"; + static String m33(text) => "تم العثور على صور إضافية لـ ${text}"; - static String m33(name) => "الاستمتاع بالطعام مع ${name}"; - - static String m34(count, formattedNumber) => - "${Intl.plural(count, one: 'ملف واحد', two: 'ملفان', few: '${formattedNumber} ملفات', many: '${formattedNumber} ملفًا', other: '${formattedNumber} ملفًا')} على هذا الجهاز تم نسخه احتياطيًا بأمان"; + static String m34(name) => "الاستمتاع بالطعام مع ${name}"; static String m35(count, formattedNumber) => - "${Intl.plural(count, one: 'ملف واحد', two: 'ملفان', few: '${formattedNumber} ملفات', many: '${formattedNumber} ملفًا', other: '${formattedNumber} ملفًا')} في هذا الألبوم تم نسخه احتياطيًا بأمان"; + "${Intl.plural(count, one: 'ملف واحد', two: 'ملفان', other: '${formattedNumber} ملفًا')} على هذا الجهاز تم نسخه احتياطيًا بأمان"; - static String m36(storageAmountInGB) => + static String m36(count, formattedNumber) => + "${Intl.plural(count, one: 'ملف واحد', two: 'ملفان', other: '${formattedNumber} ملفًا')} في هذا الألبوم تم نسخه احتياطيًا بأمان"; + + static String m37(storageAmountInGB) => "${storageAmountInGB} جيجابايت مجانية في كل مرة يشترك فيها شخص بخطة مدفوعة ويطبق رمزك"; - static String m37(endDate) => "التجربة المجانية صالحة حتى ${endDate}"; + static String m38(endDate) => "التجربة المجانية صالحة حتى ${endDate}"; - static String m38(count) => + static String m39(count) => "لا يزال بإمكانك الوصول ${Intl.plural(count, one: 'إليه', two: 'إليهما', other: 'إليها')} على Ente طالما لديك اشتراك نشط."; - static String m39(sizeInMBorGB) => "تحرير ${sizeInMBorGB}"; + static String m40(sizeInMBorGB) => "تحرير ${sizeInMBorGB}"; - static String m40(count, formattedSize) => - "${Intl.plural(count, one: 'يمكن حذفه من الجهاز لتحرير ${formattedSize}', two: 'يمكن حذفهما من الجهاز لتحرير ${formattedSize}', few: 'يمكن حذفها من الجهاز لتحرير ${formattedSize}', many: 'يمكن حذفها من الجهاز لتحرير ${formattedSize}', other: 'يمكن حذفها من الجهاز لتحرير ${formattedSize}')}"; + static String m41(count, formattedSize) => + "${Intl.plural(count, one: 'يمكن حذفه من الجهاز لتحرير ${formattedSize}', two: 'يمكن حذفهما من الجهاز لتحرير ${formattedSize}', other: 'يمكن حذفها من الجهاز لتحرير ${formattedSize}')}"; - static String m41(currentlyProcessing, totalCount) => + static String m42(currentlyProcessing, totalCount) => "جارٍ المعالجة ${currentlyProcessing} / ${totalCount}"; - static String m42(name) => "التنزه مع ${name}"; + static String m43(name) => "التنزه مع ${name}"; - static String m43(count) => + static String m44(count) => "${Intl.plural(count, one: '${count} عُنْصُر', other: '${count} عَنَاصِر')}"; - static String m44(name) => "آخر مرة مع ${name}"; + static String m45(name) => "آخر مرة مع ${name}"; - static String m45(email) => "${email} دعاك لتكون جهة اتصال موثوقة"; + static String m46(email) => "${email} دعاك لتكون جهة اتصال موثوقة"; - static String m46(expiryTime) => "ستنتهي صلاحية الرابط في ${expiryTime}"; + static String m47(expiryTime) => "ستنتهي صلاحية الرابط في ${expiryTime}"; - static String m47(email) => "ربط الشخص بـ ${email}"; + static String m48(email) => "ربط الشخص بـ ${email}"; - static String m48(personName, email) => + static String m49(personName, email) => "سيؤدي هذا إلى ربط ${personName} بـ ${email}"; - static String m49(count, formattedCount) => - "${Intl.plural(count, zero: 'لا توجد ذكريات', one: 'ذكرى واحدة', two: 'ذكريتان', few: '${formattedCount} ذكريات', many: '${formattedCount} ذكرى', other: '${formattedCount} ذكرى')}"; + static String m50(count, formattedCount) => + "${Intl.plural(count, zero: 'لا توجد ذكريات', one: 'ذكرى واحدة', two: 'ذكريتان', other: '${formattedCount} ذكرى')}"; - static String m50(count) => - "${Intl.plural(count, one: 'نقل عنصر', two: 'نقل عنصرين', few: 'نقل ${count} عناصر', many: 'نقل ${count} عنصرًا', other: 'نقل ${count} عنصرًا')}"; + static String m51(count) => + "${Intl.plural(count, one: 'نقل عنصر', two: 'نقل عنصرين', other: 'نقل ${count} عنصرًا')}"; - static String m51(albumName) => "تم النقل بنجاح إلى ${albumName}"; + static String m52(albumName) => "تم النقل بنجاح إلى ${albumName}"; - static String m52(personName) => "لا توجد اقتراحات لـ ${personName}"; + static String m53(personName) => "لا توجد اقتراحات لـ ${personName}"; - static String m53(name) => "ليس ${name}؟"; + static String m54(name) => "ليس ${name}؟"; - static String m54(familyAdminEmail) => + static String m55(familyAdminEmail) => "يرجى الاتصال بـ ${familyAdminEmail} لتغيير الرمز الخاص بك."; - static String m55(name) => "الاحتفال مع ${name}"; + static String m56(name) => "الاحتفال مع ${name}"; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "قوة كلمة المرور: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "يرجى التواصل مع دعم ${providerName} إذا تم خصم المبلغ منك."; - static String m58(name, age) => "${name} يبلغ ${age}!"; + static String m59(name, age) => "${name} يبلغ ${age}!"; - static String m59(name, age) => "${name} سيبلغ ${age} قريبًا"; - - static String m60(count) => - "${Intl.plural(count, zero: 'لا توجد صور', one: 'صورة واحدة', two: 'صورتان', few: '${count} صور', many: '${count} صورة', other: '${count} صورة')}"; + static String m60(name, age) => "${name} سيبلغ ${age} قريبًا"; static String m61(count) => - "${Intl.plural(count, zero: 'لا توجد صور', one: 'صورة واحدة', two: 'صورتان', few: '${count} صور', many: '${count} صورة', other: '${count} صورة')}"; + "${Intl.plural(count, zero: 'لا توجد صور', one: 'صورة واحدة', two: 'صورتان', other: '${count} صورة')}"; - static String m62(endDate) => + static String m62(count) => + "${Intl.plural(count, zero: 'لا توجد صور', one: 'صورة واحدة', two: 'صورتان', other: '${count} صورة')}"; + + static String m63(endDate) => "التجربة المجانية صالحة حتى ${endDate}.\nيمكنك اختيار خطة مدفوعة بعد ذلك."; - static String m63(toEmail) => + static String m64(toEmail) => "يرجى مراسلتنا عبر البريد الإلكتروني على ${toEmail}"; - static String m64(toEmail) => "يرجى إرسال السجلات إلى \n${toEmail}"; + static String m65(toEmail) => "يرجى إرسال السجلات إلى \n${toEmail}"; - static String m65(name) => "التقاط صور مع ${name}"; + static String m66(name) => "التقاط صور مع ${name}"; - static String m66(folderName) => "جارٍ معالجة ${folderName}..."; + static String m67(folderName) => "جارٍ معالجة ${folderName}..."; - static String m67(storeName) => "قيّمنا على ${storeName}"; + static String m68(storeName) => "قيّمنا على ${storeName}"; - static String m68(name) => "تمت إعادة تعيينك إلى ${name}"; + static String m69(name) => "تمت إعادة تعيينك إلى ${name}"; - static String m69(days, email) => + static String m70(days, email) => "يمكنك الوصول إلى الحساب بعد ${days} أيام. سيتم إرسال إشعار إلى ${email}."; - static String m70(email) => + static String m71(email) => "يمكنك الآن استرداد حساب ${email} عن طريق تعيين كلمة مرور جديدة."; - static String m71(email) => "${email} يحاول استرداد حسابك."; + static String m72(email) => "${email} يحاول استرداد حسابك."; - static String m72(storageInGB) => + static String m73(storageInGB) => "3. تحصلون كلاكما على ${storageInGB} جيجابايت* مجانًا"; - static String m73(userEmail) => + static String m74(userEmail) => "سيتم إزالة ${userEmail} من هذا الألبوم المشترك.\n\nسيتم أيضًا إزالة أي صور أضافها إلى الألبوم."; - static String m74(endDate) => "يتجدد الاشتراك في ${endDate}"; + static String m75(endDate) => "يتجدد الاشتراك في ${endDate}"; - static String m75(name) => "رحلة برية مع ${name}"; + static String m76(name) => "رحلة برية مع ${name}"; - static String m76(count) => - "${Intl.plural(count, one: '${count} النتائج التي تم العثور عليها', other: '${count} النتائج التي تم العثور عليها')}"; + static String m77(count) => + "${Intl.plural(count, other: '${count} النتائج التي تم العثور عليها')}"; - static String m77(snapshotLength, searchLength) => + static String m78(snapshotLength, searchLength) => "عدم تطابق طول الأقسام: ${snapshotLength} != ${searchLength}"; - static String m78(count) => "تم تحديد ${count}"; + static String m79(count) => "${count} تم تحديد"; - static String m79(count, yourCount) => + static String m80(count) => "تم تحديد ${count}"; + + static String m81(count, yourCount) => "تم تحديد ${count} (${yourCount} منها لك)"; - static String m80(name) => "صور سيلفي مع ${name}"; + static String m82(name) => "صور سيلفي مع ${name}"; - static String m81(verificationID) => + static String m83(verificationID) => "إليك معرّف التحقق الخاص بي لـ ente.io: ${verificationID}"; - static String m82(verificationID) => - "مرحبًا، هل يمكنك تأكيد أن هذا هو معرّف التحقق الخاص بك على ente.io: ${verificationID}؟"; + static String m84(verificationID) => + "مرحبًا، هل يمكنك تأكيد أن هذا هو معرّف التحقق الخاص بك على ente.io: ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "رمز إحالة Ente الخاص بي: ${referralCode}\n\nطبقه في الإعدادات ← عام ← الإحالات للحصول على ${referralStorageInGB} جيجابايت مجانًا بعد الاشتراك في خطة مدفوعة.\n\nhttps://ente.io"; - static String m84(numberOfPeople) => - "${Intl.plural(numberOfPeople, zero: 'مشاركة مع أشخاص محددين', one: 'تمت المشاركة مع شخص واحد', two: 'تمت المشاركة مع شخصين', few: 'تمت المشاركة مع ${numberOfPeople} أشخاص', many: 'تمت المشاركة مع ${numberOfPeople} شخصًا', other: 'تمت المشاركة مع ${numberOfPeople} شخصًا')}"; + static String m86(numberOfPeople) => + "${Intl.plural(numberOfPeople, zero: 'مشاركة مع أشخاص مُحددين', one: 'مُشارَك مع شخص واحد', other: 'مُشارَك مع ${numberOfPeople} أشخاص')}"; - static String m85(emailIDs) => "تمت المشاركة مع ${emailIDs}"; + static String m87(emailIDs) => "تمت المشاركة مع ${emailIDs}"; - static String m86(fileType) => "سيتم حذف ${fileType} من جهازك."; + static String m88(fileType) => "سيتم حذف ${fileType} من جهازك."; - static String m87(fileType) => "${fileType} موجود في Ente وعلى جهازك."; + static String m89(fileType) => "${fileType} موجود في Ente وعلى جهازك."; - static String m88(fileType) => "سيتم حذف ${fileType} من Ente."; + static String m90(fileType) => "سيتم حذف ${fileType} من Ente."; - static String m89(name) => "الرياضة مع ${name}"; + static String m91(name) => "الرياضة مع ${name}"; - static String m90(name) => "تسليط الضوء على ${name}"; + static String m92(name) => "تسليط الضوء على ${name}"; - static String m91(storageAmountInGB) => "${storageAmountInGB} جيجابايت"; + static String m93(storageAmountInGB) => "${storageAmountInGB} جيجابايت"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "تم استخدام ${usedAmount} ${usedStorageUnit} من ${totalAmount} ${totalStorageUnit}"; - static String m93(id) => + static String m95(id) => "تم ربط ${id} الخاص بك بحساب Ente آخر.\nإذا كنت ترغب في استخدام ${id} مع هذا الحساب، يرجى الاتصال بدعمنا."; - static String m94(endDate) => "سيتم إلغاء اشتراكك في ${endDate}"; + static String m96(endDate) => "سيتم إلغاء اشتراكك في ${endDate}"; - static String m95(completed, total) => "${completed}/${total} ذكريات محفوظة"; + static String m97(completed, total) => "${completed}/${total} ذكريات محفوظة"; - static String m96(ignoreReason) => + static String m98(ignoreReason) => "انقر للتحميل، تم تجاهل التحميل حاليًا بسبب ${ignoreReason}"; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "سيحصلون أيضًا على ${storageAmountInGB} جيجابايت"; - static String m98(email) => "هذا هو معرّف التحقق الخاص بـ ${email}"; - - static String m99(count) => - "${Intl.plural(count, one: 'هذا الأسبوع، قبل سنة', two: 'هذا الأسبوع، قبل سنتين', few: 'هذا الأسبوع، قبل ${count} سنوات', many: 'هذا الأسبوع، قبل ${count} سنة', other: 'هذا الأسبوع، قبل ${count} سنة')}"; - - static String m100(dateFormat) => "${dateFormat} عبر السنين"; + static String m100(email) => "هذا هو معرّف التحقق الخاص بـ ${email}"; static String m101(count) => - "${Intl.plural(count, zero: 'قريبًا', one: 'يوم واحد', two: 'يومان', few: '${count} أيام', many: '${count} يومًا', other: '${count} يومًا')}"; + "${Intl.plural(count, one: 'هذا الأسبوع، قبل سنة', two: 'هذا الأسبوع، قبل سنتين', other: 'هذا الأسبوع، قبل ${count} سنة')}"; - static String m102(year) => "رحلة في ${year}"; + static String m102(dateFormat) => "${dateFormat} عبر السنين"; - static String m103(location) => "رحلة إلى ${location}"; + static String m103(count) => + "${Intl.plural(count, zero: 'قريبًا', one: 'يوم واحد', two: 'يومان', other: '${count} يومًا')}"; - static String m104(email) => + static String m104(year) => "رحلة في ${year}"; + + static String m105(location) => "رحلة إلى ${location}"; + + static String m106(email) => "لقد تمت دعوتك لتكون جهة اتصال موثوقة بواسطة ${email}."; - static String m105(galleryType) => + static String m107(galleryType) => "نوع المعرض ${galleryType} غير مدعوم لإعادة التسمية."; - static String m106(ignoreReason) => "تم تجاهل التحميل بسبب ${ignoreReason}"; + static String m108(ignoreReason) => "تم تجاهل التحميل بسبب ${ignoreReason}"; - static String m107(count) => "جارٍ حفظ ${count} ذكريات..."; + static String m109(count) => "جارٍ حفظ ${count} ذكريات..."; - static String m108(endDate) => "صالح حتى ${endDate}"; + static String m110(endDate) => "صالح حتى ${endDate}"; - static String m109(email) => "التحقق من ${email}"; + static String m111(email) => "التحقق من ${email}"; - static String m110(name) => "عرض ${name} لإلغاء الربط"; - - static String m111(count) => - "${Intl.plural(count, zero: 'تمت إضافة 0 مشاهدين', one: 'تمت إضافة مشاهد واحد', two: 'تمت إضافة مشاهدين', few: 'تمت إضافة ${count} مشاهدين', many: 'تمت إضافة ${count} مشاهدًا', other: 'تمت إضافة ${count} مشاهدًا')}"; - - static String m112(email) => - "لقد أرسلنا بريدًا إلكترونيًا إلى ${email}"; + static String m112(name) => "عرض ${name} لإلغاء الربط"; static String m113(count) => - "${Intl.plural(count, one: 'قبل سنة', two: 'قبل سنتين', few: 'قبل ${count} سنوات', many: 'قبل ${count} سنة', other: 'قبل ${count} سنة')}"; + "${Intl.plural(count, zero: 'تمت إضافة 0 مشاهدين', one: 'تمت إضافة مشاهد واحد', two: 'تمت إضافة مشاهدين', other: 'تمت إضافة ${count} مشاهدًا')}"; - static String m114(name) => "أنت و ${name}"; + static String m114(email) => + "لقد أرسلنا بريدًا إلكترونيًا إلى ${email}"; - static String m115(storageSaved) => "لقد حررت ${storageSaved} بنجاح!"; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + + static String m116(count) => + "${Intl.plural(count, one: 'قبل سنة', two: 'قبل سنتين', other: 'قبل ${count} سنة')}"; + + static String m117(name) => "أنت و ${name}"; + + static String m118(storageSaved) => "لقد حررت ${storageSaved} بنجاح!"; final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { @@ -331,6 +338,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("أهلاً بعودتك!"), "ackPasswordLostWarning": MessageLookupByLibrary.simpleMessage( "أدرك أنني إذا فقدت كلمة المرور، فقد أفقد بياناتي لأنها مشفرة بالكامل من طرف إلى طرف."), + "actionNotSupportedOnFavouritesAlbum": + MessageLookupByLibrary.simpleMessage( + "الإجراء غير مدعوم في ألبوم المفضلة"), "activeSessions": MessageLookupByLibrary.simpleMessage("الجلسات النشطة"), "add": MessageLookupByLibrary.simpleMessage("إضافة"), @@ -355,6 +365,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("تفاصيل الإضافات"), "addOnValidTill": m3, "addOns": MessageLookupByLibrary.simpleMessage("الإضافات"), + "addParticipants": + MessageLookupByLibrary.simpleMessage("إضافة مشاركين"), "addPhotos": MessageLookupByLibrary.simpleMessage("إضافة صور"), "addSelected": MessageLookupByLibrary.simpleMessage("إضافة المحدد"), "addToAlbum": MessageLookupByLibrary.simpleMessage("إضافة إلى الألبوم"), @@ -467,28 +479,28 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("في ملجأ للطوارئ"), "authToChangeEmailVerificationSetting": MessageLookupByLibrary.simpleMessage( - "يرجى المصادقة لتغيير إعداد التحقق من البريد الإلكتروني."), + "يرجى المصادقة لتغيير إعداد التحقق من البريد الإلكتروني"), "authToChangeLockscreenSetting": MessageLookupByLibrary.simpleMessage( "يرجى المصادقة لتغيير إعدادات شاشة القفل."), "authToChangeYourEmail": MessageLookupByLibrary.simpleMessage( - "يرجى المصادقة لتغيير بريدك الإلكتروني."), + "يرجى المصادقة لتغيير بريدك الإلكتروني"), "authToChangeYourPassword": MessageLookupByLibrary.simpleMessage( - "يرجى المصادقة لتغيير كلمة المرور الخاصة بك."), + "يرجى المصادقة لتغيير كلمة المرور الخاصة بك"), "authToConfigureTwofactorAuthentication": MessageLookupByLibrary.simpleMessage( "يرجى المصادقة لإعداد المصادقة الثنائية."), "authToInitiateAccountDeletion": MessageLookupByLibrary.simpleMessage( - "يرجى المصادقة لبدء عملية حذف الحساب."), + "يرجى المصادقة لبدء عملية حذف الحساب"), "authToManageLegacy": MessageLookupByLibrary.simpleMessage( "يرجى المصادقة لإدارة جهات الاتصال الموثوقة الخاصة بك."), "authToViewPasskey": MessageLookupByLibrary.simpleMessage( "يرجى المصادقة لعرض مفتاح المرور الخاص بك."), "authToViewTrashedFiles": MessageLookupByLibrary.simpleMessage( - "يرجى المصادقة لعرض ملفاتك المحذوفة."), + "يرجى المصادقة لعرض ملفاتك المحذوفة"), "authToViewYourActiveSessions": MessageLookupByLibrary.simpleMessage( "يرجى المصادقة لعرض جلساتك النشطة."), "authToViewYourHiddenFiles": MessageLookupByLibrary.simpleMessage( - "يرجى المصادقة للوصول إلى ملفاتك المخفية."), + "يرجى المصادقة للوصول إلى ملفاتك المخفية"), "authToViewYourMemories": MessageLookupByLibrary.simpleMessage("يرجى المصادقة لعرض ذكرياتك."), "authToViewYourRecoveryKey": MessageLookupByLibrary.simpleMessage( @@ -533,6 +545,7 @@ class MessageLookup extends MessageLookupByLibrary { "النسخ الاحتياطي لمقاطع الفيديو"), "beach": MessageLookupByLibrary.simpleMessage("رمال وبحر"), "birthday": MessageLookupByLibrary.simpleMessage("تاريخ الميلاد"), + "birthdays": MessageLookupByLibrary.simpleMessage("أعياد الميلاد"), "blackFridaySale": MessageLookupByLibrary.simpleMessage("تخفيضات الجمعة السوداء"), "blog": MessageLookupByLibrary.simpleMessage("المدونة"), @@ -560,7 +573,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("إلغاء الاشتراك"), "cannotAddMorePhotosAfterBecomingViewer": m13, "cannotDeleteSharedFiles": MessageLookupByLibrary.simpleMessage( - "لا يمكن حذف الملفات المشتركة."), + "لا يمكن حذف الملفات المشتركة"), "castAlbum": MessageLookupByLibrary.simpleMessage("بث الألبوم"), "castIPMismatchBody": MessageLookupByLibrary.simpleMessage( "يرجى التأكد من أنك متصل بنفس الشبكة المتصل بها التلفزيون."), @@ -606,8 +619,6 @@ class MessageLookup extends MessageLookupByLibrary { "click": MessageLookupByLibrary.simpleMessage("• انقر على"), "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage( "• انقر على قائمة الخيارات الإضافية"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "close": MessageLookupByLibrary.simpleMessage("إغلاق"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage("التجميع حسب وقت الالتقاط"), @@ -624,7 +635,7 @@ class MessageLookup extends MessageLookupByLibrary { "codeUsedByYou": MessageLookupByLibrary.simpleMessage("الرمز المستخدم من قبلك"), "collabLinkSectionDescription": MessageLookupByLibrary.simpleMessage( - "أنشئ رابطًا يسمح للأشخاص بإضافة الصور ومشاهدتها في ألبومك المشترك دون الحاجة إلى تطبيق Ente أو حساب. خيار مثالي لجمع صور الفعاليات بسهولة."), + "أنشئ رابطًا يسمح للأشخاص بإضافة الصور ومشاهدتها في ألبومك المشترك دون الحاجة إلى تطبيق أو حساب Ente. خيار مثالي لجمع صور الفعاليات بسهولة."), "collaborativeLink": MessageLookupByLibrary.simpleMessage("رابط تعاوني"), "collaborativeLinkCreatedFor": m15, @@ -708,7 +719,7 @@ class MessageLookup extends MessageLookupByLibrary { "crop": MessageLookupByLibrary.simpleMessage("اقتصاص"), "curatedMemories": MessageLookupByLibrary.simpleMessage("ذكريات منسقة"), "currentUsageIs": - MessageLookupByLibrary.simpleMessage("استخدامك الحالي هو"), + MessageLookupByLibrary.simpleMessage("استخدامك الحالي هو "), "currentlyRunning": MessageLookupByLibrary.simpleMessage("قيد التشغيل حاليًا"), "custom": MessageLookupByLibrary.simpleMessage("مخصص"), @@ -748,11 +759,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("الحذف من كليهما"), "deleteFromDevice": MessageLookupByLibrary.simpleMessage("الحذف من الجهاز"), - "deleteFromEnte": MessageLookupByLibrary.simpleMessage("الحذف من Ente"), + "deleteFromEnte": MessageLookupByLibrary.simpleMessage("حذف من Ente"), "deleteItemCount": m21, "deleteLocation": MessageLookupByLibrary.simpleMessage("حذف الموقع"), + "deleteMultipleAlbumDialog": m22, "deletePhotos": MessageLookupByLibrary.simpleMessage("حذف الصور"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "تفتقر إلى مِيزة أساسية أحتاج إليها"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -786,10 +798,10 @@ class MessageLookup extends MessageLookupByLibrary { "disableAutoLock": MessageLookupByLibrary.simpleMessage("تعطيل القفل التلقائي"), "disableDownloadWarningBody": MessageLookupByLibrary.simpleMessage( - "لا يزال بإمكان المشاهدين التقاط لقطات شاشة أو حفظ نسخة من صورك باستخدام أدوات خارجية."), + "لا يزال بإمكان المشاهدين التقاط لقطات شاشة أو حفظ نسخة من صورك باستخدام أدوات خارجية"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("يرجى الملاحظة"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage("تعطيل المصادقة الثنائية"), "disablingTwofactorAuthentication": @@ -832,11 +844,11 @@ class MessageLookup extends MessageLookupByLibrary { "download": MessageLookupByLibrary.simpleMessage("تنزيل"), "downloadFailed": MessageLookupByLibrary.simpleMessage("فشل التنزيل"), "downloading": MessageLookupByLibrary.simpleMessage("جارٍ التنزيل..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("تعديل"), - "editEmailAlreadyLinked": m27, + "editEmailAlreadyLinked": m28, "editLocation": MessageLookupByLibrary.simpleMessage("تعديل الموقع"), "editLocationTagTitle": MessageLookupByLibrary.simpleMessage("تعديل الموقع"), @@ -850,16 +862,16 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("البريد الإلكتروني"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage( "البريد الإلكتروني مُسجل من قبل."), - "emailChangedTo": m28, - "emailDoesNotHaveEnteAccount": m29, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailDoesNotHaveEnteAccount": m30, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage("البريد الإلكتروني غير مسجل."), "emailVerificationToggle": MessageLookupByLibrary.simpleMessage( "تأكيد عنوان البريد الإلكتروني"), "emailYourLogs": MessageLookupByLibrary.simpleMessage( "إرسال سجلاتك عبر البريد الإلكتروني"), - "embracingThem": m31, + "embracingThem": m32, "emergencyContacts": MessageLookupByLibrary.simpleMessage("جهات اتصال الطوارئ"), "empty": MessageLookupByLibrary.simpleMessage("إفراغ"), @@ -885,7 +897,7 @@ class MessageLookup extends MessageLookupByLibrary { "تشفير من طرف إلى طرف بشكل افتراضي"), "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": MessageLookupByLibrary.simpleMessage( - "يمكن لـ Ente تشفير وحفظ الملفات فقط إذا منحت الإذن بالوصول إليها."), + "يمكن لـ Ente تشفير وحفظ الملفات فقط إذا منحت الإذن بالوصول إليها"), "entePhotosPerm": MessageLookupByLibrary.simpleMessage( "Ente بحاجة إلى إذن لحفظ صورك"), "enteSubscriptionPitch": MessageLookupByLibrary.simpleMessage( @@ -896,7 +908,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("أدخل اسم الألبوم"), "enterCode": MessageLookupByLibrary.simpleMessage("أدخل الرمز"), "enterCodeDescription": MessageLookupByLibrary.simpleMessage( - "أدخل الرمز المقدم من صديقك للمطالبة بمساحة تخزين مجانية لكما."), + "أدخل الرمز المقدم من صديقك للمطالبة بمساحة تخزين مجانية لكما"), "enterDateOfBirth": MessageLookupByLibrary.simpleMessage("تاريخ الميلاد (اختياري)"), "enterEmail": @@ -921,6 +933,8 @@ class MessageLookup extends MessageLookupByLibrary { "يرجى إدخال عنوان بريد إلكتروني صالح."), "enterYourEmailAddress": MessageLookupByLibrary.simpleMessage("أدخل عنوان بريدك الإلكتروني"), + "enterYourNewEmailAddress": MessageLookupByLibrary.simpleMessage( + "أدخل عنوان بريدك الإلكتروني الجديد"), "enterYourPassword": MessageLookupByLibrary.simpleMessage("أدخل كلمة المرور"), "enterYourRecoveryKey": @@ -935,7 +949,7 @@ class MessageLookup extends MessageLookupByLibrary { "exportYourData": MessageLookupByLibrary.simpleMessage("تصدير بياناتك"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage("تم العثور على صور إضافية"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage( "لم يتم تجميع الوجه بعد، يرجى العودة لاحقًا"), "faceRecognition": @@ -970,7 +984,7 @@ class MessageLookup extends MessageLookupByLibrary { "faq": MessageLookupByLibrary.simpleMessage("الأسئلة الشائعة"), "faqs": MessageLookupByLibrary.simpleMessage("الأسئلة الشائعة"), "favorite": MessageLookupByLibrary.simpleMessage("المفضلة"), - "feastingWithThem": m33, + "feastingWithThem": m34, "feedback": MessageLookupByLibrary.simpleMessage("ملاحظات"), "file": MessageLookupByLibrary.simpleMessage("ملف"), "fileFailedToSaveToGallery": @@ -984,8 +998,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("أنواع الملفات"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("أنواع وأسماء الملفات"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("تم حذف الملفات."), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage("تم حفظ الملفات في المعرض."), @@ -997,37 +1011,37 @@ class MessageLookup extends MessageLookupByLibrary { "food": MessageLookupByLibrary.simpleMessage("متعة الطهي"), "forYourMemories": MessageLookupByLibrary.simpleMessage("لذكرياتك"), "forgotPassword": - MessageLookupByLibrary.simpleMessage("نسيت كلمة المرور؟"), + MessageLookupByLibrary.simpleMessage("نسيت كلمة المرور"), "foundFaces": MessageLookupByLibrary.simpleMessage("الوجوه التي تم العثور عليها"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage( "تم المطالبة بمساحة التخزين المجانية"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage( "مساحة تخزين مجانية متاحة للاستخدام"), "freeTrial": MessageLookupByLibrary.simpleMessage("تجربة مجانية"), - "freeTrialValidTill": m37, - "freeUpAccessPostDelete": m38, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAccessPostDelete": m39, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("تحرير مساحة على الجهاز"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "وفر مساحة على جهازك عن طريق مسح الملفات التي تم نسخها احتياطيًا."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("تحرير المساحة"), - "freeUpSpaceSaving": m40, + "freeUpSpaceSaving": m41, "gallery": MessageLookupByLibrary.simpleMessage("المعرض"), "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "يتم عرض ما يصل إلى 1000 ذكرى في المعرض."), "general": MessageLookupByLibrary.simpleMessage("عام"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "جارٍ إنشاء مفاتيح التشفير..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("الانتقال إلى الإعدادات"), "googlePlayId": MessageLookupByLibrary.simpleMessage("معرّف Google Play"), "grantFullAccessPrompt": MessageLookupByLibrary.simpleMessage( - "يرجى السماح بالوصول إلى جميع الصور في تطبيق الإعدادات."), + "الرجاء السماح بالوصول إلى جميع الصور في تطبيق الإعدادات"), "grantPermission": MessageLookupByLibrary.simpleMessage("منح الإذن"), "greenery": MessageLookupByLibrary.simpleMessage("الحياة الخضراء"), "groupNearbyPhotos": @@ -1035,6 +1049,8 @@ class MessageLookup extends MessageLookupByLibrary { "guestView": MessageLookupByLibrary.simpleMessage("عرض الضيف"), "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( "لتمكين عرض الضيف، يرجى إعداد رمز مرور الجهاز أو قفل الشاشة في إعدادات النظام."), + "happyBirthday": + MessageLookupByLibrary.simpleMessage("عيد ميلاد سعيد! 🥳"), "hearUsExplanation": MessageLookupByLibrary.simpleMessage( "نحن لا نتتبع عمليات تثبيت التطبيق. سيساعدنا إذا أخبرتنا أين وجدتنا!"), "hearUsWhereTitle": @@ -1050,7 +1066,7 @@ class MessageLookup extends MessageLookupByLibrary { "hideSharedItemsFromHomeGallery": MessageLookupByLibrary.simpleMessage( "إخفاء العناصر المشتركة من معرض الصفحة الرئيسية"), "hiding": MessageLookupByLibrary.simpleMessage("جارٍ الإخفاء..."), - "hikingWithThem": m42, + "hikingWithThem": m43, "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("مستضاف في OSM France"), "howItWorks": MessageLookupByLibrary.simpleMessage("كيف يعمل"), @@ -1105,7 +1121,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "يبدو أن خطأً ما قد حدث. يرجى المحاولة مرة أخرى بعد بعض الوقت. إذا استمر الخطأ، يرجى الاتصال بفريق الدعم لدينا."), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "تعرض العناصر عدد الأيام المتبقية قبل الحذف الدائم."), @@ -1127,7 +1143,7 @@ class MessageLookup extends MessageLookupByLibrary { "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( "يرجى مساعدتنا بهذه المعلومات"), "language": MessageLookupByLibrary.simpleMessage("اللغة"), - "lastTimeWithThem": m44, + "lastTimeWithThem": m45, "lastUpdated": MessageLookupByLibrary.simpleMessage("آخر تحديث"), "lastYearsTrip": MessageLookupByLibrary.simpleMessage("رحلة العام الماضي"), @@ -1141,7 +1157,7 @@ class MessageLookup extends MessageLookupByLibrary { "legacy": MessageLookupByLibrary.simpleMessage("جهات الاتصال الموثوقة"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("الحسابات الموثوقة"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage( "تسمح جهات الاتصال الموثوقة لأشخاص معينين بالوصول إلى حسابك في حالة غيابك."), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( @@ -1158,7 +1174,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("لمشاركة أسرع"), "linkEnabled": MessageLookupByLibrary.simpleMessage("مفعّل"), "linkExpired": MessageLookupByLibrary.simpleMessage("منتهي الصلاحية"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("انتهاء صلاحية الرابط"), "linkHasExpired": @@ -1167,13 +1183,13 @@ class MessageLookup extends MessageLookupByLibrary { "linkPerson": MessageLookupByLibrary.simpleMessage("ربط الشخص"), "linkPersonCaption": MessageLookupByLibrary.simpleMessage("لتجربة مشاركة أفضل"), - "linkPersonToEmail": m47, - "linkPersonToEmailConfirmation": m48, + "linkPersonToEmail": m48, + "linkPersonToEmailConfirmation": m49, "livePhotos": MessageLookupByLibrary.simpleMessage("الصور الحية"), "loadMessage1": MessageLookupByLibrary.simpleMessage( "يمكنك مشاركة اشتراكك مع عائلتك."), "loadMessage2": MessageLookupByLibrary.simpleMessage( - "لقد حفظنا أكثر من 200 مليون ذكرى حتى الآن."), + "لقد حفظنا أكثر من 200 مليون ذكرى حتى الآن"), "loadMessage3": MessageLookupByLibrary.simpleMessage( "نحتفظ بـ 3 نسخ من بياناتك، إحداها في ملجأ للطوارئ تحت الأرض."), "loadMessage4": MessageLookupByLibrary.simpleMessage( @@ -1230,8 +1246,6 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "اضغط مطولاً على عنصر لعرضه في وضع ملء الشاشة."), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "loopVideoOff": MessageLookupByLibrary.simpleMessage("إيقاف تكرار الفيديو"), "loopVideoOn": @@ -1259,7 +1273,8 @@ class MessageLookup extends MessageLookupByLibrary { "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), "me": MessageLookupByLibrary.simpleMessage("أنا"), - "memoryCount": m49, + "memories": MessageLookupByLibrary.simpleMessage("ذكريات"), + "memoryCount": m50, "merchandise": MessageLookupByLibrary.simpleMessage("المنتجات الترويجية"), "mergeWithExisting": @@ -1291,13 +1306,13 @@ class MessageLookup extends MessageLookupByLibrary { "mostRecent": MessageLookupByLibrary.simpleMessage("الأحدث"), "mostRelevant": MessageLookupByLibrary.simpleMessage("الأكثر صلة"), "mountains": MessageLookupByLibrary.simpleMessage("فوق التلال"), - "moveItem": m50, + "moveItem": m51, "moveSelectedPhotosToOneDate": MessageLookupByLibrary.simpleMessage( "نقل الصور المحددة إلى تاريخ واحد"), "moveToAlbum": MessageLookupByLibrary.simpleMessage("نقل إلى ألبوم"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("نقل إلى الألبوم المخفي"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("تم النقل إلى سلة المهملات"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1312,7 +1327,7 @@ class MessageLookup extends MessageLookupByLibrary { "newAlbum": MessageLookupByLibrary.simpleMessage("ألبوم جديد"), "newLocation": MessageLookupByLibrary.simpleMessage("موقع جديد"), "newPerson": MessageLookupByLibrary.simpleMessage("شخص جديد"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), + "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" جديد 📸"), "newRange": MessageLookupByLibrary.simpleMessage("نطاق جديد"), "newToEnte": MessageLookupByLibrary.simpleMessage("جديد في Ente"), "newest": MessageLookupByLibrary.simpleMessage("الأحدث"), @@ -1324,7 +1339,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("لم يتم العثور على جهاز."), "noDeviceLimit": MessageLookupByLibrary.simpleMessage("لا شيء"), "noDeviceThatCanBeDeleted": MessageLookupByLibrary.simpleMessage( - "لا توجد ملفات على هذا الجهاز يمكن حذفها."), + "لا توجد ملفات على هذا الجهاز يمكن حذفها"), "noDuplicates": MessageLookupByLibrary.simpleMessage("✨ لا توجد ملفات مكررة"), "noEnteAccountExclamation": @@ -1341,7 +1356,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("لا يوجد اتصال بالإنترنت"), "noPhotosAreBeingBackedUpRightNow": MessageLookupByLibrary.simpleMessage( - "لا يتم نسخ أي صور احتياطيًا في الوقت الحالي."), + "لا يتم نسخ أي صور احتياطيًا في الوقت الحالي"), "noPhotosFoundHere": MessageLookupByLibrary.simpleMessage("لم يتم العثور على صور هنا"), "noQuickLinksSelected": @@ -1353,10 +1368,10 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("لا توجد نتائج"), "noResultsFound": MessageLookupByLibrary.simpleMessage("لم يتم العثور على نتائج."), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage("لم يتم العثور على قفل نظام."), - "notPersonLabel": m53, + "notPersonLabel": m54, "notThisPerson": MessageLookupByLibrary.simpleMessage("ليس هذا الشخص؟"), "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( "لم تتم مشاركة أي شيء معك بعد"), @@ -1369,10 +1384,8 @@ class MessageLookup extends MessageLookupByLibrary { "على Ente"), "onTheRoad": MessageLookupByLibrary.simpleMessage("على الطريق مرة أخرى"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "onThisDay": MessageLookupByLibrary.simpleMessage("في هذا اليوم"), + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("هم فقط"), "oops": MessageLookupByLibrary.simpleMessage("عفوًا"), "oopsCouldNotSaveEdits": @@ -1402,7 +1415,7 @@ class MessageLookup extends MessageLookupByLibrary { "pairingComplete": MessageLookupByLibrary.simpleMessage("اكتمل الإقران"), "panorama": MessageLookupByLibrary.simpleMessage("بانوراما"), - "partyWithThem": m55, + "partyWithThem": m56, "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage("التحقق لا يزال معلقًا."), "passkey": MessageLookupByLibrary.simpleMessage("مفتاح المرور"), @@ -1412,7 +1425,7 @@ class MessageLookup extends MessageLookupByLibrary { "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage("تم تغيير كلمة المرور بنجاح"), "passwordLock": MessageLookupByLibrary.simpleMessage("قفل بكلمة مرور"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "يتم حساب قوة كلمة المرور مع الأخذ في الاعتبار طول كلمة المرور، والأحرف المستخدمة، وما إذا كانت كلمة المرور تظهر في قائمة أفضل 10,000 كلمة مرور شائعة الاستخدام."), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -1422,7 +1435,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("فشلت عملية الدفع"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "للأسف، فشلت عملية الدفع الخاصة بك. يرجى الاتصال بالدعم وسوف نساعدك!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("العناصر المعلقة"), "pendingSync": MessageLookupByLibrary.simpleMessage("المزامنة المعلقة"), "people": MessageLookupByLibrary.simpleMessage("الأشخاص"), @@ -1433,20 +1446,20 @@ class MessageLookup extends MessageLookupByLibrary { "permanentlyDelete": MessageLookupByLibrary.simpleMessage("حذف نهائي"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage("حذف نهائي من الجهاز؟"), - "personIsAge": m58, + "personIsAge": m59, "personName": MessageLookupByLibrary.simpleMessage("اسم الشخص"), - "personTurningAge": m59, + "personTurningAge": m60, "pets": MessageLookupByLibrary.simpleMessage("رفاق فروي"), "photoDescriptions": MessageLookupByLibrary.simpleMessage("أوصاف الصور"), "photoGridSize": MessageLookupByLibrary.simpleMessage("حجم شبكة الصور"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("صورة"), - "photocountPhotos": m60, + "photocountPhotos": m61, "photos": MessageLookupByLibrary.simpleMessage("الصور"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage( "ستتم إزالة الصور التي أضفتها من الألبوم."), - "photosCount": m61, + "photosCount": m62, "photosKeepRelativeTimeDifference": MessageLookupByLibrary.simpleMessage( "تحتفظ الصور بالفرق الزمني النسبي"), @@ -1457,7 +1470,7 @@ class MessageLookup extends MessageLookupByLibrary { "playOnTv": MessageLookupByLibrary.simpleMessage("تشغيل الألبوم على التلفزيون"), "playOriginal": MessageLookupByLibrary.simpleMessage("تشغيل الأصلي"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playStream": MessageLookupByLibrary.simpleMessage("تشغيل البث"), "playstoreSubscription": MessageLookupByLibrary.simpleMessage("اشتراك متجر Play"), @@ -1470,14 +1483,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "يرجى الاتصال بالدعم إذا استمرت المشكلة."), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": - MessageLookupByLibrary.simpleMessage("يرجى منح الأذونات."), + MessageLookupByLibrary.simpleMessage("يرجى منح الأذونات"), "pleaseLoginAgain": - MessageLookupByLibrary.simpleMessage("يرجى تسجيل الدخول مرة أخرى."), + MessageLookupByLibrary.simpleMessage("يرجى تسجيل الدخول مرة أخرى"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "يرجى تحديد الروابط السريعة للإزالة."), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("يرجى المحاولة مرة أخرى"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1488,10 +1501,10 @@ class MessageLookup extends MessageLookupByLibrary { "يرجى الانتظار، جارٍ حذف الألبوم"), "pleaseWaitForSometimeBeforeRetrying": MessageLookupByLibrary.simpleMessage( - "يرجى الانتظار لبعض الوقت قبل إعادة المحاولة."), + "يرجى الانتظار لبعض الوقت قبل إعادة المحاولة"), "pleaseWaitThisWillTakeAWhile": MessageLookupByLibrary.simpleMessage( "يرجى الانتظار، قد يستغرق هذا بعض الوقت."), - "posingWithThem": m65, + "posingWithThem": m66, "preparingLogs": MessageLookupByLibrary.simpleMessage("جارٍ تحضير السجلات..."), "preserveMore": MessageLookupByLibrary.simpleMessage("حفظ المزيد"), @@ -1509,7 +1522,7 @@ class MessageLookup extends MessageLookupByLibrary { "proceed": MessageLookupByLibrary.simpleMessage("متابعة"), "processed": MessageLookupByLibrary.simpleMessage("تمت المعالجة"), "processing": MessageLookupByLibrary.simpleMessage("المعالجة"), - "processingImport": m66, + "processingImport": m67, "processingVideos": MessageLookupByLibrary.simpleMessage("معالجة مقاطع الفيديو"), "publicLinkCreated": @@ -1522,10 +1535,10 @@ class MessageLookup extends MessageLookupByLibrary { "raiseTicket": MessageLookupByLibrary.simpleMessage("فتح تذكرة دعم"), "rateTheApp": MessageLookupByLibrary.simpleMessage("تقييم التطبيق"), "rateUs": MessageLookupByLibrary.simpleMessage("تقييم التطبيق"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "reassignMe": MessageLookupByLibrary.simpleMessage("إعادة تعيين \"أنا\""), - "reassignedToName": m68, + "reassignedToName": m69, "reassigningLoading": MessageLookupByLibrary.simpleMessage("جارٍ إعادة التعيين..."), "recover": MessageLookupByLibrary.simpleMessage("استعادة"), @@ -1536,7 +1549,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("استرداد الحساب"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage("بدء الاسترداد"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("مفتاح الاسترداد"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( "تم نسخ مفتاح الاسترداد إلى الحافظة"), @@ -1547,15 +1560,15 @@ class MessageLookup extends MessageLookupByLibrary { "recoveryKeySuccessBody": MessageLookupByLibrary.simpleMessage( "مفتاح الاسترداد الخاص بك صالح. شكرًا على التحقق.\n\nيرجى تذكر الاحتفاظ بنسخة احتياطية آمنة من مفتاح الاسترداد."), "recoveryKeyVerified": MessageLookupByLibrary.simpleMessage( - "تم التحقق من مفتاح الاسترداد."), + "تم التحقق من مفتاح الاسترداد"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "مفتاح الاسترداد هو الطريقة الوحيدة لاستعادة صورك إذا نسيت كلمة المرور. يمكنك العثور عليه في الإعدادات > الحساب.\n\nالرجاء إدخال مفتاح الاسترداد هنا للتحقق من أنك حفظته بشكل صحيح."), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage("تم الاسترداد بنجاح!"), "recoveryWarning": MessageLookupByLibrary.simpleMessage( "جهة اتصال موثوقة تحاول الوصول إلى حسابك"), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "لا يمكن التحقق من كلمة المرور على جهازك الحالي، لكن يمكننا تعديلها لتعمل على جميع الأجهزة.\n\nسجّل الدخول باستخدام مفتاح الاسترداد، ثم أنشئ كلمة مرور جديدة (يمكنك اختيار نفس الكلمة السابقة إذا أردت)."), "recreatePasswordTitle": @@ -1571,13 +1584,13 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("1. أعطِ هذا الرمز لأصدقائك"), "referralStep2": MessageLookupByLibrary.simpleMessage("2. يشتركون في خطة مدفوعة"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("الإحالات"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage("الإحالات متوقفة مؤقتًا"), "rejectRecovery": MessageLookupByLibrary.simpleMessage("رفض الاسترداد"), "remindToEmptyDeviceTrash": MessageLookupByLibrary.simpleMessage( - "تذكر أيضًا إفراغ \"المحذوفة مؤخرًا\" من \"الإعدادات\" -> \"التخزين\" لاستعادة المساحة المحررة."), + "تذكر أيضًا إفراغ \"المحذوفة مؤخرًا\" من \"الإعدادات\" -> \"التخزين\" لاستعادة المساحة المحررة"), "remindToEmptyEnteTrash": MessageLookupByLibrary.simpleMessage( "تذكر أيضًا إفراغ \"سلة المهملات\" لاستعادة المساحة المحررة."), "remoteImages": MessageLookupByLibrary.simpleMessage("الصور عن بعد"), @@ -1600,7 +1613,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("إزالة الرابط"), "removeParticipant": MessageLookupByLibrary.simpleMessage("إزالة المشارك"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage("إزالة تسمية الشخص"), "removePublicLink": @@ -1621,7 +1634,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("إعادة تسمية الملف"), "renewSubscription": MessageLookupByLibrary.simpleMessage("تجديد الاشتراك"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("الإبلاغ عن خطأ"), "reportBug": MessageLookupByLibrary.simpleMessage("الإبلاغ عن خطأ"), "resendEmail": MessageLookupByLibrary.simpleMessage( @@ -1647,7 +1660,7 @@ class MessageLookup extends MessageLookupByLibrary { "reviewSuggestions": MessageLookupByLibrary.simpleMessage("مراجعة الاقتراحات"), "right": MessageLookupByLibrary.simpleMessage("يمين"), - "roadtripWithThem": m75, + "roadtripWithThem": m76, "rotate": MessageLookupByLibrary.simpleMessage("تدوير"), "rotateLeft": MessageLookupByLibrary.simpleMessage("تدوير لليسار"), "rotateRight": MessageLookupByLibrary.simpleMessage("تدوير لليمين"), @@ -1661,7 +1674,7 @@ class MessageLookup extends MessageLookupByLibrary { "savePerson": MessageLookupByLibrary.simpleMessage("حفظ الشخص"), "saveYourRecoveryKeyIfYouHaventAlready": MessageLookupByLibrary.simpleMessage( - "احفظ مفتاح الاسترداد إذا لم تكن قد فعلت ذلك بالفعل."), + "احفظ مفتاح الاسترداد إذا لم تكن قد فعلت ذلك"), "saving": MessageLookupByLibrary.simpleMessage("جارٍ الحفظ..."), "savingEdits": MessageLookupByLibrary.simpleMessage("جارٍ حفظ التعديلات..."), @@ -1701,8 +1714,8 @@ class MessageLookup extends MessageLookupByLibrary { "ادعُ الأشخاص، وسترى جميع الصور التي شاركوها هنا."), "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage( "سيتم عرض الأشخاص هنا بمجرد اكتمال المعالجة والمزامنة."), - "searchResultCount": m76, - "searchSectionsLengthMismatch": m77, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("الأمان"), "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage( "رؤية روابط الألبومات العامة في التطبيق"), @@ -1736,6 +1749,7 @@ class MessageLookup extends MessageLookupByLibrary { "selectTime": MessageLookupByLibrary.simpleMessage("تحديد الوقت"), "selectYourFace": MessageLookupByLibrary.simpleMessage("حدد وجهك"), "selectYourPlan": MessageLookupByLibrary.simpleMessage("اختر خطتك"), + "selectedAlbums": m79, "selectedFilesAreNotOnEnte": MessageLookupByLibrary.simpleMessage( "الملفات المحددة ليست موجودة على Ente."), "selectedFoldersWillBeEncryptedAndBackedUp": @@ -1747,9 +1761,9 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeRemovedFromThisPerson": MessageLookupByLibrary.simpleMessage( "سيتم إزالة العناصر المحددة من هذا الشخص، ولكن لن يتم حذفها من مكتبتك."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, - "selfiesWithThem": m80, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, + "selfiesWithThem": m82, "send": MessageLookupByLibrary.simpleMessage("إرسال"), "sendEmail": MessageLookupByLibrary.simpleMessage("إرسال بريد إلكتروني"), @@ -1779,16 +1793,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("شارك ألبومًا الآن"), "shareLink": MessageLookupByLibrary.simpleMessage("مشاركة الرابط"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "شارك فقط مع الأشخاص الذين تريدهم."), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "قم بتنزيل تطبيق Ente حتى نتمكن من مشاركة الصور ومقاطع الفيديو بالجودة الأصلية بسهولة.\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "المشاركة مع غير مستخدمي Ente"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage("شارك ألبومك الأول"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1801,7 +1815,7 @@ class MessageLookup extends MessageLookupByLibrary { "إشعارات الصور المشتركة الجديدة"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "تلقّ إشعارات عندما يضيف شخص ما صورة إلى ألبوم مشترك أنت جزء منه."), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("تمت مشاركتها معي"), "sharedWithYou": @@ -1819,11 +1833,11 @@ class MessageLookup extends MessageLookupByLibrary { "تسجيل الخروج من الأجهزة الأخرى"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "أوافق على شروط الخدمة وسياسة الخصوصية"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "سيتم حذفه من جميع الألبومات."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("تخط"), "social": MessageLookupByLibrary.simpleMessage("التواصل الاجتماعي"), "someItemsAreInBothEnteAndYourDevice": @@ -1854,15 +1868,13 @@ class MessageLookup extends MessageLookupByLibrary { "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "عذرًا، لم نتمكن من إنشاء مفاتيح آمنة على هذا الجهاز.\n\nيرجى التسجيل من جهاز مختلف."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "sort": MessageLookupByLibrary.simpleMessage("فرز"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("فرز حسب"), "sortNewestFirst": MessageLookupByLibrary.simpleMessage("الأحدث أولاً"), "sortOldestFirst": MessageLookupByLibrary.simpleMessage("الأقدم أولاً"), "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ نجاح"), - "sportsWithThem": m89, - "spotlightOnThem": m90, + "sportsWithThem": m91, + "spotlightOnThem": m92, "spotlightOnYourself": MessageLookupByLibrary.simpleMessage("تسليط الضوء عليك"), "startAccountRecoveryTitle": @@ -1876,14 +1888,14 @@ class MessageLookup extends MessageLookupByLibrary { "storage": MessageLookupByLibrary.simpleMessage("التخزين"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("العائلة"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("أنت"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": - MessageLookupByLibrary.simpleMessage("تم تجاوز حد التخزين."), - "storageUsageInfo": m92, + MessageLookupByLibrary.simpleMessage("تم تجاوز حد التخزين"), + "storageUsageInfo": m94, "streamDetails": MessageLookupByLibrary.simpleMessage("تفاصيل البث"), "strongStrength": MessageLookupByLibrary.simpleMessage("قوية"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("اشتراك"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "المشاركة متاحة فقط للاشتراكات المدفوعة النشطة."), @@ -1900,7 +1912,7 @@ class MessageLookup extends MessageLookupByLibrary { "suggestFeatures": MessageLookupByLibrary.simpleMessage("اقتراح ميزة"), "sunrise": MessageLookupByLibrary.simpleMessage("على الأفق"), "support": MessageLookupByLibrary.simpleMessage("الدعم"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("توقفت المزامنة"), "syncing": MessageLookupByLibrary.simpleMessage("جارٍ المزامنة..."), "systemTheme": MessageLookupByLibrary.simpleMessage("النظام"), @@ -1909,7 +1921,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("انقر لإدخال الرمز"), "tapToUnlock": MessageLookupByLibrary.simpleMessage("انقر لفتح القفل"), "tapToUpload": MessageLookupByLibrary.simpleMessage("انقر للتحميل"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "يبدو أن خطأً ما قد حدث. يرجى المحاولة مرة أخرى بعد بعض الوقت. إذا استمر الخطأ، يرجى الاتصال بفريق الدعم لدينا."), "terminate": MessageLookupByLibrary.simpleMessage("إنهاء"), @@ -1922,7 +1934,7 @@ class MessageLookup extends MessageLookupByLibrary { "thankYouForSubscribing": MessageLookupByLibrary.simpleMessage("شكرًا لاشتراكك!"), "theDownloadCouldNotBeCompleted": - MessageLookupByLibrary.simpleMessage("تعذر إكمال التنزيل."), + MessageLookupByLibrary.simpleMessage("تعذر إكمال التنزيل"), "theLinkYouAreTryingToAccessHasExpired": MessageLookupByLibrary.simpleMessage( "انتهت صلاحية الرابط الذي تحاول الوصول إليه."), @@ -1933,7 +1945,7 @@ class MessageLookup extends MessageLookupByLibrary { "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage( "سيتم حذف هذه العناصر من جهازك."), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage( "سيتم حذفها من جميع الألبومات."), "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( @@ -1943,31 +1955,31 @@ class MessageLookup extends MessageLookupByLibrary { "هذا الألبوم لديه رابط تعاوني بالفعل."), "thisCanBeUsedToRecoverYourAccountIfYou": MessageLookupByLibrary.simpleMessage( - "يمكن استخدام هذا المفتاح لاستعادة حسابك إذا فقدت جهاز المصادقة الثنائية."), + "يمكن استخدام هذا المفتاح لاستعادة حسابك إذا فقدت العامل الثاني للمصادقة"), "thisDevice": MessageLookupByLibrary.simpleMessage("هذا الجهاز"), "thisEmailIsAlreadyInUse": MessageLookupByLibrary.simpleMessage( "هذا البريد الإلكتروني مستخدم بالفعل."), "thisImageHasNoExifData": MessageLookupByLibrary.simpleMessage( "لا تحتوي هذه الصورة على بيانات EXIF."), "thisIsMeExclamation": MessageLookupByLibrary.simpleMessage("هذا أنا!"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( "هذا هو معرّف التحقق الخاص بك"), "thisWeekThroughTheYears": MessageLookupByLibrary.simpleMessage("هذا الأسبوع عبر السنين"), - "thisWeekXYearsAgo": m99, + "thisWeekXYearsAgo": m101, "thisWillLogYouOutOfTheFollowingDevice": MessageLookupByLibrary.simpleMessage( "سيؤدي هذا إلى تسجيل خروجك من الجهاز التالي:"), "thisWillLogYouOutOfThisDevice": MessageLookupByLibrary.simpleMessage( - "سيؤدي هذا إلى تسجيل خروجك من هذا الجهاز."), + "سيؤدي هذا إلى تسجيل خروجك من هذا الجهاز!"), "thisWillMakeTheDateAndTimeOfAllSelected": MessageLookupByLibrary.simpleMessage( "سيجعل هذا تاريخ ووقت جميع الصور المحددة متماثلاً."), "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( "سيؤدي هذا إلى إزالة الروابط العامة لجميع الروابط السريعة المحددة."), - "throughTheYears": m100, + "throughTheYears": m102, "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": MessageLookupByLibrary.simpleMessage( "لتمكين قفل التطبيق، يرجى إعداد رمز مرور الجهاز أو قفل الشاشة في إعدادات النظام."), @@ -1981,13 +1993,13 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("المجموع"), "totalSize": MessageLookupByLibrary.simpleMessage("الحجم الإجمالي"), "trash": MessageLookupByLibrary.simpleMessage("سلة المهملات"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("قص"), - "tripInYear": m102, - "tripToLocation": m103, + "tripInYear": m104, + "tripToLocation": m105, "trustedContacts": MessageLookupByLibrary.simpleMessage("جهات الاتصال الموثوقة"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("المحاولة مرة أخرى"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "قم بتشغيل النسخ الاحتياطي لتحميل الملفات المضافة إلى مجلد الجهاز هذا تلقائيًا إلى Ente."), @@ -2004,7 +2016,7 @@ class MessageLookup extends MessageLookupByLibrary { "تمت إعادة تعيين المصادقة الثنائية بنجاح."), "twofactorSetup": MessageLookupByLibrary.simpleMessage("إعداد المصادقة الثنائية"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("إلغاء الأرشفة"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("إلغاء أرشفة الألبوم"), @@ -2028,10 +2040,10 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage("جارٍ تحديث تحديد المجلد..."), "upgrade": MessageLookupByLibrary.simpleMessage("ترقية"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "جارٍ تحميل الملفات إلى الألبوم..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage("جارٍ حفظ ذكرى واحدة..."), "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( @@ -2049,7 +2061,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("استخدام الصورة المحددة"), "usedSpace": MessageLookupByLibrary.simpleMessage("المساحة المستخدمة"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "فشل التحقق، يرجى المحاولة مرة أخرى."), @@ -2057,7 +2069,7 @@ class MessageLookup extends MessageLookupByLibrary { "verify": MessageLookupByLibrary.simpleMessage("التحقق"), "verifyEmail": MessageLookupByLibrary.simpleMessage("التحقق من البريد الإلكتروني"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("تحقق"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("التحقق من مفتاح المرور"), @@ -2082,11 +2094,11 @@ class MessageLookup extends MessageLookupByLibrary { "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( "عرض الملفات التي تستهلك أكبر قدر من مساحة التخزين."), "viewLogs": MessageLookupByLibrary.simpleMessage("عرض السجلات"), - "viewPersonToUnlink": m110, + "viewPersonToUnlink": m112, "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("عرض مفتاح الاسترداد"), "viewer": MessageLookupByLibrary.simpleMessage("مشاهد"), - "viewersSuccessfullyAdded": m111, + "viewersSuccessfullyAdded": m113, "visitWebToManage": MessageLookupByLibrary.simpleMessage( "يرجى زيارة web.ente.io لإدارة اشتراكك."), "waitingForVerification": @@ -2099,15 +2111,16 @@ class MessageLookup extends MessageLookupByLibrary { "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "لا ندعم تعديل الصور والألبومات التي لا تملكها بعد."), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("ضعيفة"), "welcomeBack": MessageLookupByLibrary.simpleMessage("أهلاً بعودتك!"), "whatsNew": MessageLookupByLibrary.simpleMessage("ما الجديد"), "whyAddTrustContact": MessageLookupByLibrary.simpleMessage( "يمكن لجهة الاتصال الموثوقة المساعدة في استعادة بياناتك."), + "wishThemAHappyBirthday": m115, "yearShort": MessageLookupByLibrary.simpleMessage("سنة"), "yearly": MessageLookupByLibrary.simpleMessage("سنويًا"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("نعم"), "yesCancel": MessageLookupByLibrary.simpleMessage("نعم، إلغاء"), "yesConvertToViewer": @@ -2121,7 +2134,7 @@ class MessageLookup extends MessageLookupByLibrary { "yesResetPerson": MessageLookupByLibrary.simpleMessage("نعم، إعادة تعيين الشخص"), "you": MessageLookupByLibrary.simpleMessage("أنت"), - "youAndThem": m114, + "youAndThem": m117, "youAreOnAFamilyPlan": MessageLookupByLibrary.simpleMessage("أنت مشترك في خطة عائلية!"), "youAreOnTheLatestVersion": @@ -2140,7 +2153,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("لا يمكنك المشاركة مع نفسك."), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( "لا توجد لديك أي عناصر مؤرشفة."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("تم حذف حسابك بنجاح"), "yourMap": MessageLookupByLibrary.simpleMessage("خريطتك"), @@ -2154,14 +2167,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "تعذر جلب تفاصيل التخزين الخاصة بك."), "yourSubscriptionHasExpired": - MessageLookupByLibrary.simpleMessage("انتهت صلاحية اشتراكك."), + MessageLookupByLibrary.simpleMessage("انتهت صلاحية اشتراكك"), "yourSubscriptionWasUpdatedSuccessfully": MessageLookupByLibrary.simpleMessage("تم تحديث اشتراكك بنجاح."), "yourVerificationCodeHasExpired": MessageLookupByLibrary.simpleMessage( "انتهت صلاحية رمز التحقق الخاص بك."), "youveNoDuplicateFilesThatCanBeCleared": MessageLookupByLibrary.simpleMessage( - "لا توجد لديك أي ملفات مكررة يمكن مسحها."), + "لا توجد لديك أي ملفات مكررة يمكن مسحها"), "youveNoFilesInThisAlbumThatCanBeDeleted": MessageLookupByLibrary.simpleMessage( "لا توجد لديك ملفات في هذا الألبوم يمكن حذفها."), diff --git a/mobile/lib/generated/intl/messages_be.dart b/mobile/lib/generated/intl/messages_be.dart index 92cc493598..5e13c17451 100644 --- a/mobile/lib/generated/intl/messages_be.dart +++ b/mobile/lib/generated/intl/messages_be.dart @@ -20,14 +20,16 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'be'; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Надзейнасць пароля: ${passwordStrengthValue}"; - static String m91(storageAmountInGB) => "${storageAmountInGB} Гб"; + static String m93(storageAmountInGB) => "${storageAmountInGB} Гб"; - static String m112(email) => + static String m114(email) => "Ліст адпраўлены на электронную пошту ${email}"; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { "about": MessageLookupByLibrary.simpleMessage("Пра праграму"), @@ -57,8 +59,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Змяніць пароль"), "checkInboxAndSpamFolder": MessageLookupByLibrary.simpleMessage( "Праверце свае ўваходныя лісты (і спам) для завяршэння праверкі"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "codeAppliedPageTitle": MessageLookupByLibrary.simpleMessage("Код ужыты"), "confirm": MessageLookupByLibrary.simpleMessage("Пацвердзіць"), @@ -113,6 +113,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Зрабіць гэта пазней"), "done": MessageLookupByLibrary.simpleMessage("Гатова"), "email": MessageLookupByLibrary.simpleMessage("Электронная пошта"), + "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage( + "Электронная пошта ўжо зарэгістравана."), "encryption": MessageLookupByLibrary.simpleMessage("Шыфраванне"), "encryptionKeys": MessageLookupByLibrary.simpleMessage("Ключы шыфравання"), @@ -127,6 +129,8 @@ class MessageLookup extends MessageLookupByLibrary { "Увядзіце сапраўдны адрас электронная пошты."), "enterYourEmailAddress": MessageLookupByLibrary.simpleMessage( "Увядзіце свой адрас электроннай пошты"), + "enterYourNewEmailAddress": MessageLookupByLibrary.simpleMessage( + "Увядзіце ваш новы адрас электроннай пошты"), "enterYourPassword": MessageLookupByLibrary.simpleMessage("Увядзіце свой пароль"), "enterYourRecoveryKey": MessageLookupByLibrary.simpleMessage( @@ -169,15 +173,12 @@ class MessageLookup extends MessageLookupByLibrary { "loginTerms": MessageLookupByLibrary.simpleMessage( "Націскаючы ўвайсці, я пагаджаюся з умовамі абслугоўвання і палітыкай прыватнасці"), "logout": MessageLookupByLibrary.simpleMessage("Выйсці"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "lostDevice": MessageLookupByLibrary.simpleMessage("Згубілі прыладу?"), "magicSearch": MessageLookupByLibrary.simpleMessage("Магічны пошук"), "manage": MessageLookupByLibrary.simpleMessage("Кіраванне"), "manageParticipants": MessageLookupByLibrary.simpleMessage("Кіраванне"), "moderateStrength": MessageLookupByLibrary.simpleMessage("Умераны"), "never": MessageLookupByLibrary.simpleMessage("Ніколі"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "noDuplicates": MessageLookupByLibrary.simpleMessage("✨ Няма дублікатаў"), "noRecoveryKey": @@ -186,16 +187,13 @@ class MessageLookup extends MessageLookupByLibrary { "Вашы даныя не могуць быць расшыфраваны без пароля або ключа аднаўлення па прычыне архітэктуры наша пратакола скразнога шыфравання"), "notifications": MessageLookupByLibrary.simpleMessage("Апавяшчэнні"), "ok": MessageLookupByLibrary.simpleMessage("Добра"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), "oops": MessageLookupByLibrary.simpleMessage("Вой"), "oopsSomethingWentWrong": MessageLookupByLibrary.simpleMessage("Штосьці пайшло не так"), "password": MessageLookupByLibrary.simpleMessage("Пароль"), "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage("Пароль паспяхова зменены"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordWarning": MessageLookupByLibrary.simpleMessage( "Мы не захоўваем гэты пароль і мы не зможам расшыфраваць вашы даныя, калі вы забудзеце яго"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("фота"), @@ -256,10 +254,8 @@ class MessageLookup extends MessageLookupByLibrary { "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "Немагчыма згенерыраваць ключы бяспекі на гэтай прыладзе.\n\nЗарэгіструйцеся з іншай прылады."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "status": MessageLookupByLibrary.simpleMessage("Стан"), - "storageInGB": m91, + "storageInGB": m93, "strongStrength": MessageLookupByLibrary.simpleMessage("Надзейны"), "support": MessageLookupByLibrary.simpleMessage("Падтрымка"), "systemTheme": MessageLookupByLibrary.simpleMessage("Сістэма"), @@ -298,9 +294,10 @@ class MessageLookup extends MessageLookupByLibrary { "videoSmallCase": MessageLookupByLibrary.simpleMessage("відэа"), "viewLargeFiles": MessageLookupByLibrary.simpleMessage("Вялікія файлы"), "viewer": MessageLookupByLibrary.simpleMessage("Праглядальнік"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Ненадзейны"), "welcomeBack": MessageLookupByLibrary.simpleMessage("З вяртаннем!"), + "wishThemAHappyBirthday": m115, "yesDelete": MessageLookupByLibrary.simpleMessage("Так, выдаліць"), "yesLogout": MessageLookupByLibrary.simpleMessage("Так, выйсці"), "yesRemove": MessageLookupByLibrary.simpleMessage("Так, выдаліць"), diff --git a/mobile/lib/generated/intl/messages_bg.dart b/mobile/lib/generated/intl/messages_bg.dart index 38b09f89ec..9228905e66 100644 --- a/mobile/lib/generated/intl/messages_bg.dart +++ b/mobile/lib/generated/intl/messages_bg.dart @@ -20,17 +20,9 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'bg'; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => { - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups") - }; + static Map _notInlinedMessages(_) => + {"wishThemAHappyBirthday": m115}; } diff --git a/mobile/lib/generated/intl/messages_ca.dart b/mobile/lib/generated/intl/messages_ca.dart index 13a0bb611c..c826f94abe 100644 --- a/mobile/lib/generated/intl/messages_ca.dart +++ b/mobile/lib/generated/intl/messages_ca.dart @@ -20,17 +20,9 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'ca'; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => { - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups") - }; + static Map _notInlinedMessages(_) => + {"wishThemAHappyBirthday": m115}; } diff --git a/mobile/lib/generated/intl/messages_cs.dart b/mobile/lib/generated/intl/messages_cs.dart index a92944c0fb..911cb93921 100644 --- a/mobile/lib/generated/intl/messages_cs.dart +++ b/mobile/lib/generated/intl/messages_cs.dart @@ -22,17 +22,19 @@ class MessageLookup extends MessageLookupByLibrary { static String m6(albumName) => "Úspěšně přidáno do ${albumName}"; - static String m46(expiryTime) => "Platnost odkazu vyprší ${expiryTime}"; + static String m47(expiryTime) => "Platnost odkazu vyprší ${expiryTime}"; - static String m67(storeName) => "Ohodnoťte nás na ${storeName}"; + static String m68(storeName) => "Ohodnoťte nás na ${storeName}"; - static String m74(endDate) => "Předplatné se obnoví ${endDate}"; + static String m75(endDate) => "Předplatné se obnoví ${endDate}"; - static String m80(name) => "Selfie s ${name}"; + static String m82(name) => "Selfie s ${name}"; - static String m109(email) => "Ověřit ${email}"; + static String m111(email) => "Ověřit ${email}"; - static String m114(name) => "Vy a ${name}"; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + + static String m117(name) => "Vy a ${name}"; final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { @@ -78,6 +80,10 @@ class MessageLookup extends MessageLookupByLibrary { "archiveAlbum": MessageLookupByLibrary.simpleMessage("Archivovat album"), "archiving": MessageLookupByLibrary.simpleMessage("Archivování..."), + "areThey": MessageLookupByLibrary.simpleMessage("Are they "), + "areYouSureRemoveThisFaceFromPerson": + MessageLookupByLibrary.simpleMessage( + "Are you sure you want to remove this face from this person?"), "areYouSureYouWantToLogout": MessageLookupByLibrary.simpleMessage("Opravdu se chcete odhlásit?"), "askDeleteReason": MessageLookupByLibrary.simpleMessage( @@ -112,8 +118,6 @@ class MessageLookup extends MessageLookupByLibrary { "clearCaches": MessageLookupByLibrary.simpleMessage("Vymazat mezipaměť"), "clearIndexes": MessageLookupByLibrary.simpleMessage("Smazat indexy"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "close": MessageLookupByLibrary.simpleMessage("Zavřít"), "codeAppliedPageTitle": MessageLookupByLibrary.simpleMessage("Kód byl použit"), @@ -291,7 +295,7 @@ class MessageLookup extends MessageLookupByLibrary { "leaveAlbum": MessageLookupByLibrary.simpleMessage("Opustit album"), "left": MessageLookupByLibrary.simpleMessage("Doleva"), "lightTheme": MessageLookupByLibrary.simpleMessage("Světlý"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkHasExpired": MessageLookupByLibrary.simpleMessage("Platnost odkazu vypršela"), "linkNeverExpires": MessageLookupByLibrary.simpleMessage("Nikdy"), @@ -307,8 +311,6 @@ class MessageLookup extends MessageLookupByLibrary { "loginWithTOTP": MessageLookupByLibrary.simpleMessage("Přihlášení pomocí TOTP"), "logout": MessageLookupByLibrary.simpleMessage("Odhlásit se"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "lostDevice": MessageLookupByLibrary.simpleMessage("Ztratili jste zařízení?"), "manage": MessageLookupByLibrary.simpleMessage("Spravovat"), @@ -334,7 +336,6 @@ class MessageLookup extends MessageLookupByLibrary { "never": MessageLookupByLibrary.simpleMessage("Nikdy"), "newAlbum": MessageLookupByLibrary.simpleMessage("Nové album"), "newPerson": MessageLookupByLibrary.simpleMessage("Nová osoba"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "newRange": MessageLookupByLibrary.simpleMessage("Nový rozsah"), "newest": MessageLookupByLibrary.simpleMessage("Nejnovější"), "next": MessageLookupByLibrary.simpleMessage("Další"), @@ -356,9 +357,6 @@ class MessageLookup extends MessageLookupByLibrary { "onDevice": MessageLookupByLibrary.simpleMessage("V zařízení"), "onEnte": MessageLookupByLibrary.simpleMessage( "Na ente"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), "oops": MessageLookupByLibrary.simpleMessage("Jejda"), "oopsSomethingWentWrong": MessageLookupByLibrary.simpleMessage("Jejda, něco se pokazilo"), @@ -367,6 +365,8 @@ class MessageLookup extends MessageLookupByLibrary { "openFile": MessageLookupByLibrary.simpleMessage("Otevřít soubor"), "openSettings": MessageLookupByLibrary.simpleMessage("Otevřít Nastavení"), + "otherDetectedFaces": + MessageLookupByLibrary.simpleMessage("Other detected faces"), "pair": MessageLookupByLibrary.simpleMessage("Spárovat"), "panorama": MessageLookupByLibrary.simpleMessage("Panorama"), "password": MessageLookupByLibrary.simpleMessage("Heslo"), @@ -390,10 +390,11 @@ class MessageLookup extends MessageLookupByLibrary { "processing": MessageLookupByLibrary.simpleMessage("Zpracovává se"), "publicLinkCreated": MessageLookupByLibrary.simpleMessage("Veřejný odkaz vytvořen"), + "questionmark": MessageLookupByLibrary.simpleMessage("?"), "queued": MessageLookupByLibrary.simpleMessage("Ve frontě"), "radius": MessageLookupByLibrary.simpleMessage("Rádius"), "rateUs": MessageLookupByLibrary.simpleMessage("Ohodnoť nás"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "recoverButton": MessageLookupByLibrary.simpleMessage("Obnovit"), "recoveryKeyVerified": MessageLookupByLibrary.simpleMessage("Obnovovací klíč byl ověřen"), @@ -422,7 +423,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Přejmenovat album"), "renameFile": MessageLookupByLibrary.simpleMessage("Přejmenovat soubor"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Nahlásit chybu"), "reportBug": MessageLookupByLibrary.simpleMessage("Nahlásit chybu"), "resendEmail": @@ -441,6 +442,8 @@ class MessageLookup extends MessageLookupByLibrary { "safelyStored": MessageLookupByLibrary.simpleMessage("Bezpečně uloženo"), "save": MessageLookupByLibrary.simpleMessage("Uložit"), + "saveAsAnotherPerson": + MessageLookupByLibrary.simpleMessage("Save as another person"), "saveCopy": MessageLookupByLibrary.simpleMessage("Uložit kopii"), "saveKey": MessageLookupByLibrary.simpleMessage("Uložit klíč"), "savePerson": MessageLookupByLibrary.simpleMessage("Uložit osobu"), @@ -464,7 +467,7 @@ class MessageLookup extends MessageLookupByLibrary { "selectTime": MessageLookupByLibrary.simpleMessage("Vybrat čas"), "selectYourPlan": MessageLookupByLibrary.simpleMessage("Vyberte svůj plán"), - "selfiesWithThem": m80, + "selfiesWithThem": m82, "send": MessageLookupByLibrary.simpleMessage("Odeslat"), "sendEmail": MessageLookupByLibrary.simpleMessage("Odeslat e-mail"), "sendInvite": MessageLookupByLibrary.simpleMessage("Odeslat pozvánku"), @@ -483,10 +486,12 @@ class MessageLookup extends MessageLookupByLibrary { "sharedWithMe": MessageLookupByLibrary.simpleMessage("Sdíleno se mnou"), "sharedWithYou": MessageLookupByLibrary.simpleMessage("Sdíleno s vámi"), "sharing": MessageLookupByLibrary.simpleMessage("Sdílení..."), + "showLessFaces": + MessageLookupByLibrary.simpleMessage("Show less faces"), + "showMoreFaces": + MessageLookupByLibrary.simpleMessage("Show more faces"), "skip": MessageLookupByLibrary.simpleMessage("Přeskočit"), "sorry": MessageLookupByLibrary.simpleMessage("Omlouváme se"), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "sort": MessageLookupByLibrary.simpleMessage("Seřadit"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Seřadit podle"), "sortNewestFirst": @@ -534,7 +539,7 @@ class MessageLookup extends MessageLookupByLibrary { "usedSpace": MessageLookupByLibrary.simpleMessage("Využité místo"), "verify": MessageLookupByLibrary.simpleMessage("Ověřit"), "verifyEmail": MessageLookupByLibrary.simpleMessage("Ověřit e-mail"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Ověřit"), "verifying": MessageLookupByLibrary.simpleMessage("Ověřování..."), "verifyingRecoveryKey": MessageLookupByLibrary.simpleMessage( @@ -548,6 +553,7 @@ class MessageLookup extends MessageLookupByLibrary { "weakStrength": MessageLookupByLibrary.simpleMessage("Slabé"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Vítejte zpět!"), "whatsNew": MessageLookupByLibrary.simpleMessage("Co je nového"), + "wishThemAHappyBirthday": m115, "yearly": MessageLookupByLibrary.simpleMessage("Ročně"), "yes": MessageLookupByLibrary.simpleMessage("Ano"), "yesCancel": MessageLookupByLibrary.simpleMessage("Ano, zrušit"), @@ -558,7 +564,7 @@ class MessageLookup extends MessageLookupByLibrary { "yesRemove": MessageLookupByLibrary.simpleMessage("Ano, odstranit"), "yesRenew": MessageLookupByLibrary.simpleMessage("Ano, obnovit"), "you": MessageLookupByLibrary.simpleMessage("Vy"), - "youAndThem": m114, + "youAndThem": m117, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("Váš účet byl smazán"), "yourMap": MessageLookupByLibrary.simpleMessage("Vaše mapa") diff --git a/mobile/lib/generated/intl/messages_da.dart b/mobile/lib/generated/intl/messages_da.dart index 7c27a0f1d5..aff66588e6 100644 --- a/mobile/lib/generated/intl/messages_da.dart +++ b/mobile/lib/generated/intl/messages_da.dart @@ -26,29 +26,31 @@ class MessageLookup extends MessageLookupByLibrary { static String m13(user) => "${user} vil ikke kunne tilføje flere billeder til dette album\n\nDe vil stadig kunne fjerne eksisterende billeder tilføjet af dem"; - static String m24(supportEmail) => + static String m25(supportEmail) => "Send venligst en email til ${supportEmail} fra din registrerede email adresse"; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "${storageAmountInGB} GB hver gang nogen tilmelder sig et betalt abonnement og anvender din kode"; - static String m46(expiryTime) => "Link udløber den ${expiryTime}"; + static String m47(expiryTime) => "Link udløber den ${expiryTime}"; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Kodeordets styrke: ${passwordStrengthValue}"; - static String m78(count) => "${count} valgt"; + static String m80(count) => "${count} valgt"; - static String m82(verificationID) => + static String m84(verificationID) => "Hey, kan du bekræfte, at dette er dit ente.io verifikation ID: ${verificationID}"; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; - static String m97(storageAmountInGB) => "De får også ${storageAmountInGB} GB"; + static String m99(storageAmountInGB) => "De får også ${storageAmountInGB} GB"; - static String m112(email) => + static String m114(email) => "Vi har sendt en email til ${email}"; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { "accountWelcomeBack": @@ -107,8 +109,6 @@ class MessageLookup extends MessageLookupByLibrary { "checkInboxAndSpamFolder": MessageLookupByLibrary.simpleMessage( "Tjek venligst din indbakke (og spam) for at færdiggøre verificeringen"), "clearIndexes": MessageLookupByLibrary.simpleMessage("Ryd indekser"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "codeCopiedToClipboard": MessageLookupByLibrary.simpleMessage( "Kode kopieret til udklipsholder"), "collabLinkSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -181,7 +181,7 @@ class MessageLookup extends MessageLookupByLibrary { "discover_wallpapers": MessageLookupByLibrary.simpleMessage("Baggrundsbilleder"), "doThisLater": MessageLookupByLibrary.simpleMessage("Gør det senere"), - "dropSupportEmail": m24, + "dropSupportEmail": m25, "eligible": MessageLookupByLibrary.simpleMessage("kvalificeret"), "email": MessageLookupByLibrary.simpleMessage("Email"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage( @@ -221,7 +221,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Find folk hurtigt ved navn"), "forgotPassword": MessageLookupByLibrary.simpleMessage("Glemt adgangskode"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("Frigør enhedsplads"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( @@ -255,7 +255,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Enheds grænse"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Aktiveret"), "linkExpired": MessageLookupByLibrary.simpleMessage("Udløbet"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Udløb af link"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("Linket er udløbet"), @@ -270,8 +270,6 @@ class MessageLookup extends MessageLookupByLibrary { "longPressAnEmailToVerifyEndToEndEncryption": MessageLookupByLibrary.simpleMessage( "Langt tryk på en e-mail for at bekræfte slutningen af krypteringen."), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "lostDevice": MessageLookupByLibrary.simpleMessage("Har du mistet enhed?"), "machineLearning": MessageLookupByLibrary.simpleMessage("Maskinlæring"), @@ -293,15 +291,11 @@ class MessageLookup extends MessageLookupByLibrary { "moments": MessageLookupByLibrary.simpleMessage("Øjeblikke"), "never": MessageLookupByLibrary.simpleMessage("Aldrig"), "newAlbum": MessageLookupByLibrary.simpleMessage("Nyt album"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "next": MessageLookupByLibrary.simpleMessage("Næste"), "noDeviceLimit": MessageLookupByLibrary.simpleMessage("Ingen"), "noRecoveryKey": MessageLookupByLibrary.simpleMessage("Ingen gendannelsesnøgle?"), "ok": MessageLookupByLibrary.simpleMessage("Ok"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), "oops": MessageLookupByLibrary.simpleMessage("Ups"), "oopsSomethingWentWrong": MessageLookupByLibrary.simpleMessage("Ups, noget gik galt"), @@ -311,7 +305,7 @@ class MessageLookup extends MessageLookupByLibrary { "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage( "Adgangskoden er blevet ændret"), "passwordLock": MessageLookupByLibrary.simpleMessage("Adgangskodelås"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordWarning": MessageLookupByLibrary.simpleMessage( "Vi gemmer ikke denne adgangskode, så hvis du glemmer den kan vi ikke dekryptere dine data"), "pendingItems": @@ -383,7 +377,7 @@ class MessageLookup extends MessageLookupByLibrary { "selectedFoldersWillBeEncryptedAndBackedUp": MessageLookupByLibrary.simpleMessage( "Valgte mapper vil blive krypteret og sikkerhedskopieret"), - "selectedPhotos": m78, + "selectedPhotos": m80, "sendEmail": MessageLookupByLibrary.simpleMessage("Send email"), "sendLink": MessageLookupByLibrary.simpleMessage("Send link"), "setPasswordTitle": @@ -391,7 +385,7 @@ class MessageLookup extends MessageLookupByLibrary { "setupComplete": MessageLookupByLibrary.simpleMessage("Opsætning fuldført"), "shareALink": MessageLookupByLibrary.simpleMessage("Del et link"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage("Del med ikke Ente brugere"), "showMemories": MessageLookupByLibrary.simpleMessage("Vis minder"), @@ -410,10 +404,8 @@ class MessageLookup extends MessageLookupByLibrary { "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "Beklager, vi kunne ikke generere sikre krypteringsnøgler på denne enhed.\n\nForsøg venligst at oprette en konto fra en anden enhed."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "status": MessageLookupByLibrary.simpleMessage("Status"), - "storageInGB": m91, + "storageInGB": m93, "strongStrength": MessageLookupByLibrary.simpleMessage("Stærkt"), "subscribe": MessageLookupByLibrary.simpleMessage("Abonner"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( @@ -427,7 +419,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Afslut session?"), "termsOfServicesTitle": MessageLookupByLibrary.simpleMessage("Betingelser"), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "thisCanBeUsedToRecoverYourAccountIfYou": MessageLookupByLibrary.simpleMessage( "Dette kan bruges til at gendanne din konto, hvis du mister din anden faktor"), @@ -466,10 +458,11 @@ class MessageLookup extends MessageLookupByLibrary { "viewer": MessageLookupByLibrary.simpleMessage("Seer"), "waitingForWifi": MessageLookupByLibrary.simpleMessage("Venter på Wi-fi..."), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Svagt"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Velkommen tilbage!"), + "wishThemAHappyBirthday": m115, "yesConvertToViewer": MessageLookupByLibrary.simpleMessage( "Ja, konverter til præsentation"), "yesRemove": MessageLookupByLibrary.simpleMessage("Ja, fjern"), diff --git a/mobile/lib/generated/intl/messages_de.dart b/mobile/lib/generated/intl/messages_de.dart index fea2e68920..774c8b5e77 100644 --- a/mobile/lib/generated/intl/messages_de.dart +++ b/mobile/lib/generated/intl/messages_de.dart @@ -84,244 +84,251 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'Lösche ${count} Element', other: 'Lösche ${count} Elemente')}"; - static String m22(currentlyDeleting, totalCount) => + static String m22(count) => + "Sollen die Fotos (und Videos) aus diesen ${count} Alben auch aus allen anderen Alben gelöscht werden, in denen sie enthalten sind?"; + + static String m23(currentlyDeleting, totalCount) => "Lösche ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "Der öffentliche Link zum Zugriff auf \"${albumName}\" wird entfernt."; - static String m24(supportEmail) => + static String m25(supportEmail) => "Bitte sende eine E-Mail an ${supportEmail} von deiner registrierten E-Mail-Adresse"; - static String m25(count, storageSaved) => + static String m26(count, storageSaved) => "Du hast ${Intl.plural(count, one: '${count} duplizierte Datei', other: '${count} dupliziere Dateien')} gelöscht und (${storageSaved}!) freigegeben"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} Dateien, ${formattedSize} jede"; - static String m27(name) => "Diese E-Mail ist bereits verknüpft mit ${name}."; + static String m28(name) => "Diese E-Mail ist bereits verknüpft mit ${name}."; - static String m28(newEmail) => "E-Mail-Adresse geändert zu ${newEmail}"; + static String m29(newEmail) => "E-Mail-Adresse geändert zu ${newEmail}"; - static String m29(email) => "${email} hat kein Ente-Konto."; + static String m30(email) => "${email} hat kein Ente-Konto."; - static String m30(email) => + static String m31(email) => "${email} hat kein Ente-Konto.\n\nSende eine Einladung, um Fotos zu teilen."; - static String m31(name) => "${name} umarmen"; + static String m32(name) => "${name} umarmen"; - static String m32(text) => "Zusätzliche Fotos für ${text} gefunden"; + static String m33(text) => "Zusätzliche Fotos für ${text} gefunden"; - static String m33(name) => "Feiern mit ${name}"; - - static String m34(count, formattedNumber) => - "${Intl.plural(count, one: '1 Datei', other: '${formattedNumber} Dateien')} auf diesem Gerät wurde(n) sicher gespeichert"; + static String m34(name) => "Feiern mit ${name}"; static String m35(count, formattedNumber) => + "${Intl.plural(count, one: '1 Datei', other: '${formattedNumber} Dateien')} auf diesem Gerät wurde(n) sicher gespeichert"; + + static String m36(count, formattedNumber) => "${Intl.plural(count, one: '1 Datei', other: '${formattedNumber} Dateien')} in diesem Album wurde(n) sicher gespeichert"; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "${storageAmountInGB} GB jedes Mal, wenn sich jemand mit deinem Code für einen bezahlten Tarif anmeldet"; - static String m37(endDate) => "Kostenlose Demo verfügbar bis zum ${endDate}"; + static String m38(endDate) => "Kostenlose Demo verfügbar bis zum ${endDate}"; - static String m38(count) => + static String m39(count) => "Du hast ${Intl.plural(count, one: 'darauf', other: 'auf sie')} weiterhin Zugriff, solange du ein aktives Abo hast"; - static String m39(sizeInMBorGB) => "${sizeInMBorGB} freigeben"; + static String m40(sizeInMBorGB) => "${sizeInMBorGB} freigeben"; - static String m40(count, formattedSize) => + static String m41(count, formattedSize) => "${Intl.plural(count, one: 'Es kann vom Gerät gelöscht werden, um ${formattedSize} freizugeben', other: 'Sie können vom Gerät gelöscht werden, um ${formattedSize} freizugeben')}"; - static String m41(currentlyProcessing, totalCount) => + static String m42(currentlyProcessing, totalCount) => "Verarbeite ${currentlyProcessing} / ${totalCount}"; - static String m42(name) => "Wandern mit ${name}"; + static String m43(name) => "Wandern mit ${name}"; - static String m43(count) => + static String m44(count) => "${Intl.plural(count, one: '${count} Objekt', other: '${count} Objekte')}"; - static String m44(name) => "Zuletzt mit ${name}"; + static String m45(name) => "Zuletzt mit ${name}"; - static String m45(email) => + static String m46(email) => "${email} hat dich eingeladen, ein vertrauenswürdiger Kontakt zu werden"; - static String m46(expiryTime) => "Link läuft am ${expiryTime} ab"; + static String m47(expiryTime) => "Link läuft am ${expiryTime} ab"; - static String m47(email) => "Person mit ${email} verknüpfen"; + static String m48(email) => "Person mit ${email} verknüpfen"; - static String m48(personName, email) => + static String m49(personName, email) => "Dies wird ${personName} mit ${email} verknüpfen"; - static String m49(count, formattedCount) => + static String m50(count, formattedCount) => "${Intl.plural(count, zero: 'keine Erinnerungen', one: '${formattedCount} Erinnerung', other: '${formattedCount} Erinnerungen')}"; - static String m50(count) => + static String m51(count) => "${Intl.plural(count, one: 'Element verschieben', other: 'Elemente verschieben')}"; - static String m51(albumName) => "Erfolgreich zu ${albumName} hinzugefügt"; + static String m52(albumName) => "Erfolgreich zu ${albumName} hinzugefügt"; - static String m52(personName) => "Keine Vorschläge für ${personName}"; + static String m53(personName) => "Keine Vorschläge für ${personName}"; - static String m53(name) => "Nicht ${name}?"; + static String m54(name) => "Nicht ${name}?"; - static String m54(familyAdminEmail) => + static String m55(familyAdminEmail) => "Bitte wende Dich an ${familyAdminEmail}, um den Code zu ändern."; - static String m55(name) => "Party mit ${name}"; + static String m56(name) => "Party mit ${name}"; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Passwortstärke: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "Bitte kontaktiere den Support von ${providerName}, falls etwas abgebucht wurde"; - static String m58(name, age) => "${name} ist ${age}!"; + static String m59(name, age) => "${name} ist ${age}!"; - static String m59(name, age) => "${name} wird bald ${age}"; - - static String m60(count) => - "${Intl.plural(count, zero: 'Keine Fotos', one: 'Ein Foto', other: '${count} Fotos')}"; + static String m60(name, age) => "${name} wird bald ${age}"; static String m61(count) => + "${Intl.plural(count, zero: 'Keine Fotos', one: 'Ein Foto', other: '${count} Fotos')}"; + + static String m62(count) => "${Intl.plural(count, zero: '0 Fotos', one: 'Ein Foto', other: '${count} Fotos')}"; - static String m62(endDate) => + static String m63(endDate) => "Kostenlose Testversion gültig bis ${endDate}.\nDu kannst anschließend ein bezahltes Paket auswählen."; - static String m63(toEmail) => "Bitte sende uns eine E-Mail an ${toEmail}"; + static String m64(toEmail) => "Bitte sende uns eine E-Mail an ${toEmail}"; - static String m64(toEmail) => "Bitte sende die Protokolle an ${toEmail}"; + static String m65(toEmail) => "Bitte sende die Protokolle an ${toEmail}"; - static String m65(name) => "Posieren mit ${name}"; + static String m66(name) => "Posieren mit ${name}"; - static String m66(folderName) => "Verarbeite ${folderName}..."; + static String m67(folderName) => "Verarbeite ${folderName}..."; - static String m67(storeName) => "Bewerte uns auf ${storeName}"; + static String m68(storeName) => "Bewerte uns auf ${storeName}"; - static String m68(name) => "Du wurdest an ${name} neu zugewiesen"; + static String m69(name) => "Du wurdest an ${name} neu zugewiesen"; - static String m69(days, email) => + static String m70(days, email) => "Du kannst nach ${days} Tagen auf das Konto zugreifen. Eine Benachrichtigung wird an ${email} versendet."; - static String m70(email) => + static String m71(email) => "Du kannst jetzt das Konto von ${email} wiederherstellen, indem du ein neues Passwort setzt."; - static String m71(email) => + static String m72(email) => "${email} versucht, dein Konto wiederherzustellen."; - static String m72(storageInGB) => + static String m73(storageInGB) => "3. Ihr beide erhaltet ${storageInGB} GB* kostenlos"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} wird aus diesem geteilten Album entfernt\n\nAlle von ihnen hinzugefügte Fotos werden ebenfalls aus dem Album entfernt"; - static String m74(endDate) => "Erneuert am ${endDate}"; + static String m75(endDate) => "Erneuert am ${endDate}"; - static String m75(name) => "Roadtrip mit ${name}"; + static String m76(name) => "Roadtrip mit ${name}"; - static String m76(count) => + static String m77(count) => "${Intl.plural(count, one: '${count} Ergebnis gefunden', other: '${count} Ergebnisse gefunden')}"; - static String m77(snapshotLength, searchLength) => + static String m78(snapshotLength, searchLength) => "Abschnittslänge stimmt nicht überein: ${snapshotLength} != ${searchLength}"; - static String m78(count) => "${count} ausgewählt"; + static String m79(count) => "${count} ausgewählt"; - static String m79(count, yourCount) => + static String m80(count) => "${count} ausgewählt"; + + static String m81(count, yourCount) => "${count} ausgewählt (${yourCount} von Ihnen)"; - static String m80(name) => "Selfies mit ${name}"; + static String m82(name) => "Selfies mit ${name}"; - static String m81(verificationID) => + static String m83(verificationID) => "Hier ist meine Verifizierungs-ID: ${verificationID} für ente.io."; - static String m82(verificationID) => + static String m84(verificationID) => "Hey, kannst du bestätigen, dass dies deine ente.io Verifizierungs-ID ist: ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Ente Weiterempfehlungs-Code: ${referralCode} \n\nEinlösen unter Einstellungen → Allgemein → Weiterempfehlungen, um ${referralStorageInGB} GB kostenlos zu erhalten, sobald Sie einen kostenpflichtigen Tarif abgeschlossen haben\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Teile mit bestimmten Personen', one: 'Teilen mit 1 Person', other: 'Teilen mit ${numberOfPeople} Personen')}"; - static String m85(emailIDs) => "Geteilt mit ${emailIDs}"; + static String m87(emailIDs) => "Geteilt mit ${emailIDs}"; - static String m86(fileType) => + static String m88(fileType) => "Dieses ${fileType} wird von deinem Gerät gelöscht."; - static String m87(fileType) => + static String m89(fileType) => "Diese Datei ist sowohl in Ente als auch auf deinem Gerät."; - static String m88(fileType) => "Diese Datei wird von Ente gelöscht."; + static String m90(fileType) => "Diese Datei wird von Ente gelöscht."; - static String m89(name) => "Sport mit ${name}"; + static String m91(name) => "Sport mit ${name}"; - static String m90(name) => "Spot auf ${name}"; + static String m92(name) => "Spot auf ${name}"; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} von ${totalAmount} ${totalStorageUnit} verwendet"; - static String m93(id) => + static String m95(id) => "Dein ${id} ist bereits mit einem anderen Ente-Konto verknüpft.\nWenn du deine ${id} mit diesem Konto verwenden möchtest, kontaktiere bitte unseren Support"; - static String m94(endDate) => "Dein Abo endet am ${endDate}"; + static String m96(endDate) => "Dein Abo endet am ${endDate}"; - static String m95(completed, total) => + static String m97(completed, total) => "${completed}/${total} Erinnerungsstücke gesichert"; - static String m96(ignoreReason) => + static String m98(ignoreReason) => "Zum Hochladen tippen, Hochladen wird derzeit ignoriert, da ${ignoreReason}"; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "Diese erhalten auch ${storageAmountInGB} GB"; - static String m98(email) => "Dies ist ${email}s Verifizierungs-ID"; - - static String m99(count) => - "${Intl.plural(count, one: 'Diese Woche, vor einem Jahr', other: 'Diese Woche, vor ${count} Jahren')}"; - - static String m100(dateFormat) => "${dateFormat} über die Jahre"; + static String m100(email) => "Dies ist ${email}s Verifizierungs-ID"; static String m101(count) => + "${Intl.plural(count, one: 'Diese Woche, vor einem Jahr', other: 'Diese Woche, vor ${count} Jahren')}"; + + static String m102(dateFormat) => "${dateFormat} über die Jahre"; + + static String m103(count) => "${Intl.plural(count, zero: 'Demnächst', one: '1 Tag', other: '${count} Tage')}"; - static String m102(year) => "Reise in ${year}"; + static String m104(year) => "Reise in ${year}"; - static String m103(location) => "Ausflug nach ${location}"; + static String m105(location) => "Ausflug nach ${location}"; - static String m104(email) => + static String m106(email) => "Du wurdest von ${email} eingeladen, ein Kontakt für das digitale Erbe zu werden."; - static String m105(galleryType) => + static String m107(galleryType) => "Der Galerie-Typ ${galleryType} unterstützt kein Umbenennen"; - static String m106(ignoreReason) => + static String m108(ignoreReason) => "Upload wird aufgrund von ${ignoreReason} ignoriert"; - static String m107(count) => "Sichere ${count} Erinnerungsstücke..."; + static String m109(count) => "Sichere ${count} Erinnerungsstücke..."; - static String m108(endDate) => "Gültig bis ${endDate}"; + static String m110(endDate) => "Gültig bis ${endDate}"; - static String m109(email) => "Verifiziere ${email}"; + static String m111(email) => "Verifiziere ${email}"; - static String m110(name) => "${name} zum Entfernen des Links anzeigen"; - - static String m111(count) => - "${Intl.plural(count, zero: '0 Betrachter hinzugefügt', one: 'Einen Betrachter hinzugefügt', other: '${count} Betrachter hinzugefügt')}"; - - static String m112(email) => - "Wir haben eine E-Mail an ${email} gesendet"; + static String m112(name) => "${name} zum Entfernen des Links anzeigen"; static String m113(count) => + "${Intl.plural(count, zero: '0 Betrachter hinzugefügt', one: 'Einen Betrachter hinzugefügt', other: '${count} Betrachter hinzugefügt')}"; + + static String m114(email) => + "Wir haben eine E-Mail an ${email} gesendet"; + + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + + static String m116(count) => "${Intl.plural(count, one: 'vor einem Jahr', other: 'vor ${count} Jahren')}"; - static String m114(name) => "Du und ${name}"; + static String m117(name) => "Du und ${name}"; - static String m115(storageSaved) => + static String m118(storageSaved) => "Du hast ${storageSaved} erfolgreich freigegeben!"; final messages = _notInlinedMessages(_notInlinedMessages); @@ -340,6 +347,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Willkommen zurück!"), "ackPasswordLostWarning": MessageLookupByLibrary.simpleMessage( "Ich verstehe, dass ich meine Daten verlieren kann, wenn ich mein Passwort vergesse, da meine Daten Ende-zu-Ende-verschlüsselt sind."), + "actionNotSupportedOnFavouritesAlbum": + MessageLookupByLibrary.simpleMessage( + "Aktion für das Favoritenalbum nicht unterstützt"), "activeSessions": MessageLookupByLibrary.simpleMessage("Aktive Sitzungen"), "add": MessageLookupByLibrary.simpleMessage("Hinzufügen"), @@ -347,6 +357,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Füge einen Namen hinzu"), "addANewEmail": MessageLookupByLibrary.simpleMessage( "Neue E-Mail-Adresse hinzufügen"), + "addAlbumWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Füge ein Alben-Widget zu deiner Startseite hinzu und komm hierher zurück, um es anzupassen."), "addCollaborator": MessageLookupByLibrary.simpleMessage("Bearbeiter hinzufügen"), "addCollaborators": m1, @@ -356,6 +368,8 @@ class MessageLookup extends MessageLookupByLibrary { "addItem": m2, "addLocation": MessageLookupByLibrary.simpleMessage("Ort hinzufügen"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Hinzufügen"), + "addMemoriesWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Füge ein Erinnerungs-Widget zu deiner Startseite hinzu und komm hierher zurück, um es anzupassen."), "addMore": MessageLookupByLibrary.simpleMessage("Mehr hinzufügen"), "addName": MessageLookupByLibrary.simpleMessage("Name hinzufügen"), "addNameOrMerge": MessageLookupByLibrary.simpleMessage( @@ -367,6 +381,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Details der Add-ons"), "addOnValidTill": m3, "addOns": MessageLookupByLibrary.simpleMessage("Add-ons"), + "addParticipants": + MessageLookupByLibrary.simpleMessage("Teilnehmer hinzufügen"), + "addPeopleWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Füge ein Personen-Widget zu deiner Startseite hinzu und komm hierher zurück, um es anzupassen."), "addPhotos": MessageLookupByLibrary.simpleMessage("Fotos hinzufügen"), "addSelected": MessageLookupByLibrary.simpleMessage("Auswahl hinzufügen"), @@ -400,6 +418,8 @@ class MessageLookup extends MessageLookupByLibrary { "albumUpdated": MessageLookupByLibrary.simpleMessage("Album aktualisiert"), "albums": MessageLookupByLibrary.simpleMessage("Alben"), + "albumsWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Wähle die Alben, die du auf der Startseite sehen möchtest."), "allClear": MessageLookupByLibrary.simpleMessage("✨ Alles klar"), "allMemoriesPreserved": MessageLookupByLibrary.simpleMessage( "Alle Erinnerungsstücke gesichert"), @@ -551,9 +571,35 @@ class MessageLookup extends MessageLookupByLibrary { "backupVideos": MessageLookupByLibrary.simpleMessage("Videos sichern"), "beach": MessageLookupByLibrary.simpleMessage("Am Strand"), "birthday": MessageLookupByLibrary.simpleMessage("Geburtstag"), + "birthdayNotifications": MessageLookupByLibrary.simpleMessage( + "Geburtstagsbenachrichtigungen"), + "birthdays": MessageLookupByLibrary.simpleMessage("Geburtstage"), "blackFridaySale": MessageLookupByLibrary.simpleMessage("Black-Friday-Aktion"), "blog": MessageLookupByLibrary.simpleMessage("Blog"), + "cLDesc1": MessageLookupByLibrary.simpleMessage( + "Nach der Video-Streaming-Beta und der Arbeit an fortsetzbaren Uploads und Downloads haben wir das Datei-Upload-Limit auf 10 GB erhöht. Dies ist jetzt sowohl in Desktop- als auch in mobilen Apps verfügbar."), + "cLDesc2": MessageLookupByLibrary.simpleMessage( + "Hintergrund-Uploads werden jetzt auch auf iOS unterstützt, zusätzlich zu Android-Geräten. Du musst die App nicht öffnen, um deine neuesten Fotos und Videos zu sichern."), + "cLDesc3": MessageLookupByLibrary.simpleMessage( + "Wir haben erhebliche Verbesserungen an unserer Erinnerungserfahrung vorgenommen, einschließlich Autoplay, Wischen zur nächsten Erinnerung und vieles mehr."), + "cLDesc4": MessageLookupByLibrary.simpleMessage( + "Zusammen mit vielen internen Verbesserungen ist es jetzt viel einfacher, alle erkannten Gesichter zu sehen, Feedback zu ähnlichen Gesichtern zu geben und Gesichter zu einem einzelnen Foto hinzuzufügen/zu entfernen."), + "cLDesc5": MessageLookupByLibrary.simpleMessage( + "Du erhältst jetzt eine optionale Benachrichtigung für alle Geburtstage, die du auf Ente gespeichert hast, zusammen mit einer Sammlung ihrer besten Fotos."), + "cLDesc6": MessageLookupByLibrary.simpleMessage( + "Kein Warten mehr darauf, dass Uploads/Downloads abgeschlossen werden, bevor du die App schließen kannst. Alle Uploads und Downloads können jetzt mitten im Vorgang pausiert und von dort fortgesetzt werden, wo du aufgehört hast."), + "cLTitle1": + MessageLookupByLibrary.simpleMessage("Upload großer Videodateien"), + "cLTitle2": MessageLookupByLibrary.simpleMessage("Hintergrund-Upload"), + "cLTitle3": + MessageLookupByLibrary.simpleMessage("Autoplay-Erinnerungen"), + "cLTitle4": MessageLookupByLibrary.simpleMessage( + "Verbesserte Gesichtserkennung"), + "cLTitle5": MessageLookupByLibrary.simpleMessage( + "Geburtstags-Benachrichtigungen"), + "cLTitle6": MessageLookupByLibrary.simpleMessage( + "Fortsetzbare Uploads und Downloads"), "cachedData": MessageLookupByLibrary.simpleMessage("Daten im Cache"), "calculating": MessageLookupByLibrary.simpleMessage("Wird berechnet..."), @@ -626,7 +672,7 @@ class MessageLookup extends MessageLookupByLibrary { "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage( "• Klicken Sie auf das Überlaufmenü"), "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), + "Klicke, um unsere bisher beste Version zu installieren"), "close": MessageLookupByLibrary.simpleMessage("Schließen"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage( "Nach Aufnahmezeit gruppieren"), @@ -775,8 +821,9 @@ class MessageLookup extends MessageLookupByLibrary { "deleteItemCount": m21, "deleteLocation": MessageLookupByLibrary.simpleMessage("Standort löschen"), + "deleteMultipleAlbumDialog": m22, "deletePhotos": MessageLookupByLibrary.simpleMessage("Fotos löschen"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Es fehlt eine zentrale Funktion, die ich benötige"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -814,7 +861,7 @@ class MessageLookup extends MessageLookupByLibrary { "Zuschauer können weiterhin Screenshots oder mit anderen externen Programmen Kopien der Bilder machen."), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Bitte beachten Sie:"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Zweiten Faktor (2FA) deaktivieren"), "disablingTwofactorAuthentication": @@ -858,11 +905,11 @@ class MessageLookup extends MessageLookupByLibrary { "Herunterladen fehlgeschlagen"), "downloading": MessageLookupByLibrary.simpleMessage("Wird heruntergeladen..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("Bearbeiten"), - "editEmailAlreadyLinked": m27, + "editEmailAlreadyLinked": m28, "editLocation": MessageLookupByLibrary.simpleMessage("Standort bearbeiten"), "editLocationTagTitle": @@ -878,16 +925,16 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("E-Mail"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage( "E-Mail ist bereits registriert."), - "emailChangedTo": m28, - "emailDoesNotHaveEnteAccount": m29, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailDoesNotHaveEnteAccount": m30, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage("E-Mail nicht registriert."), "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("E-Mail-Verifizierung"), "emailYourLogs": MessageLookupByLibrary.simpleMessage( "Protokolle per E-Mail senden"), - "embracingThem": m31, + "embracingThem": m32, "emergencyContacts": MessageLookupByLibrary.simpleMessage("Notfallkontakte"), "empty": MessageLookupByLibrary.simpleMessage("Leeren"), @@ -949,6 +996,8 @@ class MessageLookup extends MessageLookupByLibrary { "Bitte gib eine gültige E-Mail-Adresse ein."), "enterYourEmailAddress": MessageLookupByLibrary.simpleMessage( "Gib deine E-Mail-Adresse ein"), + "enterYourNewEmailAddress": MessageLookupByLibrary.simpleMessage( + "Gib Deine neue E-Mail-Adresse ein"), "enterYourPassword": MessageLookupByLibrary.simpleMessage("Passwort eingeben"), "enterYourRecoveryKey": MessageLookupByLibrary.simpleMessage( @@ -966,7 +1015,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Daten exportieren"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage("Zusätzliche Fotos gefunden"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage( "Gesicht ist noch nicht gruppiert, bitte komm später zurück"), "faceRecognition": @@ -1004,7 +1053,7 @@ class MessageLookup extends MessageLookupByLibrary { "faq": MessageLookupByLibrary.simpleMessage("Häufig gestellte Fragen"), "faqs": MessageLookupByLibrary.simpleMessage("FAQs"), "favorite": MessageLookupByLibrary.simpleMessage("Favorit"), - "feastingWithThem": m33, + "feastingWithThem": m34, "feedback": MessageLookupByLibrary.simpleMessage("Rückmeldung"), "file": MessageLookupByLibrary.simpleMessage("Datei"), "fileFailedToSaveToGallery": MessageLookupByLibrary.simpleMessage( @@ -1018,8 +1067,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Dateitypen"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Dateitypen und -namen"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("Dateien gelöscht"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage( @@ -1038,28 +1087,28 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Gesichter gefunden"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage( "Kostenlos hinzugefügter Speicherplatz"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage( "Freier Speicherplatz nutzbar"), "freeTrial": MessageLookupByLibrary.simpleMessage("Kostenlose Testphase"), - "freeTrialValidTill": m37, - "freeUpAccessPostDelete": m38, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAccessPostDelete": m39, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("Gerätespeicher freiräumen"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Spare Speicherplatz auf deinem Gerät, indem du Dateien löschst, die bereits gesichert wurden."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Speicherplatz freigeben"), - "freeUpSpaceSaving": m40, + "freeUpSpaceSaving": m41, "gallery": MessageLookupByLibrary.simpleMessage("Galerie"), "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Bis zu 1000 Erinnerungsstücke angezeigt in der Galerie"), "general": MessageLookupByLibrary.simpleMessage("Allgemein"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Generierung von Verschlüsselungscodes..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("Zu den Einstellungen"), "googlePlayId": MessageLookupByLibrary.simpleMessage("Google Play ID"), @@ -1073,6 +1122,8 @@ class MessageLookup extends MessageLookupByLibrary { "guestView": MessageLookupByLibrary.simpleMessage("Gastansicht"), "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( "Bitte richte einen Gerätepasscode oder eine Bildschirmsperre ein, um die Gastansicht zu nutzen."), + "happyBirthday": MessageLookupByLibrary.simpleMessage( + "Herzlichen Glückwunsch zum Geburtstag! 🥳"), "hearUsExplanation": MessageLookupByLibrary.simpleMessage( "Wir tracken keine App-Installationen. Es würde uns jedoch helfen, wenn du uns mitteilst, wie du von uns erfahren hast!"), "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( @@ -1089,7 +1140,7 @@ class MessageLookup extends MessageLookupByLibrary { "hideSharedItemsFromHomeGallery": MessageLookupByLibrary.simpleMessage( "Geteilte Elemente in der Home-Galerie ausblenden"), "hiding": MessageLookupByLibrary.simpleMessage("Verstecken..."), - "hikingWithThem": m42, + "hikingWithThem": m43, "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("Gehostet bei OSM France"), "howItWorks": @@ -1148,7 +1199,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Etwas ist schiefgelaufen. Bitte versuche es später noch einmal. Sollte der Fehler weiter bestehen, kontaktiere unser Supportteam."), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Elemente zeigen die Anzahl der Tage bis zum dauerhaften Löschen an"), @@ -1169,7 +1220,7 @@ class MessageLookup extends MessageLookupByLibrary { "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage("Bitte gib diese Daten ein"), "language": MessageLookupByLibrary.simpleMessage("Sprache"), - "lastTimeWithThem": m44, + "lastTimeWithThem": m45, "lastUpdated": MessageLookupByLibrary.simpleMessage("Zuletzt aktualisiert"), "lastYearsTrip": @@ -1184,7 +1235,7 @@ class MessageLookup extends MessageLookupByLibrary { "legacy": MessageLookupByLibrary.simpleMessage("Digitales Erbe"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("Digital geerbte Konten"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage( "Das digitale Erbe erlaubt vertrauenswürdigen Kontakten den Zugriff auf dein Konto in deiner Abwesenheit."), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( @@ -1201,7 +1252,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("für schnelleres Teilen"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Aktiviert"), "linkExpired": MessageLookupByLibrary.simpleMessage("Abgelaufen"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Ablaufdatum des Links"), "linkHasExpired": @@ -1210,8 +1261,8 @@ class MessageLookup extends MessageLookupByLibrary { "linkPerson": MessageLookupByLibrary.simpleMessage("Person verknüpfen"), "linkPersonCaption": MessageLookupByLibrary.simpleMessage( "um besseres Teilen zu ermöglichen"), - "linkPersonToEmail": m47, - "linkPersonToEmailConfirmation": m48, + "linkPersonToEmail": m48, + "linkPersonToEmailConfirmation": m49, "livePhotos": MessageLookupByLibrary.simpleMessage("Live-Fotos"), "loadMessage1": MessageLookupByLibrary.simpleMessage( "Du kannst dein Abonnement mit deiner Familie teilen"), @@ -1272,7 +1323,7 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Drücken Sie lange auf ein Element, um es im Vollbildmodus anzuzeigen"), "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), + "Schau zurück auf deine Erinnerungen 🌄"), "loopVideoOff": MessageLookupByLibrary.simpleMessage("Videoschleife aus"), "loopVideoOn": MessageLookupByLibrary.simpleMessage("Videoschleife an"), @@ -1300,7 +1351,10 @@ class MessageLookup extends MessageLookupByLibrary { "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), "me": MessageLookupByLibrary.simpleMessage("Ich"), - "memoryCount": m49, + "memories": MessageLookupByLibrary.simpleMessage("Erinnerungen"), + "memoriesWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Wähle die Arten von Erinnerungen, die du auf der Startseite sehen möchtest."), + "memoryCount": m50, "merchandise": MessageLookupByLibrary.simpleMessage("Merchandise"), "mergeWithExisting": MessageLookupByLibrary.simpleMessage( "Mit vorhandenem zusammenführen"), @@ -1332,14 +1386,14 @@ class MessageLookup extends MessageLookupByLibrary { "mostRecent": MessageLookupByLibrary.simpleMessage("Neuste"), "mostRelevant": MessageLookupByLibrary.simpleMessage("Nach Relevanz"), "mountains": MessageLookupByLibrary.simpleMessage("Über den Bergen"), - "moveItem": m50, + "moveItem": m51, "moveSelectedPhotosToOneDate": MessageLookupByLibrary.simpleMessage( "Ausgewählte Fotos auf ein Datum verschieben"), "moveToAlbum": MessageLookupByLibrary.simpleMessage("Zum Album verschieben"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage( "Zu verstecktem Album verschieben"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage( "In den Papierkorb verschoben"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1354,7 +1408,7 @@ class MessageLookup extends MessageLookupByLibrary { "newAlbum": MessageLookupByLibrary.simpleMessage("Neues Album"), "newLocation": MessageLookupByLibrary.simpleMessage("Neuer Ort"), "newPerson": MessageLookupByLibrary.simpleMessage("Neue Person"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), + "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" neue 📸"), "newRange": MessageLookupByLibrary.simpleMessage("Neue Auswahl"), "newToEnte": MessageLookupByLibrary.simpleMessage("Neu bei Ente"), "newest": MessageLookupByLibrary.simpleMessage("Zuletzt"), @@ -1394,10 +1448,10 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Keine Ergebnisse"), "noResultsFound": MessageLookupByLibrary.simpleMessage("Keine Ergebnisse gefunden"), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage("Keine Systemsperre gefunden"), - "notPersonLabel": m53, + "notPersonLabel": m54, "notThisPerson": MessageLookupByLibrary.simpleMessage("Nicht diese Person?"), "nothingSharedWithYouYet": @@ -1411,10 +1465,12 @@ class MessageLookup extends MessageLookupByLibrary { "onEnte": MessageLookupByLibrary.simpleMessage( "Auf ente"), "onTheRoad": MessageLookupByLibrary.simpleMessage("Wieder unterwegs"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), + "onThisDay": MessageLookupByLibrary.simpleMessage("An diesem Tag"), + "onThisDayMemories": + MessageLookupByLibrary.simpleMessage("Erinnerungen an diesem Tag"), "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "Erhalte Erinnerungen von diesem Tag in den vergangenen Jahren."), + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("Nur diese"), "oops": MessageLookupByLibrary.simpleMessage("Hoppla"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( @@ -1444,7 +1500,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Mit PIN verbinden"), "pairingComplete": MessageLookupByLibrary.simpleMessage("Verbunden"), "panorama": MessageLookupByLibrary.simpleMessage("Panorama"), - "partyWithThem": m55, + "partyWithThem": m56, "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage( "Verifizierung steht noch aus"), "passkey": MessageLookupByLibrary.simpleMessage("Passkey"), @@ -1454,18 +1510,20 @@ class MessageLookup extends MessageLookupByLibrary { "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage( "Passwort erfolgreich geändert"), "passwordLock": MessageLookupByLibrary.simpleMessage("Passwort Sperre"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "Die Berechnung der Stärke des Passworts basiert auf dessen Länge, den verwendeten Zeichen, und ob es in den 10.000 am häufigsten verwendeten Passwörtern vorkommt"), "passwordWarning": MessageLookupByLibrary.simpleMessage( "Wir speichern dieses Passwort nicht. Wenn du es vergisst, können wir deine Daten nicht entschlüsseln"), + "pastYearsMemories": MessageLookupByLibrary.simpleMessage( + "Erinnerungen der letzten Jahre"), "paymentDetails": MessageLookupByLibrary.simpleMessage("Zahlungsdetails"), "paymentFailed": MessageLookupByLibrary.simpleMessage("Zahlung fehlgeschlagen"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Leider ist deine Zahlung fehlgeschlagen. Wende dich an unseren Support und wir helfen dir weiter!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("Ausstehende Elemente"), "pendingSync": @@ -1473,27 +1531,29 @@ class MessageLookup extends MessageLookupByLibrary { "people": MessageLookupByLibrary.simpleMessage("Personen"), "peopleUsingYourCode": MessageLookupByLibrary.simpleMessage( "Leute, die deinen Code verwenden"), + "peopleWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Wähle die Personen, die du auf der Startseite sehen möchtest."), "permDeleteWarning": MessageLookupByLibrary.simpleMessage( "Alle Elemente im Papierkorb werden dauerhaft gelöscht\n\nDiese Aktion kann nicht rückgängig gemacht werden"), "permanentlyDelete": MessageLookupByLibrary.simpleMessage("Dauerhaft löschen"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage( "Endgültig vom Gerät löschen?"), - "personIsAge": m58, + "personIsAge": m59, "personName": MessageLookupByLibrary.simpleMessage("Name der Person"), - "personTurningAge": m59, + "personTurningAge": m60, "pets": MessageLookupByLibrary.simpleMessage("Pelzige Begleiter"), "photoDescriptions": MessageLookupByLibrary.simpleMessage("Foto Beschreibungen"), "photoGridSize": MessageLookupByLibrary.simpleMessage("Fotorastergröße"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("Foto"), - "photocountPhotos": m60, + "photocountPhotos": m61, "photos": MessageLookupByLibrary.simpleMessage("Fotos"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage( "Von dir hinzugefügte Fotos werden vom Album entfernt"), - "photosCount": m61, + "photosCount": m62, "photosKeepRelativeTimeDifference": MessageLookupByLibrary.simpleMessage( "Fotos behalten relativen Zeitunterschied"), @@ -1505,7 +1565,7 @@ class MessageLookup extends MessageLookupByLibrary { "Album auf dem Fernseher wiedergeben"), "playOriginal": MessageLookupByLibrary.simpleMessage("Original abspielen"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playStream": MessageLookupByLibrary.simpleMessage("Stream abspielen"), "playstoreSubscription": MessageLookupByLibrary.simpleMessage("PlayStore Abo"), @@ -1518,14 +1578,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Bitte wenden Sie sich an den Support, falls das Problem weiterhin besteht"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage( "Bitte erteile die nötigen Berechtigungen"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Bitte logge dich erneut ein"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Bitte wähle die zu entfernenden schnellen Links"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Bitte versuche es erneut"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1539,7 +1599,7 @@ class MessageLookup extends MessageLookupByLibrary { "Bitte warte kurz, bevor du es erneut versuchst"), "pleaseWaitThisWillTakeAWhile": MessageLookupByLibrary.simpleMessage( "Bitte warten, dies wird eine Weile dauern."), - "posingWithThem": m65, + "posingWithThem": m66, "preparingLogs": MessageLookupByLibrary.simpleMessage( "Protokolle werden vorbereitet..."), "preserveMore": @@ -1559,7 +1619,7 @@ class MessageLookup extends MessageLookupByLibrary { "proceed": MessageLookupByLibrary.simpleMessage("Fortfahren"), "processed": MessageLookupByLibrary.simpleMessage("Verarbeitet"), "processing": MessageLookupByLibrary.simpleMessage("In Bearbeitung"), - "processingImport": m66, + "processingImport": m67, "processingVideos": MessageLookupByLibrary.simpleMessage("Verarbeite Videos"), "publicLinkCreated": @@ -1572,12 +1632,14 @@ class MessageLookup extends MessageLookupByLibrary { "raiseTicket": MessageLookupByLibrary.simpleMessage("Ticket erstellen"), "rateTheApp": MessageLookupByLibrary.simpleMessage("App bewerten"), "rateUs": MessageLookupByLibrary.simpleMessage("Bewerte uns"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "reassignMe": MessageLookupByLibrary.simpleMessage("\"Ich\" neu zuweisen"), - "reassignedToName": m68, + "reassignedToName": m69, "reassigningLoading": MessageLookupByLibrary.simpleMessage("Ordne neu zu..."), + "receiveRemindersOnBirthdays": MessageLookupByLibrary.simpleMessage( + "Erhalte Erinnerungen, wenn jemand Geburtstag hat. Ein Klick auf die Benachrichtigung bringt dich zu den Fotos der Person, die Geburtstag hat."), "recover": MessageLookupByLibrary.simpleMessage("Wiederherstellen"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Konto wiederherstellen"), @@ -1587,7 +1649,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Konto wiederherstellen"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage("Wiederherstellung gestartet"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage( "Wiederherstellungs-Schlüssel"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( @@ -1602,12 +1664,12 @@ class MessageLookup extends MessageLookupByLibrary { "Wiederherstellungs-Schlüssel überprüft"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "Dein Wiederherstellungsschlüssel ist die einzige Möglichkeit, auf deine Fotos zuzugreifen, solltest du dein Passwort vergessen. Du findest ihn unter Einstellungen > Konto.\n\nBitte gib deinen Wiederherstellungsschlüssel hier ein, um sicherzugehen, dass du ihn korrekt gesichert hast."), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage( "Wiederherstellung erfolgreich!"), "recoveryWarning": MessageLookupByLibrary.simpleMessage( "Ein vertrauenswürdiger Kontakt versucht, auf dein Konto zuzugreifen"), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "Das aktuelle Gerät ist nicht leistungsfähig genug, um dein Passwort zu verifizieren, aber wir können es neu erstellen, damit es auf allen Geräten funktioniert.\n\nBitte melde dich mit deinem Wiederherstellungs-Schlüssel an und erstelle dein Passwort neu (Wenn du willst, kannst du dasselbe erneut verwenden)."), "recreatePasswordTitle": @@ -1623,7 +1685,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Gib diesen Code an deine Freunde"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Sie schließen ein bezahltes Abo ab"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("Weiterempfehlungen"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Einlösungen sind derzeit pausiert"), @@ -1655,7 +1717,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Link entfernen"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Teilnehmer entfernen"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Personenetikett entfernen"), "removePublicLink": @@ -1675,7 +1737,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("Datei umbenennen"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Abonnement erneuern"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Fehler melden"), "reportBug": MessageLookupByLibrary.simpleMessage("Fehler melden"), "resendEmail": @@ -1701,7 +1763,7 @@ class MessageLookup extends MessageLookupByLibrary { "reviewSuggestions": MessageLookupByLibrary.simpleMessage("Vorschläge überprüfen"), "right": MessageLookupByLibrary.simpleMessage("Rechts"), - "roadtripWithThem": m75, + "roadtripWithThem": m76, "rotate": MessageLookupByLibrary.simpleMessage("Drehen"), "rotateLeft": MessageLookupByLibrary.simpleMessage("Nach links drehen"), "rotateRight": @@ -1758,8 +1820,8 @@ class MessageLookup extends MessageLookupByLibrary { "Laden Sie Personen ein, damit Sie geteilte Fotos hier einsehen können"), "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage( "Personen werden hier angezeigt, sobald Verarbeitung und Synchronisierung abgeschlossen sind"), - "searchResultCount": m76, - "searchSectionsLengthMismatch": m77, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("Sicherheit"), "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage( "Öffentliche Album-Links in der App ansehen"), @@ -1797,6 +1859,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Wähle dein Gesicht"), "selectYourPlan": MessageLookupByLibrary.simpleMessage("Wähle dein Abo aus"), + "selectedAlbums": m79, "selectedFilesAreNotOnEnte": MessageLookupByLibrary.simpleMessage( "Ausgewählte Dateien sind nicht auf Ente"), "selectedFoldersWillBeEncryptedAndBackedUp": @@ -1808,9 +1871,9 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeRemovedFromThisPerson": MessageLookupByLibrary.simpleMessage( "Ausgewählte Elemente werden von dieser Person entfernt, aber nicht aus deiner Bibliothek gelöscht."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, - "selfiesWithThem": m80, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, + "selfiesWithThem": m82, "send": MessageLookupByLibrary.simpleMessage("Absenden"), "sendEmail": MessageLookupByLibrary.simpleMessage("E-Mail senden"), "sendInvite": MessageLookupByLibrary.simpleMessage("Einladung senden"), @@ -1840,16 +1903,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Teile jetzt ein Album"), "shareLink": MessageLookupByLibrary.simpleMessage("Link teilen"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Teile mit ausgewählten Personen"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Hol dir Ente, damit wir ganz einfach Fotos und Videos in Originalqualität teilen können\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Mit Nicht-Ente-Benutzern teilen"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage("Teile dein erstes Album"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1860,7 +1923,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Neue geteilte Fotos"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "Erhalte Benachrichtigungen, wenn jemand ein Foto zu einem gemeinsam genutzten Album hinzufügt, dem du angehörst"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Mit mir geteilt"), "sharedWithYou": MessageLookupByLibrary.simpleMessage("Mit dir geteilt"), @@ -1878,12 +1941,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Andere Geräte abmelden"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Ich stimme den Nutzungsbedingungen und der Datenschutzerklärung zu"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "Es wird aus allen Alben gelöscht."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("Überspringen"), + "smartMemories": + MessageLookupByLibrary.simpleMessage("Smarte Erinnerungen"), "social": MessageLookupByLibrary.simpleMessage("Social Media"), "someItemsAreInBothEnteAndYourDevice": MessageLookupByLibrary.simpleMessage( @@ -1914,7 +1979,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Es tut uns leid, wir konnten keine sicheren Schlüssel auf diesem Gerät generieren.\n\nBitte starte die Registrierung auf einem anderen Gerät."), "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), + "Entschuldigung, wir mussten deine Sicherungen pausieren"), "sort": MessageLookupByLibrary.simpleMessage("Sortierung"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Sortieren nach"), "sortNewestFirst": @@ -1923,8 +1988,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Älteste zuerst"), "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ Abgeschlossen"), - "sportsWithThem": m89, - "spotlightOnThem": m90, + "sportsWithThem": m91, + "spotlightOnThem": m92, "spotlightOnYourself": MessageLookupByLibrary.simpleMessage("Spot auf dich selbst"), "startAccountRecoveryTitle": @@ -1939,14 +2004,14 @@ class MessageLookup extends MessageLookupByLibrary { "storage": MessageLookupByLibrary.simpleMessage("Speicherplatz"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Familie"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Sie"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage( "Speichergrenze überschritten"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "streamDetails": MessageLookupByLibrary.simpleMessage("Stream-Details"), "strongStrength": MessageLookupByLibrary.simpleMessage("Stark"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("Abonnieren"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "Du benötigst ein aktives, bezahltes Abonnement, um das Teilen zu aktivieren."), @@ -1964,7 +2029,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Verbesserung vorschlagen"), "sunrise": MessageLookupByLibrary.simpleMessage("Am Horizont"), "support": MessageLookupByLibrary.simpleMessage("Support"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("Synchronisierung angehalten"), "syncing": MessageLookupByLibrary.simpleMessage("Synchronisiere …"), @@ -1977,7 +2042,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Zum Entsperren antippen"), "tapToUpload": MessageLookupByLibrary.simpleMessage("Zum Hochladen antippen"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Etwas ist schiefgelaufen. Bitte versuche es später noch einmal. Sollte der Fehler weiter bestehen, kontaktiere unser Supportteam."), "terminate": MessageLookupByLibrary.simpleMessage("Beenden"), @@ -2001,7 +2066,7 @@ class MessageLookup extends MessageLookupByLibrary { "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage( "Diese Elemente werden von deinem Gerät gelöscht."), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage( "Sie werden aus allen Alben gelöscht."), "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( @@ -2019,12 +2084,12 @@ class MessageLookup extends MessageLookupByLibrary { "Dieses Bild hat keine Exif-Daten"), "thisIsMeExclamation": MessageLookupByLibrary.simpleMessage("Das bin ich!"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( "Dies ist deine Verifizierungs-ID"), "thisWeekThroughTheYears": MessageLookupByLibrary.simpleMessage("Diese Woche über die Jahre"), - "thisWeekXYearsAgo": m99, + "thisWeekXYearsAgo": m101, "thisWillLogYouOutOfTheFollowingDevice": MessageLookupByLibrary.simpleMessage( "Dadurch wirst du von folgendem Gerät abgemeldet:"), @@ -2036,7 +2101,7 @@ class MessageLookup extends MessageLookupByLibrary { "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( "Hiermit werden die öffentlichen Links aller ausgewählten schnellen Links entfernt."), - "throughTheYears": m100, + "throughTheYears": m102, "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": MessageLookupByLibrary.simpleMessage( "Um die App-Sperre zu aktivieren, konfiguriere bitte den Gerätepasscode oder die Bildschirmsperre in den Systemeinstellungen."), @@ -2051,13 +2116,13 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("Gesamt"), "totalSize": MessageLookupByLibrary.simpleMessage("Gesamtgröße"), "trash": MessageLookupByLibrary.simpleMessage("Papierkorb"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("Schneiden"), - "tripInYear": m102, - "tripToLocation": m103, + "tripInYear": m104, + "tripToLocation": m105, "trustedContacts": MessageLookupByLibrary.simpleMessage("Vertrauenswürdige Kontakte"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("Erneut versuchen"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "Aktiviere die Sicherung, um neue Dateien in diesem Ordner automatisch zu Ente hochzuladen."), @@ -2076,7 +2141,7 @@ class MessageLookup extends MessageLookupByLibrary { "Zwei-Faktor-Authentifizierung (2FA) erfolgreich zurückgesetzt"), "twofactorSetup": MessageLookupByLibrary.simpleMessage( "Zweiten Faktor (2FA) einrichten"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("Dearchivieren"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("Album dearchivieren"), @@ -2100,10 +2165,10 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage( "Ordnerauswahl wird aktualisiert..."), "upgrade": MessageLookupByLibrary.simpleMessage("Upgrade"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Dateien werden ins Album hochgeladen..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage( "Sichere ein Erinnerungsstück..."), "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( @@ -2122,7 +2187,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ausgewähltes Foto verwenden"), "usedSpace": MessageLookupByLibrary.simpleMessage("Belegter Speicherplatz"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Verifizierung fehlgeschlagen, bitte versuchen Sie es erneut"), @@ -2131,7 +2196,7 @@ class MessageLookup extends MessageLookupByLibrary { "verify": MessageLookupByLibrary.simpleMessage("Überprüfen"), "verifyEmail": MessageLookupByLibrary.simpleMessage("E-Mail-Adresse verifizieren"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Überprüfen"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("Passkey verifizieren"), @@ -2143,6 +2208,8 @@ class MessageLookup extends MessageLookupByLibrary { "videoInfo": MessageLookupByLibrary.simpleMessage("Video-Informationen"), "videoSmallCase": MessageLookupByLibrary.simpleMessage("Video"), + "videoStreaming": + MessageLookupByLibrary.simpleMessage("Streambare Videos"), "videos": MessageLookupByLibrary.simpleMessage("Videos"), "viewActiveSessions": MessageLookupByLibrary.simpleMessage("Aktive Sitzungen anzeigen"), @@ -2155,11 +2222,11 @@ class MessageLookup extends MessageLookupByLibrary { "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( "Dateien anzeigen, die den meisten Speicherplatz belegen."), "viewLogs": MessageLookupByLibrary.simpleMessage("Protokolle anzeigen"), - "viewPersonToUnlink": m110, + "viewPersonToUnlink": m112, "viewRecoveryKey": MessageLookupByLibrary.simpleMessage( "Wiederherstellungsschlüssel anzeigen"), "viewer": MessageLookupByLibrary.simpleMessage("Zuschauer"), - "viewersSuccessfullyAdded": m111, + "viewersSuccessfullyAdded": m113, "visitWebToManage": MessageLookupByLibrary.simpleMessage( "Bitte rufe \"web.ente.io\" auf, um dein Abo zu verwalten"), "waitingForVerification": @@ -2172,16 +2239,18 @@ class MessageLookup extends MessageLookupByLibrary { "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "Wir unterstützen keine Bearbeitung von Fotos und Alben, die du noch nicht besitzt"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Schwach"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Willkommen zurück!"), "whatsNew": MessageLookupByLibrary.simpleMessage("Neue Funktionen"), "whyAddTrustContact": MessageLookupByLibrary.simpleMessage( "Ein vertrauenswürdiger Kontakt kann helfen, deine Daten wiederherzustellen."), + "widgets": MessageLookupByLibrary.simpleMessage("Widgets"), + "wishThemAHappyBirthday": m115, "yearShort": MessageLookupByLibrary.simpleMessage("Jahr"), "yearly": MessageLookupByLibrary.simpleMessage("Jährlich"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Ja"), "yesCancel": MessageLookupByLibrary.simpleMessage("Ja, kündigen"), "yesConvertToViewer": MessageLookupByLibrary.simpleMessage( @@ -2195,7 +2264,7 @@ class MessageLookup extends MessageLookupByLibrary { "yesResetPerson": MessageLookupByLibrary.simpleMessage("Ja, Person zurücksetzen"), "you": MessageLookupByLibrary.simpleMessage("Du"), - "youAndThem": m114, + "youAndThem": m117, "youAreOnAFamilyPlan": MessageLookupByLibrary.simpleMessage("Du bist im Familien-Tarif!"), "youAreOnTheLatestVersion": MessageLookupByLibrary.simpleMessage( @@ -2214,7 +2283,7 @@ class MessageLookup extends MessageLookupByLibrary { "Du kannst nicht mit dir selbst teilen"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( "Du hast keine archivierten Elemente."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage( "Dein Benutzerkonto wurde gelöscht"), "yourMap": MessageLookupByLibrary.simpleMessage("Deine Karte"), diff --git a/mobile/lib/generated/intl/messages_el.dart b/mobile/lib/generated/intl/messages_el.dart index 198bc2affb..2af0da1ad8 100644 --- a/mobile/lib/generated/intl/messages_el.dart +++ b/mobile/lib/generated/intl/messages_el.dart @@ -20,19 +20,12 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'el'; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "enterYourEmailAddress": MessageLookupByLibrary.simpleMessage( "Εισάγετε την διεύθυνση ηλ. ταχυδρομείου σας"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups") + "wishThemAHappyBirthday": m115 }; } diff --git a/mobile/lib/generated/intl/messages_en.dart b/mobile/lib/generated/intl/messages_en.dart index 64c7bf315d..77f9b672a5 100644 --- a/mobile/lib/generated/intl/messages_en.dart +++ b/mobile/lib/generated/intl/messages_en.dart @@ -82,248 +82,250 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'Delete ${count} item', other: 'Delete ${count} items')}"; - static String m116(count) => + static String m22(count) => "Also delete the photos (and videos) present in these ${count} albums from all other albums they are part of?"; - static String m22(currentlyDeleting, totalCount) => + static String m23(currentlyDeleting, totalCount) => "Deleting ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "This will remove the public link for accessing \"${albumName}\"."; - static String m24(supportEmail) => + static String m25(supportEmail) => "Please drop an email to ${supportEmail} from your registered email address"; - static String m25(count, storageSaved) => + static String m26(count, storageSaved) => "You have cleaned up ${Intl.plural(count, one: '${count} duplicate file', other: '${count} duplicate files')}, saving (${storageSaved}!)"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} files, ${formattedSize} each"; - static String m27(name) => "This email is already linked to ${name}."; + static String m28(name) => "This email is already linked to ${name}."; - static String m28(newEmail) => "Email changed to ${newEmail}"; + static String m29(newEmail) => "Email changed to ${newEmail}"; - static String m29(email) => "${email} does not have an Ente account."; + static String m30(email) => "${email} does not have an Ente account."; - static String m30(email) => + static String m31(email) => "${email} does not have an Ente account.\n\nSend them an invite to share photos."; - static String m31(name) => "Embracing ${name}"; + static String m32(name) => "Embracing ${name}"; - static String m32(text) => "Extra photos found for ${text}"; + static String m33(text) => "Extra photos found for ${text}"; - static String m33(name) => "Feasting with ${name}"; - - static String m34(count, formattedNumber) => - "${Intl.plural(count, one: '1 file', other: '${formattedNumber} files')} on this device have been backed up safely"; + static String m34(name) => "Feasting with ${name}"; static String m35(count, formattedNumber) => + "${Intl.plural(count, one: '1 file', other: '${formattedNumber} files')} on this device have been backed up safely"; + + static String m36(count, formattedNumber) => "${Intl.plural(count, one: '1 file', other: '${formattedNumber} files')} in this album has been backed up safely"; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "${storageAmountInGB} GB each time someone signs up for a paid plan and applies your code"; - static String m37(endDate) => "Free trial valid till ${endDate}"; + static String m38(endDate) => "Free trial valid till ${endDate}"; - static String m38(count) => + static String m39(count) => "You can still access ${Intl.plural(count, one: 'it', other: 'them')} on Ente as long as you have an active subscription"; - static String m39(sizeInMBorGB) => "Free up ${sizeInMBorGB}"; + static String m40(sizeInMBorGB) => "Free up ${sizeInMBorGB}"; - static String m40(count, formattedSize) => + static String m41(count, formattedSize) => "${Intl.plural(count, one: 'It can be deleted from the device to free up ${formattedSize}', other: 'They can be deleted from the device to free up ${formattedSize}')}"; - static String m41(currentlyProcessing, totalCount) => + static String m42(currentlyProcessing, totalCount) => "Processing ${currentlyProcessing} / ${totalCount}"; - static String m42(name) => "Hiking with ${name}"; + static String m43(name) => "Hiking with ${name}"; - static String m43(count) => + static String m44(count) => "${Intl.plural(count, one: '${count} item', other: '${count} items')}"; - static String m44(name) => "Last time with ${name}"; + static String m45(name) => "Last time with ${name}"; - static String m45(email) => + static String m46(email) => "${email} has invited you to be a trusted contact"; - static String m46(expiryTime) => "Link will expire on ${expiryTime}"; + static String m47(expiryTime) => "Link will expire on ${expiryTime}"; - static String m47(email) => "Link person to ${email}"; + static String m48(email) => "Link person to ${email}"; - static String m48(personName, email) => + static String m49(personName, email) => "This will link ${personName} to ${email}"; - static String m49(count, formattedCount) => + static String m50(count, formattedCount) => "${Intl.plural(count, zero: 'no memories', one: '${formattedCount} memory', other: '${formattedCount} memories')}"; - static String m50(count) => + static String m51(count) => "${Intl.plural(count, one: 'Move item', other: 'Move items')}"; - static String m51(albumName) => "Moved successfully to ${albumName}"; + static String m52(albumName) => "Moved successfully to ${albumName}"; - static String m52(personName) => "No suggestions for ${personName}"; + static String m53(personName) => "No suggestions for ${personName}"; - static String m53(name) => "Not ${name}?"; + static String m54(name) => "Not ${name}?"; - static String m54(familyAdminEmail) => + static String m55(familyAdminEmail) => "Please contact ${familyAdminEmail} to change your code."; - static String m55(name) => "Party with ${name}"; + static String m56(name) => "Party with ${name}"; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Password strength: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "Please talk to ${providerName} support if you were charged"; - static String m58(name, age) => "${name} is ${age}!"; + static String m59(name, age) => "${name} is ${age}!"; - static String m59(name, age) => "${name} turning ${age} soon"; - - static String m60(count) => - "${Intl.plural(count, zero: 'No photos', one: '1 photo', other: '${count} photos')}"; + static String m60(name, age) => "${name} turning ${age} soon"; static String m61(count) => + "${Intl.plural(count, zero: 'No photos', one: '1 photo', other: '${count} photos')}"; + + static String m62(count) => "${Intl.plural(count, zero: '0 photos', one: '1 photo', other: '${count} photos')}"; - static String m62(endDate) => + static String m63(endDate) => "Free trial valid till ${endDate}.\nYou can choose a paid plan afterwards."; - static String m63(toEmail) => "Please email us at ${toEmail}"; + static String m64(toEmail) => "Please email us at ${toEmail}"; - static String m64(toEmail) => "Please send the logs to \n${toEmail}"; + static String m65(toEmail) => "Please send the logs to \n${toEmail}"; - static String m65(name) => "Posing with ${name}"; + static String m66(name) => "Posing with ${name}"; - static String m66(folderName) => "Processing ${folderName}..."; + static String m67(folderName) => "Processing ${folderName}..."; - static String m67(storeName) => "Rate us on ${storeName}"; + static String m68(storeName) => "Rate us on ${storeName}"; - static String m68(name) => "Reassigned you to ${name}"; + static String m69(name) => "Reassigned you to ${name}"; - static String m69(days, email) => + static String m70(days, email) => "You can access the account after ${days} days. A notification will be sent to ${email}."; - static String m70(email) => + static String m71(email) => "You can now recover ${email}\'s account by setting a new password."; - static String m71(email) => "${email} is trying to recover your account."; + static String m72(email) => "${email} is trying to recover your account."; - static String m72(storageInGB) => + static String m73(storageInGB) => "3. Both of you get ${storageInGB} GB* free"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} will be removed from this shared album\n\nAny photos added by them will also be removed from the album"; - static String m74(endDate) => "Subscription renews on ${endDate}"; + static String m75(endDate) => "Subscription renews on ${endDate}"; - static String m75(name) => "Road trip with ${name}"; + static String m76(name) => "Road trip with ${name}"; - static String m76(count) => + static String m77(count) => "${Intl.plural(count, one: '${count} result found', other: '${count} results found')}"; - static String m77(snapshotLength, searchLength) => + static String m78(snapshotLength, searchLength) => "Sections length mismatch: ${snapshotLength} != ${searchLength}"; - static String m117(count) => "${count} selected"; + static String m79(count) => "${count} selected"; - static String m78(count) => "${count} selected"; + static String m80(count) => "${count} selected"; - static String m79(count, yourCount) => + static String m81(count, yourCount) => "${count} selected (${yourCount} yours)"; - static String m80(name) => "Selfies with ${name}"; + static String m82(name) => "Selfies with ${name}"; - static String m81(verificationID) => + static String m83(verificationID) => "Here\'s my verification ID: ${verificationID} for ente.io."; - static String m82(verificationID) => + static String m84(verificationID) => "Hey, can you confirm that this is your ente.io verification ID: ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Ente referral code: ${referralCode} \n\nApply it in Settings → General → Referrals to get ${referralStorageInGB} GB free after you signup for a paid plan\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Share with specific people', one: 'Shared with 1 person', other: 'Shared with ${numberOfPeople} people')}"; - static String m85(emailIDs) => "Shared with ${emailIDs}"; + static String m87(emailIDs) => "Shared with ${emailIDs}"; - static String m86(fileType) => + static String m88(fileType) => "This ${fileType} will be deleted from your device."; - static String m87(fileType) => + static String m89(fileType) => "This ${fileType} is in both Ente and your device."; - static String m88(fileType) => "This ${fileType} will be deleted from Ente."; + static String m90(fileType) => "This ${fileType} will be deleted from Ente."; - static String m89(name) => "Sports with ${name}"; + static String m91(name) => "Sports with ${name}"; - static String m90(name) => "Spotlight on ${name}"; + static String m92(name) => "Spotlight on ${name}"; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} of ${totalAmount} ${totalStorageUnit} used"; - static String m93(id) => + static String m95(id) => "Your ${id} is already linked to another Ente account.\nIf you would like to use your ${id} with this account, please contact our support\'\'"; - static String m94(endDate) => + static String m96(endDate) => "Your subscription will be cancelled on ${endDate}"; - static String m95(completed, total) => + static String m97(completed, total) => "${completed}/${total} memories preserved"; - static String m96(ignoreReason) => + static String m98(ignoreReason) => "Tap to upload, upload is currently ignored due to ${ignoreReason}"; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "They also get ${storageAmountInGB} GB"; - static String m98(email) => "This is ${email}\'s Verification ID"; - - static String m99(count) => - "${Intl.plural(count, one: 'This week, ${count} year ago', other: 'This week, ${count} years ago')}"; - - static String m100(dateFormat) => "${dateFormat} through the years"; + static String m100(email) => "This is ${email}\'s Verification ID"; static String m101(count) => + "${Intl.plural(count, one: 'This week, ${count} year ago', other: 'This week, ${count} years ago')}"; + + static String m102(dateFormat) => "${dateFormat} through the years"; + + static String m103(count) => "${Intl.plural(count, zero: 'Soon', one: '1 day', other: '${count} days')}"; - static String m102(year) => "Trip in ${year}"; + static String m104(year) => "Trip in ${year}"; - static String m103(location) => "Trip to ${location}"; + static String m105(location) => "Trip to ${location}"; - static String m104(email) => + static String m106(email) => "You have been invited to be a legacy contact by ${email}."; - static String m105(galleryType) => + static String m107(galleryType) => "Type of gallery ${galleryType} is not supported for rename"; - static String m106(ignoreReason) => + static String m108(ignoreReason) => "Upload is ignored due to ${ignoreReason}"; - static String m107(count) => "Preserving ${count} memories..."; + static String m109(count) => "Preserving ${count} memories..."; - static String m108(endDate) => "Valid till ${endDate}"; + static String m110(endDate) => "Valid till ${endDate}"; - static String m109(email) => "Verify ${email}"; + static String m111(email) => "Verify ${email}"; - static String m110(name) => "View ${name} to unlink"; - - static String m111(count) => - "${Intl.plural(count, zero: 'Added 0 viewers', one: 'Added 1 viewer', other: 'Added ${count} viewers')}"; - - static String m112(email) => "We have sent a mail to ${email}"; + static String m112(name) => "View ${name} to unlink"; static String m113(count) => + "${Intl.plural(count, zero: 'Added 0 viewers', one: 'Added 1 viewer', other: 'Added ${count} viewers')}"; + + static String m114(email) => "We have sent a mail to ${email}"; + + static String m115(name) => "Wish ${name} a happy birthday! 🎉"; + + static String m116(count) => "${Intl.plural(count, one: '${count} year ago', other: '${count} years ago')}"; - static String m114(name) => "You and ${name}"; + static String m117(name) => "You and ${name}"; - static String m115(storageSaved) => + static String m118(storageSaved) => "You have successfully freed up ${storageSaved}!"; final messages = _notInlinedMessages(_notInlinedMessages); @@ -413,6 +415,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("All memories preserved"), "allPersonGroupingWillReset": MessageLookupByLibrary.simpleMessage( "All groupings for this person will be reset, and you will lose all suggestions made for this person"), + "allUnnamedGroupsWillBeMergedIntoTheSelectedPerson": + MessageLookupByLibrary.simpleMessage( + "All unnamed groups will be merged into the selected person. This can still be undone from the suggestions history overview of the person."), "allWillShiftRangeBasedOnFirst": MessageLookupByLibrary.simpleMessage( "This is the first in the group. Other selected photos will automatically shift based on this new date"), "allow": MessageLookupByLibrary.simpleMessage("Allow"), @@ -462,6 +467,10 @@ class MessageLookup extends MessageLookupByLibrary { "archive": MessageLookupByLibrary.simpleMessage("Archive"), "archiveAlbum": MessageLookupByLibrary.simpleMessage("Archive album"), "archiving": MessageLookupByLibrary.simpleMessage("Archiving..."), + "areThey": MessageLookupByLibrary.simpleMessage("Are they "), + "areYouSureRemoveThisFaceFromPerson": + MessageLookupByLibrary.simpleMessage( + "Are you sure you want to remove this face from this person?"), "areYouSureThatYouWantToLeaveTheFamily": MessageLookupByLibrary.simpleMessage( "Are you sure that you want to leave the family plan?"), @@ -472,8 +481,16 @@ class MessageLookup extends MessageLookupByLibrary { "Are you sure you want to change your plan?"), "areYouSureYouWantToExit": MessageLookupByLibrary.simpleMessage( "Are you sure you want to exit?"), + "areYouSureYouWantToIgnoreThesePersons": + MessageLookupByLibrary.simpleMessage( + "Are you sure you want to ignore these persons?"), + "areYouSureYouWantToIgnoreThisPerson": + MessageLookupByLibrary.simpleMessage( + "Are you sure you want to ignore this person?"), "areYouSureYouWantToLogout": MessageLookupByLibrary.simpleMessage( "Are you sure you want to logout?"), + "areYouSureYouWantToMergeThem": MessageLookupByLibrary.simpleMessage( + "Are you sure you want to merge them?"), "areYouSureYouWantToRenew": MessageLookupByLibrary.simpleMessage( "Are you sure you want to renew?"), "areYouSureYouWantToResetThisPerson": @@ -552,9 +569,34 @@ class MessageLookup extends MessageLookupByLibrary { "backupVideos": MessageLookupByLibrary.simpleMessage("Backup videos"), "beach": MessageLookupByLibrary.simpleMessage("Sand and sea"), "birthday": MessageLookupByLibrary.simpleMessage("Birthday"), + "birthdayNotifications": + MessageLookupByLibrary.simpleMessage("Birthday notifications"), + "birthdays": MessageLookupByLibrary.simpleMessage("Birthdays"), "blackFridaySale": MessageLookupByLibrary.simpleMessage("Black Friday Sale"), "blog": MessageLookupByLibrary.simpleMessage("Blog"), + "cLDesc1": MessageLookupByLibrary.simpleMessage( + "On the back of video streaming beta, and work on resumable uploads and downloads, we have now increased the file upload limit to 10GB. This is now available in both desktop and mobile apps."), + "cLDesc2": MessageLookupByLibrary.simpleMessage( + "Background uploads are now supported on iOS as well, in addition to Android devices. No need to open the app to backup your latest photos and videos."), + "cLDesc3": MessageLookupByLibrary.simpleMessage( + "We have made significant improvements to our memories experience, including autoplay, swipe to next memory and a lot more."), + "cLDesc4": MessageLookupByLibrary.simpleMessage( + "Along with a bunch of under the hood improvements, now its much easier to see all detected faces, provide feedback on similar faces, and add/remove faces from a single photo."), + "cLDesc5": MessageLookupByLibrary.simpleMessage( + "You will now receive an opt-out notification for all the birthdays your have saved on Ente, along with a collection of their best photos."), + "cLDesc6": MessageLookupByLibrary.simpleMessage( + "No more waiting for uploads/downloads to complete before you can close the app. All uploads and downloads now have the ability to be paused midway, and resume from where you left off."), + "cLTitle1": + MessageLookupByLibrary.simpleMessage("Uploading Large Video Files"), + "cLTitle2": MessageLookupByLibrary.simpleMessage("Background Upload"), + "cLTitle3": MessageLookupByLibrary.simpleMessage("Autoplay Memories"), + "cLTitle4": + MessageLookupByLibrary.simpleMessage("Improved Face Recognition"), + "cLTitle5": + MessageLookupByLibrary.simpleMessage("Birthday Notifications"), + "cLTitle6": MessageLookupByLibrary.simpleMessage( + "Resumable Uploads and Downloads"), "cachedData": MessageLookupByLibrary.simpleMessage("Cached data"), "calculating": MessageLookupByLibrary.simpleMessage("Calculating..."), "canNotOpenBody": MessageLookupByLibrary.simpleMessage( @@ -770,9 +812,9 @@ class MessageLookup extends MessageLookupByLibrary { "deleteItemCount": m21, "deleteLocation": MessageLookupByLibrary.simpleMessage("Delete location"), - "deleteMultipleAlbumDialog": m116, + "deleteMultipleAlbumDialog": m22, "deletePhotos": MessageLookupByLibrary.simpleMessage("Delete photos"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "It’s missing a key feature that I need"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -805,13 +847,14 @@ class MessageLookup extends MessageLookupByLibrary { "deviceNotFound": MessageLookupByLibrary.simpleMessage("Device not found"), "didYouKnow": MessageLookupByLibrary.simpleMessage("Did you know?"), + "different": MessageLookupByLibrary.simpleMessage("Different"), "disableAutoLock": MessageLookupByLibrary.simpleMessage("Disable auto lock"), "disableDownloadWarningBody": MessageLookupByLibrary.simpleMessage( "Viewers can still take screenshots or save a copy of your photos using external tools"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Please note"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage("Disable two-factor"), "disablingTwofactorAuthentication": @@ -853,11 +896,11 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("Download failed"), "downloading": MessageLookupByLibrary.simpleMessage("Downloading..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("Edit"), - "editEmailAlreadyLinked": m27, + "editEmailAlreadyLinked": m28, "editLocation": MessageLookupByLibrary.simpleMessage("Edit location"), "editLocationTagTitle": MessageLookupByLibrary.simpleMessage("Edit location"), @@ -871,16 +914,16 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("Email"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage("Email already registered."), - "emailChangedTo": m28, - "emailDoesNotHaveEnteAccount": m29, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailDoesNotHaveEnteAccount": m30, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage("Email not registered."), "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("Email verification"), "emailYourLogs": MessageLookupByLibrary.simpleMessage("Email your logs"), - "embracingThem": m31, + "embracingThem": m32, "emergencyContacts": MessageLookupByLibrary.simpleMessage("Emergency Contacts"), "empty": MessageLookupByLibrary.simpleMessage("Empty"), @@ -957,7 +1000,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Export your data"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage("Extra photos found"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage( "Face not clustered yet, please come back later"), "faceRecognition": @@ -994,7 +1037,7 @@ class MessageLookup extends MessageLookupByLibrary { "faq": MessageLookupByLibrary.simpleMessage("FAQ"), "faqs": MessageLookupByLibrary.simpleMessage("FAQs"), "favorite": MessageLookupByLibrary.simpleMessage("Favorite"), - "feastingWithThem": m33, + "feastingWithThem": m34, "feedback": MessageLookupByLibrary.simpleMessage("Feedback"), "file": MessageLookupByLibrary.simpleMessage("File"), "fileFailedToSaveToGallery": MessageLookupByLibrary.simpleMessage( @@ -1008,8 +1051,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("File types"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("File types and names"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("Files deleted"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage("Files saved to gallery"), @@ -1026,26 +1069,26 @@ class MessageLookup extends MessageLookupByLibrary { "foundFaces": MessageLookupByLibrary.simpleMessage("Found faces"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("Free storage claimed"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("Free storage usable"), "freeTrial": MessageLookupByLibrary.simpleMessage("Free trial"), - "freeTrialValidTill": m37, - "freeUpAccessPostDelete": m38, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAccessPostDelete": m39, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("Free up device space"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Save space on your device by clearing files that have been already backed up."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Free up space"), - "freeUpSpaceSaving": m40, + "freeUpSpaceSaving": m41, "gallery": MessageLookupByLibrary.simpleMessage("Gallery"), "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Up to 1000 memories shown in gallery"), "general": MessageLookupByLibrary.simpleMessage("General"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Generating encryption keys..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("Go to settings"), "googlePlayId": MessageLookupByLibrary.simpleMessage("Google Play ID"), "grantFullAccessPrompt": MessageLookupByLibrary.simpleMessage( @@ -1058,6 +1101,8 @@ class MessageLookup extends MessageLookupByLibrary { "guestView": MessageLookupByLibrary.simpleMessage("Guest view"), "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( "To enable guest view, please setup device passcode or screen lock in your system settings."), + "happyBirthday": + MessageLookupByLibrary.simpleMessage("Happy birthday! 🥳"), "hearUsExplanation": MessageLookupByLibrary.simpleMessage( "We don\'t track app installs. It\'d help if you told us where you found us!"), "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( @@ -1073,7 +1118,7 @@ class MessageLookup extends MessageLookupByLibrary { "hideSharedItemsFromHomeGallery": MessageLookupByLibrary.simpleMessage( "Hide shared items from home gallery"), "hiding": MessageLookupByLibrary.simpleMessage("Hiding..."), - "hikingWithThem": m42, + "hikingWithThem": m43, "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("Hosted at OSM France"), "howItWorks": MessageLookupByLibrary.simpleMessage("How it works"), @@ -1084,6 +1129,7 @@ class MessageLookup extends MessageLookupByLibrary { "iOSLockOut": MessageLookupByLibrary.simpleMessage( "Biometric authentication is disabled. Please lock and unlock your screen to enable it."), "iOSOkButton": MessageLookupByLibrary.simpleMessage("OK"), + "ignore": MessageLookupByLibrary.simpleMessage("Ignore"), "ignoreUpdate": MessageLookupByLibrary.simpleMessage("Ignore"), "ignored": MessageLookupByLibrary.simpleMessage("ignored"), "ignoredFolderUploadReason": MessageLookupByLibrary.simpleMessage( @@ -1128,7 +1174,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "It looks like something went wrong. Please retry after some time. If the error persists, please contact our support team."), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Items show the number of days remaining before permanent deletion"), @@ -1148,7 +1194,7 @@ class MessageLookup extends MessageLookupByLibrary { "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( "Kindly help us with this information"), "language": MessageLookupByLibrary.simpleMessage("Language"), - "lastTimeWithThem": m44, + "lastTimeWithThem": m45, "lastUpdated": MessageLookupByLibrary.simpleMessage("Last updated"), "lastYearsTrip": MessageLookupByLibrary.simpleMessage("Last year\'s trip"), @@ -1161,7 +1207,7 @@ class MessageLookup extends MessageLookupByLibrary { "legacy": MessageLookupByLibrary.simpleMessage("Legacy"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("Legacy accounts"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage( "Legacy allows trusted contacts to access your account in your absence."), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( @@ -1177,7 +1223,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("for faster sharing"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Enabled"), "linkExpired": MessageLookupByLibrary.simpleMessage("Expired"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Link expiry"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("Link has expired"), @@ -1185,8 +1231,8 @@ class MessageLookup extends MessageLookupByLibrary { "linkPerson": MessageLookupByLibrary.simpleMessage("Link person"), "linkPersonCaption": MessageLookupByLibrary.simpleMessage( "for better sharing experience"), - "linkPersonToEmail": m47, - "linkPersonToEmailConfirmation": m48, + "linkPersonToEmail": m48, + "linkPersonToEmailConfirmation": m49, "livePhotos": MessageLookupByLibrary.simpleMessage("Live Photos"), "loadMessage1": MessageLookupByLibrary.simpleMessage( "You can share your subscription with your family"), @@ -1276,8 +1322,9 @@ class MessageLookup extends MessageLookupByLibrary { "memories": MessageLookupByLibrary.simpleMessage("Memories"), "memoriesWidgetDesc": MessageLookupByLibrary.simpleMessage( "Select the kind of memories you wish to see on your homescreen."), - "memoryCount": m49, + "memoryCount": m50, "merchandise": MessageLookupByLibrary.simpleMessage("Merchandise"), + "merge": MessageLookupByLibrary.simpleMessage("Merge"), "mergeWithExisting": MessageLookupByLibrary.simpleMessage("Merge with existing"), "mergedPhotos": MessageLookupByLibrary.simpleMessage("Merged photos"), @@ -1307,13 +1354,13 @@ class MessageLookup extends MessageLookupByLibrary { "mostRecent": MessageLookupByLibrary.simpleMessage("Most recent"), "mostRelevant": MessageLookupByLibrary.simpleMessage("Most relevant"), "mountains": MessageLookupByLibrary.simpleMessage("Over the hills"), - "moveItem": m50, + "moveItem": m51, "moveSelectedPhotosToOneDate": MessageLookupByLibrary.simpleMessage( "Move selected photos to one date"), "moveToAlbum": MessageLookupByLibrary.simpleMessage("Move to album"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Move to hidden album"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("Moved to trash"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage("Moving files to album..."), @@ -1365,10 +1412,10 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("No results"), "noResultsFound": MessageLookupByLibrary.simpleMessage("No results found"), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage("No system lock found"), - "notPersonLabel": m53, + "notPersonLabel": m54, "notThisPerson": MessageLookupByLibrary.simpleMessage("Not this person?"), "nothingSharedWithYouYet": @@ -1386,7 +1433,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("On this day memories"), "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("Only them"), "oops": MessageLookupByLibrary.simpleMessage("Oops"), "oopsCouldNotSaveEdits": @@ -1410,12 +1457,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Or pick an existing one"), "orPickFromYourContacts": MessageLookupByLibrary.simpleMessage("or pick from your contacts"), + "otherDetectedFaces": + MessageLookupByLibrary.simpleMessage("Other detected faces"), "pair": MessageLookupByLibrary.simpleMessage("Pair"), "pairWithPin": MessageLookupByLibrary.simpleMessage("Pair with PIN"), "pairingComplete": MessageLookupByLibrary.simpleMessage("Pairing complete"), "panorama": MessageLookupByLibrary.simpleMessage("Panorama"), - "partyWithThem": m55, + "partyWithThem": m56, "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage( "Verification is still pending"), "passkey": MessageLookupByLibrary.simpleMessage("Passkey"), @@ -1425,7 +1474,7 @@ class MessageLookup extends MessageLookupByLibrary { "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage( "Password changed successfully"), "passwordLock": MessageLookupByLibrary.simpleMessage("Password lock"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "Password strength is calculated considering the length of the password, used characters, and whether or not the password appears in the top 10,000 most used passwords"), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -1437,7 +1486,7 @@ class MessageLookup extends MessageLookupByLibrary { "paymentFailed": MessageLookupByLibrary.simpleMessage("Payment failed"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Unfortunately your payment failed. Please contact support and we\'ll help you out!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("Pending items"), "pendingSync": MessageLookupByLibrary.simpleMessage("Pending sync"), "people": MessageLookupByLibrary.simpleMessage("People"), @@ -1451,21 +1500,21 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Permanently delete"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage( "Permanently delete from device?"), - "personIsAge": m58, + "personIsAge": m59, "personName": MessageLookupByLibrary.simpleMessage("Person name"), - "personTurningAge": m59, + "personTurningAge": m60, "pets": MessageLookupByLibrary.simpleMessage("Furry companions"), "photoDescriptions": MessageLookupByLibrary.simpleMessage("Photo descriptions"), "photoGridSize": MessageLookupByLibrary.simpleMessage("Photo grid size"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("photo"), - "photocountPhotos": m60, + "photocountPhotos": m61, "photos": MessageLookupByLibrary.simpleMessage("Photos"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage( "Photos added by you will be removed from the album"), - "photosCount": m61, + "photosCount": m62, "photosKeepRelativeTimeDifference": MessageLookupByLibrary.simpleMessage( "Photos keep relative time difference"), @@ -1475,7 +1524,7 @@ class MessageLookup extends MessageLookupByLibrary { "pinLock": MessageLookupByLibrary.simpleMessage("PIN lock"), "playOnTv": MessageLookupByLibrary.simpleMessage("Play album on TV"), "playOriginal": MessageLookupByLibrary.simpleMessage("Play original"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playStream": MessageLookupByLibrary.simpleMessage("Play stream"), "playstoreSubscription": MessageLookupByLibrary.simpleMessage("PlayStore subscription"), @@ -1488,14 +1537,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Please contact support if the problem persists"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage("Please grant permissions"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Please login again"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Please select quick links to remove"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Please try again"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1509,7 +1558,7 @@ class MessageLookup extends MessageLookupByLibrary { "Please wait for sometime before retrying"), "pleaseWaitThisWillTakeAWhile": MessageLookupByLibrary.simpleMessage( "Please wait, this will take a while."), - "posingWithThem": m65, + "posingWithThem": m66, "preparingLogs": MessageLookupByLibrary.simpleMessage("Preparing logs..."), "preserveMore": MessageLookupByLibrary.simpleMessage("Preserve more"), @@ -1528,24 +1577,27 @@ class MessageLookup extends MessageLookupByLibrary { "proceed": MessageLookupByLibrary.simpleMessage("Proceed"), "processed": MessageLookupByLibrary.simpleMessage("Processed"), "processing": MessageLookupByLibrary.simpleMessage("Processing"), - "processingImport": m66, + "processingImport": m67, "processingVideos": MessageLookupByLibrary.simpleMessage("Processing videos"), "publicLinkCreated": MessageLookupByLibrary.simpleMessage("Public link created"), "publicLinkEnabled": MessageLookupByLibrary.simpleMessage("Public link enabled"), + "questionmark": MessageLookupByLibrary.simpleMessage("?"), "queued": MessageLookupByLibrary.simpleMessage("Queued"), "quickLinks": MessageLookupByLibrary.simpleMessage("Quick links"), "radius": MessageLookupByLibrary.simpleMessage("Radius"), "raiseTicket": MessageLookupByLibrary.simpleMessage("Raise ticket"), "rateTheApp": MessageLookupByLibrary.simpleMessage("Rate the app"), "rateUs": MessageLookupByLibrary.simpleMessage("Rate us"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "reassignMe": MessageLookupByLibrary.simpleMessage("Reassign \"Me\""), - "reassignedToName": m68, + "reassignedToName": m69, "reassigningLoading": MessageLookupByLibrary.simpleMessage("Reassigning..."), + "receiveRemindersOnBirthdays": MessageLookupByLibrary.simpleMessage( + "Receive reminders when it\'s someone\'s birthday. Tapping on the notification will take you to photos of the birthday person."), "recover": MessageLookupByLibrary.simpleMessage("Recover"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Recover account"), @@ -1554,7 +1606,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Recover account"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage("Recovery initiated"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("Recovery key"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( "Recovery key copied to clipboard"), @@ -1568,12 +1620,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Recovery key verified"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "Your recovery key is the only way to recover your photos if you forget your password. You can find your recovery key in Settings > Account.\n\nPlease enter your recovery key here to verify that you have saved it correctly."), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage("Recovery successful!"), "recoveryWarning": MessageLookupByLibrary.simpleMessage( "A trusted contact is trying to access your account"), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "The current device is not powerful enough to verify your password, but we can regenerate in a way that works with all devices.\n\nPlease login using your recovery key and regenerate your password (you can use the same one again if you wish)."), "recreatePasswordTitle": @@ -1588,7 +1640,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Give this code to your friends"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. They sign up for a paid plan"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("Referrals"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Referrals are currently paused"), @@ -1617,7 +1669,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Remove link"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Remove participant"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Remove person label"), "removePublicLink": @@ -1637,10 +1689,11 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("Rename file"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Renew subscription"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Report a bug"), "reportBug": MessageLookupByLibrary.simpleMessage("Report bug"), "resendEmail": MessageLookupByLibrary.simpleMessage("Resend email"), + "reset": MessageLookupByLibrary.simpleMessage("Reset"), "resetIgnoredFiles": MessageLookupByLibrary.simpleMessage("Reset ignored files"), "resetPasswordTitle": @@ -1662,12 +1715,16 @@ class MessageLookup extends MessageLookupByLibrary { "reviewSuggestions": MessageLookupByLibrary.simpleMessage("Review suggestions"), "right": MessageLookupByLibrary.simpleMessage("Right"), - "roadtripWithThem": m75, + "roadtripWithThem": m76, "rotate": MessageLookupByLibrary.simpleMessage("Rotate"), "rotateLeft": MessageLookupByLibrary.simpleMessage("Rotate left"), "rotateRight": MessageLookupByLibrary.simpleMessage("Rotate right"), "safelyStored": MessageLookupByLibrary.simpleMessage("Safely stored"), + "same": MessageLookupByLibrary.simpleMessage("Same"), + "sameperson": MessageLookupByLibrary.simpleMessage("Same person?"), "save": MessageLookupByLibrary.simpleMessage("Save"), + "saveAsAnotherPerson": + MessageLookupByLibrary.simpleMessage("Save as another person"), "saveChangesBeforeLeavingQuestion": MessageLookupByLibrary.simpleMessage( "Save changes before leaving?"), @@ -1716,8 +1773,8 @@ class MessageLookup extends MessageLookupByLibrary { "Invite people, and you\'ll see all photos shared by them here"), "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage( "People will be shown here once processing and syncing is complete"), - "searchResultCount": m76, - "searchSectionsLengthMismatch": m77, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("Security"), "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage( "See public album links in app"), @@ -1755,7 +1812,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Select your face"), "selectYourPlan": MessageLookupByLibrary.simpleMessage("Select your plan"), - "selectedAlbums": m117, + "selectedAlbums": m79, "selectedFilesAreNotOnEnte": MessageLookupByLibrary.simpleMessage( "Selected files are not on Ente"), "selectedFoldersWillBeEncryptedAndBackedUp": @@ -1767,9 +1824,9 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeRemovedFromThisPerson": MessageLookupByLibrary.simpleMessage( "Selected items will be removed from this person, but not deleted from your library."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, - "selfiesWithThem": m80, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, + "selfiesWithThem": m82, "send": MessageLookupByLibrary.simpleMessage("Send"), "sendEmail": MessageLookupByLibrary.simpleMessage("Send email"), "sendInvite": MessageLookupByLibrary.simpleMessage("Send invite"), @@ -1798,16 +1855,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Share an album now"), "shareLink": MessageLookupByLibrary.simpleMessage("Share link"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Share only with the people you want"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Download Ente so we can easily share original quality photos and videos\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage("Share with non-Ente users"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage("Share your first album"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1818,14 +1875,18 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("New shared photos"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "Receive notifications when someone adds a photo to a shared album that you\'re a part of"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Shared with me"), "sharedWithYou": MessageLookupByLibrary.simpleMessage("Shared with you"), "sharing": MessageLookupByLibrary.simpleMessage("Sharing..."), "shiftDatesAndTime": MessageLookupByLibrary.simpleMessage("Shift dates and time"), + "showLessFaces": + MessageLookupByLibrary.simpleMessage("Show less faces"), "showMemories": MessageLookupByLibrary.simpleMessage("Show memories"), + "showMoreFaces": + MessageLookupByLibrary.simpleMessage("Show more faces"), "showPerson": MessageLookupByLibrary.simpleMessage("Show person"), "signOutFromOtherDevices": MessageLookupByLibrary.simpleMessage("Sign out from other devices"), @@ -1835,11 +1896,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Sign out other devices"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "I agree to the terms of service and privacy policy"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "It will be deleted from all albums."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("Skip"), "smartMemories": MessageLookupByLibrary.simpleMessage("Smart memories"), "social": MessageLookupByLibrary.simpleMessage("Social"), @@ -1878,8 +1939,8 @@ class MessageLookup extends MessageLookupByLibrary { "sortNewestFirst": MessageLookupByLibrary.simpleMessage("Newest first"), "sortOldestFirst": MessageLookupByLibrary.simpleMessage("Oldest first"), "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ Success"), - "sportsWithThem": m89, - "spotlightOnThem": m90, + "sportsWithThem": m91, + "spotlightOnThem": m92, "spotlightOnYourself": MessageLookupByLibrary.simpleMessage("Spotlight on yourself"), "startAccountRecoveryTitle": @@ -1893,14 +1954,14 @@ class MessageLookup extends MessageLookupByLibrary { "storage": MessageLookupByLibrary.simpleMessage("Storage"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Family"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("You"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage("Storage limit exceeded"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "streamDetails": MessageLookupByLibrary.simpleMessage("Stream details"), "strongStrength": MessageLookupByLibrary.simpleMessage("Strong"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("Subscribe"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "You need an active paid subscription to enable sharing."), @@ -1918,7 +1979,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Suggest features"), "sunrise": MessageLookupByLibrary.simpleMessage("On the horizon"), "support": MessageLookupByLibrary.simpleMessage("Support"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("Sync stopped"), "syncing": MessageLookupByLibrary.simpleMessage("Syncing..."), "systemTheme": MessageLookupByLibrary.simpleMessage("System"), @@ -1927,7 +1988,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Tap to enter code"), "tapToUnlock": MessageLookupByLibrary.simpleMessage("Tap to unlock"), "tapToUpload": MessageLookupByLibrary.simpleMessage("Tap to upload"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "It looks like something went wrong. Please retry after some time. If the error persists, please contact our support team."), "terminate": MessageLookupByLibrary.simpleMessage("Terminate"), @@ -1943,6 +2004,10 @@ class MessageLookup extends MessageLookupByLibrary { "theLinkYouAreTryingToAccessHasExpired": MessageLookupByLibrary.simpleMessage( "The link you are trying to access has expired."), + "thePersonGroupsWillNotBeDisplayed": MessageLookupByLibrary.simpleMessage( + "The person groups will not be displayed in the people section anymore. Photos will remain untouched."), + "thePersonWillNotBeDisplayed": MessageLookupByLibrary.simpleMessage( + "The person will not be displayed in the people section anymore. Photos will remain untouched."), "theRecoveryKeyYouEnteredIsIncorrect": MessageLookupByLibrary.simpleMessage( "The recovery key you entered is incorrect"), @@ -1950,7 +2015,7 @@ class MessageLookup extends MessageLookupByLibrary { "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage( "These items will be deleted from your device."), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage( "They will be deleted from all albums."), "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( @@ -1968,12 +2033,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("This image has no exif data"), "thisIsMeExclamation": MessageLookupByLibrary.simpleMessage("This is me!"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( "This is your Verification ID"), "thisWeekThroughTheYears": MessageLookupByLibrary.simpleMessage("This week through the years"), - "thisWeekXYearsAgo": m99, + "thisWeekXYearsAgo": m101, "thisWillLogYouOutOfTheFollowingDevice": MessageLookupByLibrary.simpleMessage( "This will log you out of the following device:"), @@ -1985,7 +2050,7 @@ class MessageLookup extends MessageLookupByLibrary { "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( "This will remove public links of all selected quick links."), - "throughTheYears": m100, + "throughTheYears": m102, "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": MessageLookupByLibrary.simpleMessage( "To enable app lock, please setup device passcode or screen lock in your system settings."), @@ -1999,13 +2064,13 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("total"), "totalSize": MessageLookupByLibrary.simpleMessage("Total size"), "trash": MessageLookupByLibrary.simpleMessage("Trash"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("Trim"), - "tripInYear": m102, - "tripToLocation": m103, + "tripInYear": m104, + "tripToLocation": m105, "trustedContacts": MessageLookupByLibrary.simpleMessage("Trusted contacts"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("Try again"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "Turn on backup to automatically upload files added to this device folder to Ente."), @@ -2023,7 +2088,7 @@ class MessageLookup extends MessageLookupByLibrary { "Two-factor authentication successfully reset"), "twofactorSetup": MessageLookupByLibrary.simpleMessage("Two-factor setup"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("Unarchive"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("Unarchive album"), @@ -2046,10 +2111,10 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage( "Updating folder selection..."), "upgrade": MessageLookupByLibrary.simpleMessage("Upgrade"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage("Uploading files to album..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage("Preserving 1 memory..."), "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( @@ -2067,7 +2132,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("Use selected photo"), "usedSpace": MessageLookupByLibrary.simpleMessage("Used space"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Verification failed, please try again"), @@ -2075,7 +2140,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Verification ID"), "verify": MessageLookupByLibrary.simpleMessage("Verify"), "verifyEmail": MessageLookupByLibrary.simpleMessage("Verify email"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Verify"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("Verify passkey"), "verifyPassword": @@ -2098,11 +2163,11 @@ class MessageLookup extends MessageLookupByLibrary { "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( "View files that are consuming the most amount of storage."), "viewLogs": MessageLookupByLibrary.simpleMessage("View logs"), - "viewPersonToUnlink": m110, + "viewPersonToUnlink": m112, "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("View recovery key"), "viewer": MessageLookupByLibrary.simpleMessage("Viewer"), - "viewersSuccessfullyAdded": m111, + "viewersSuccessfullyAdded": m113, "visitWebToManage": MessageLookupByLibrary.simpleMessage( "Please visit web.ente.io to manage your subscription"), "waitingForVerification": @@ -2115,16 +2180,17 @@ class MessageLookup extends MessageLookupByLibrary { "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "We don\'t support editing photos and albums that you don\'t own yet"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Weak"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Welcome back!"), "whatsNew": MessageLookupByLibrary.simpleMessage("What\'s new"), "whyAddTrustContact": MessageLookupByLibrary.simpleMessage( "Trusted contact can help in recovering your data."), "widgets": MessageLookupByLibrary.simpleMessage("Widgets"), + "wishThemAHappyBirthday": m115, "yearShort": MessageLookupByLibrary.simpleMessage("yr"), "yearly": MessageLookupByLibrary.simpleMessage("Yearly"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Yes"), "yesCancel": MessageLookupByLibrary.simpleMessage("Yes, cancel"), "yesConvertToViewer": @@ -2132,13 +2198,14 @@ class MessageLookup extends MessageLookupByLibrary { "yesDelete": MessageLookupByLibrary.simpleMessage("Yes, delete"), "yesDiscardChanges": MessageLookupByLibrary.simpleMessage("Yes, discard changes"), + "yesIgnore": MessageLookupByLibrary.simpleMessage("Yes, ignore"), "yesLogout": MessageLookupByLibrary.simpleMessage("Yes, logout"), "yesRemove": MessageLookupByLibrary.simpleMessage("Yes, remove"), "yesRenew": MessageLookupByLibrary.simpleMessage("Yes, Renew"), "yesResetPerson": MessageLookupByLibrary.simpleMessage("Yes, reset person"), "you": MessageLookupByLibrary.simpleMessage("You"), - "youAndThem": m114, + "youAndThem": m117, "youAreOnAFamilyPlan": MessageLookupByLibrary.simpleMessage("You are on a family plan!"), "youAreOnTheLatestVersion": MessageLookupByLibrary.simpleMessage( @@ -2157,7 +2224,7 @@ class MessageLookup extends MessageLookupByLibrary { "You cannot share with yourself"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( "You don\'t have any archived items."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage( "Your account has been deleted"), "yourMap": MessageLookupByLibrary.simpleMessage("Your map"), diff --git a/mobile/lib/generated/intl/messages_es.dart b/mobile/lib/generated/intl/messages_es.dart index d86efb0d78..50d2340bf9 100644 --- a/mobile/lib/generated/intl/messages_es.dart +++ b/mobile/lib/generated/intl/messages_es.dart @@ -85,240 +85,242 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'Elimina ${count} elemento', other: 'Elimina ${count} elementos')}"; - static String m22(currentlyDeleting, totalCount) => + static String m23(currentlyDeleting, totalCount) => "Borrando ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "Esto eliminará el enlace público para acceder a \"${albumName}\"."; - static String m24(supportEmail) => + static String m25(supportEmail) => "Por favor, envía un correo electrónico a ${supportEmail} desde tu dirección de correo electrónico que usó para registrarse"; - static String m25(count, storageSaved) => + static String m26(count, storageSaved) => "¡Has limpiado ${Intl.plural(count, one: '${count} archivo duplicado', other: '${count} archivos duplicados')}, ahorrando (${storageSaved}!)"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} archivos, ${formattedSize} cada uno"; - static String m28(newEmail) => "Correo cambiado a ${newEmail}"; + static String m29(newEmail) => "Correo cambiado a ${newEmail}"; - static String m29(email) => "${email} no tiene una cuenta de Ente."; + static String m30(email) => "${email} no tiene una cuenta de Ente."; - static String m30(email) => + static String m31(email) => "${email} no tiene una cuente en Ente.\n\nEnvíale una invitación para compartir fotos."; - static String m31(name) => "Abrazando a ${name}"; + static String m32(name) => "Abrazando a ${name}"; - static String m32(text) => "Fotos adicionales encontradas para ${text}"; + static String m33(text) => "Fotos adicionales encontradas para ${text}"; - static String m33(name) => "Festejando con ${name}"; - - static String m34(count, formattedNumber) => - "Se ha realizado la copia de seguridad de ${Intl.plural(count, one: '1 archivo', other: '${formattedNumber} archivos')} de este dispositivo de forma segura"; + static String m34(name) => "Festejando con ${name}"; static String m35(count, formattedNumber) => + "Se ha realizado la copia de seguridad de ${Intl.plural(count, one: '1 archivo', other: '${formattedNumber} archivos')} de este dispositivo de forma segura"; + + static String m36(count, formattedNumber) => "Se ha realizado la copia de seguridad de ${Intl.plural(count, one: '1 archivo', other: '${formattedNumber} archivos')} de este álbum de forma segura"; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "${storageAmountInGB} GB cada vez que alguien se registra en un plan de pago y aplica tu código"; - static String m37(endDate) => "Prueba gratuita válida hasta ${endDate}"; + static String m38(endDate) => "Prueba gratuita válida hasta ${endDate}"; - static String m38(count) => + static String m39(count) => "Aún puedes acceder ${Intl.plural(count, one: 'a él', other: 'a ellos')} en Ente mientras tengas una suscripción activa"; - static String m39(sizeInMBorGB) => "Liberar ${sizeInMBorGB}"; + static String m40(sizeInMBorGB) => "Liberar ${sizeInMBorGB}"; - static String m40(count, formattedSize) => + static String m41(count, formattedSize) => "${Intl.plural(count, one: 'Se puede eliminar del dispositivo para liberar ${formattedSize}', other: 'Se pueden eliminar del dispositivo para liberar ${formattedSize}')}"; - static String m41(currentlyProcessing, totalCount) => + static String m42(currentlyProcessing, totalCount) => "Procesando ${currentlyProcessing} / ${totalCount}"; - static String m42(name) => "Senderismo con ${name}"; + static String m43(name) => "Senderismo con ${name}"; - static String m43(count) => + static String m44(count) => "${Intl.plural(count, one: '${count} elemento', other: '${count} elementos')}"; - static String m44(name) => "Última vez con ${name}"; + static String m45(name) => "Última vez con ${name}"; - static String m45(email) => + static String m46(email) => "${email} te ha invitado a ser un contacto de confianza"; - static String m46(expiryTime) => "El enlace caducará en ${expiryTime}"; + static String m47(expiryTime) => "El enlace caducará en ${expiryTime}"; - static String m47(email) => "Enlazar persona a ${email}"; + static String m48(email) => "Enlazar persona a ${email}"; - static String m48(personName, email) => + static String m49(personName, email) => "Esto enlazará a ${personName} a ${email}"; - static String m49(count, formattedCount) => + static String m50(count, formattedCount) => "${Intl.plural(count, zero: 'no hay recuerdos', one: '${formattedCount} recuerdo', other: '${formattedCount} recuerdos')}"; - static String m50(count) => + static String m51(count) => "${Intl.plural(count, one: 'Mover objeto', other: 'Mover objetos')}"; - static String m51(albumName) => "Movido exitosamente a ${albumName}"; + static String m52(albumName) => "Movido exitosamente a ${albumName}"; - static String m52(personName) => "No hay sugerencias para ${personName}"; + static String m53(personName) => "No hay sugerencias para ${personName}"; - static String m53(name) => "¿No es ${name}?"; + static String m54(name) => "¿No es ${name}?"; - static String m54(familyAdminEmail) => + static String m55(familyAdminEmail) => "Por favor, contacta a ${familyAdminEmail} para cambiar tu código."; - static String m55(name) => "Fiesta con ${name}"; + static String m56(name) => "Fiesta con ${name}"; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Seguridad de la contraseña: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "Por favor, habla con el soporte de ${providerName} si se te cobró"; - static String m58(name, age) => "¡${name} tiene ${age} años!"; + static String m59(name, age) => "¡${name} tiene ${age} años!"; - static String m59(name, age) => "${name} cumpliendo ${age} pronto"; - - static String m60(count) => - "${Intl.plural(count, zero: 'No hay fotos', one: '1 foto', other: '${count} fotos')}"; + static String m60(name, age) => "${name} cumpliendo ${age} pronto"; static String m61(count) => + "${Intl.plural(count, zero: 'No hay fotos', one: '1 foto', other: '${count} fotos')}"; + + static String m62(count) => "${Intl.plural(count, zero: '0 fotos', one: '1 foto', other: '${count} fotos')}"; - static String m62(endDate) => + static String m63(endDate) => "Prueba gratuita válida hasta ${endDate}.\nPuedes elegir un plan de pago después."; - static String m63(toEmail) => + static String m64(toEmail) => "Por favor, envíanos un correo electrónico a ${toEmail}"; - static String m64(toEmail) => "Por favor, envía los registros a ${toEmail}"; + static String m65(toEmail) => "Por favor, envía los registros a ${toEmail}"; - static String m65(name) => "Posando con ${name}"; + static String m66(name) => "Posando con ${name}"; - static String m66(folderName) => "Procesando ${folderName}..."; + static String m67(folderName) => "Procesando ${folderName}..."; - static String m67(storeName) => "Puntúanos en ${storeName}"; + static String m68(storeName) => "Puntúanos en ${storeName}"; - static String m68(name) => "Te has reasignado a ${name}"; + static String m69(name) => "Te has reasignado a ${name}"; - static String m69(days, email) => + static String m70(days, email) => "Puedes acceder a la cuenta después de ${days} días. Se enviará una notificación a ${email}."; - static String m70(email) => + static String m71(email) => "Ahora puedes recuperar la cuenta de ${email} estableciendo una nueva contraseña."; - static String m71(email) => "${email} está intentando recuperar tu cuenta."; + static String m72(email) => "${email} está intentando recuperar tu cuenta."; - static String m72(storageInGB) => + static String m73(storageInGB) => "3. Ambos obtienen ${storageInGB} GB* gratis"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} será eliminado de este álbum compartido\n\nCualquier foto añadida por ellos también será eliminada del álbum"; - static String m74(endDate) => "La suscripción se renueva el ${endDate}"; + static String m75(endDate) => "La suscripción se renueva el ${endDate}"; - static String m75(name) => "Viaje en carretera con ${name}"; + static String m76(name) => "Viaje en carretera con ${name}"; - static String m76(count) => + static String m77(count) => "${Intl.plural(count, one: '${count} resultado encontrado', other: '${count} resultados encontrados')}"; - static String m77(snapshotLength, searchLength) => + static String m78(snapshotLength, searchLength) => "La longitud de las secciones no coincide: ${snapshotLength} != ${searchLength}"; - static String m78(count) => "${count} seleccionados"; + static String m80(count) => "${count} seleccionados"; - static String m79(count, yourCount) => + static String m81(count, yourCount) => "${count} seleccionados (${yourCount} tuyos)"; - static String m80(name) => "Selfies con ${name}"; + static String m82(name) => "Selfies con ${name}"; - static String m81(verificationID) => + static String m83(verificationID) => "Aquí está mi ID de verificación: ${verificationID} para ente.io."; - static String m82(verificationID) => + static String m84(verificationID) => "Hola, ¿puedes confirmar que esta es tu ID de verificación ente.io: ${verificationID}?"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Código de referido de Ente: ${referralCode} \n\nAñádelo en Ajustes → General → Referidos para obtener ${referralStorageInGB} GB gratis tras comprar un plan de pago.\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Compartir con personas específicas', one: 'Compartido con 1 persona', other: 'Compartido con ${numberOfPeople} personas')}"; - static String m85(emailIDs) => "Compartido con ${emailIDs}"; + static String m87(emailIDs) => "Compartido con ${emailIDs}"; - static String m86(fileType) => + static String m88(fileType) => "Este ${fileType} se eliminará de tu dispositivo."; - static String m87(fileType) => + static String m89(fileType) => "Este ${fileType} está tanto en Ente como en tu dispositivo."; - static String m88(fileType) => "Este ${fileType} será eliminado de Ente."; + static String m90(fileType) => "Este ${fileType} será eliminado de Ente."; - static String m89(name) => "Deportes con ${name}"; + static String m91(name) => "Deportes con ${name}"; - static String m90(name) => "Enfocar a ${name}"; + static String m92(name) => "Enfocar a ${name}"; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} de ${totalAmount} ${totalStorageUnit} usados"; - static String m93(id) => + static String m95(id) => "Tu ${id} ya está vinculada a otra cuenta de Ente.\nSi deseas utilizar tu ${id} con esta cuenta, ponte en contacto con nuestro servicio de asistencia\'\'"; - static String m94(endDate) => "Tu suscripción se cancelará el ${endDate}"; + static String m96(endDate) => "Tu suscripción se cancelará el ${endDate}"; - static String m95(completed, total) => + static String m97(completed, total) => "${completed}/${total} recuerdos conservados"; - static String m96(ignoreReason) => + static String m98(ignoreReason) => "Toca para subir, la subida se está ignorando debido a ${ignoreReason}"; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "También obtienen ${storageAmountInGB} GB"; - static String m98(email) => "Este es el ID de verificación de ${email}"; - - static String m99(count) => - "${Intl.plural(count, one: 'Esta semana, hace ${count} año', other: 'Esta semana, hace ${count} años')}"; - - static String m100(dateFormat) => "${dateFormat} a través de los años"; + static String m100(email) => "Este es el ID de verificación de ${email}"; static String m101(count) => + "${Intl.plural(count, one: 'Esta semana, hace ${count} año', other: 'Esta semana, hace ${count} años')}"; + + static String m102(dateFormat) => "${dateFormat} a través de los años"; + + static String m103(count) => "${Intl.plural(count, zero: 'Pronto', one: '1 día', other: '${count} días')}"; - static String m102(year) => "Viaje en ${year}"; + static String m104(year) => "Viaje en ${year}"; - static String m103(location) => "Viaje a ${location}"; + static String m105(location) => "Viaje a ${location}"; - static String m104(email) => + static String m106(email) => "Has sido invitado a ser un contacto legado por ${email}."; - static String m105(galleryType) => + static String m107(galleryType) => "El tipo de galería ${galleryType} no es compatible con el renombrado"; - static String m106(ignoreReason) => + static String m108(ignoreReason) => "La subida se ignoró debido a ${ignoreReason}"; - static String m107(count) => "Preservando ${count} memorias..."; + static String m109(count) => "Preservando ${count} memorias..."; - static String m108(endDate) => "Válido hasta ${endDate}"; + static String m110(endDate) => "Válido hasta ${endDate}"; - static String m109(email) => "Verificar ${email}"; - - static String m111(count) => - "${Intl.plural(count, zero: '0 espectadores añadidos', one: '1 espectador añadido', other: '${count} espectadores añadidos')}"; - - static String m112(email) => - "Hemos enviado un correo a ${email}"; + static String m111(email) => "Verificar ${email}"; static String m113(count) => + "${Intl.plural(count, zero: '0 espectadores añadidos', one: '1 espectador añadido', other: '${count} espectadores añadidos')}"; + + static String m114(email) => + "Hemos enviado un correo a ${email}"; + + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + + static String m116(count) => "${Intl.plural(count, one: 'Hace ${count} año', other: 'Hace ${count} años')}"; - static String m114(name) => "Tú y ${name}"; + static String m117(name) => "Tú y ${name}"; - static String m115(storageSaved) => + static String m118(storageSaved) => "¡Has liberado ${storageSaved} con éxito!"; final messages = _notInlinedMessages(_notInlinedMessages); @@ -552,6 +554,30 @@ class MessageLookup extends MessageLookupByLibrary { "blackFridaySale": MessageLookupByLibrary.simpleMessage("Oferta del Black Friday"), "blog": MessageLookupByLibrary.simpleMessage("Blog"), + "cLDesc1": MessageLookupByLibrary.simpleMessage( + "Tras el lanzamiento de la versión beta de transmisión de video y el trabajo en subidas y descargas reanudables, ahora hemos aumentado el límite de subida de archivos a 10GB. Esto ya está disponible tanto en aplicaciones de escritorio como móviles."), + "cLDesc2": MessageLookupByLibrary.simpleMessage( + "Las subidas en segundo plano ahora también son compatibles con iOS, además de dispositivos Android. No necesitas abrir la aplicación para hacer una copia de seguridad de tus fotos y videos más recientes."), + "cLDesc3": MessageLookupByLibrary.simpleMessage( + "Hemos hecho mejoras significativas en nuestra experiencia de recuerdos, incluyendo reproducción automática, deslizar al siguiente recuerdo y mucho más."), + "cLDesc4": MessageLookupByLibrary.simpleMessage( + "Junto con un montón de mejoras internas, ahora es mucho más fácil ver todas las caras detectadas, proporcionar comentarios sobre caras similares y agregar/eliminar caras de una sola foto."), + "cLDesc5": MessageLookupByLibrary.simpleMessage( + "Ahora recibirás una notificación opcional para todos los cumpleaños que hayas guardado en Ente, junto con una colección de sus mejores fotos."), + "cLDesc6": MessageLookupByLibrary.simpleMessage( + "No más esperas para que se completen las subidas/descargas antes de poder cerrar la aplicación. Todas las subidas y descargas ahora tienen la capacidad de pausarse a mitad de camino y reanudarse desde donde lo dejaste."), + "cLTitle1": MessageLookupByLibrary.simpleMessage( + "Subida de archivos de video grandes"), + "cLTitle2": + MessageLookupByLibrary.simpleMessage("Subida en segundo plano"), + "cLTitle3": MessageLookupByLibrary.simpleMessage( + "Reproducción automática de recuerdos"), + "cLTitle4": MessageLookupByLibrary.simpleMessage( + "Reconocimiento facial mejorado"), + "cLTitle5": MessageLookupByLibrary.simpleMessage( + "Notificaciones de cumpleaños"), + "cLTitle6": MessageLookupByLibrary.simpleMessage( + "Subidas y descargas reanudables"), "cachedData": MessageLookupByLibrary.simpleMessage("Datos almacenados en caché"), "calculating": MessageLookupByLibrary.simpleMessage("Calculando..."), @@ -622,8 +648,6 @@ class MessageLookup extends MessageLookupByLibrary { "click": MessageLookupByLibrary.simpleMessage("• Clic"), "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage( "• Haga clic en el menú desbordante"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "close": MessageLookupByLibrary.simpleMessage("Cerrar"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage( "Agrupar por tiempo de captura"), @@ -773,7 +797,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Borrar la ubicación"), "deletePhotos": MessageLookupByLibrary.simpleMessage("Borrar las fotos"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Falta una función clave que necesito"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -814,7 +838,7 @@ class MessageLookup extends MessageLookupByLibrary { "Los espectadores todavía pueden tomar capturas de pantalla o guardar una copia de tus fotos usando herramientas externas"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Por favor, ten en cuenta"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage("Deshabilitar dos factores"), "disablingTwofactorAuthentication": @@ -858,9 +882,9 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("Descarga fallida"), "downloading": MessageLookupByLibrary.simpleMessage("Descargando..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("Editar"), "editLocation": MessageLookupByLibrary.simpleMessage("Editar la ubicación"), @@ -877,16 +901,16 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("Correo electrónico"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage( "Correo electrónico ya registrado."), - "emailChangedTo": m28, - "emailDoesNotHaveEnteAccount": m29, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailDoesNotHaveEnteAccount": m30, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage( "Correo electrónico no registrado."), "emailVerificationToggle": MessageLookupByLibrary.simpleMessage( "Verificación por correo electrónico"), "emailYourLogs": MessageLookupByLibrary.simpleMessage( "Envía tus registros por correo electrónico"), - "embracingThem": m31, + "embracingThem": m32, "emergencyContacts": MessageLookupByLibrary.simpleMessage("Contactos de emergencia"), "empty": MessageLookupByLibrary.simpleMessage("Vaciar"), @@ -968,7 +992,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Exportar tus datos"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage( "Fotos adicionales encontradas"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage( "Cara no agrupada todavía, por favor vuelve más tarde"), "faceRecognition": @@ -1007,7 +1031,7 @@ class MessageLookup extends MessageLookupByLibrary { "faq": MessageLookupByLibrary.simpleMessage("Preguntas Frecuentes"), "faqs": MessageLookupByLibrary.simpleMessage("Preguntas frecuentes"), "favorite": MessageLookupByLibrary.simpleMessage("Favorito"), - "feastingWithThem": m33, + "feastingWithThem": m34, "feedback": MessageLookupByLibrary.simpleMessage("Sugerencias"), "file": MessageLookupByLibrary.simpleMessage("Archivo"), "fileFailedToSaveToGallery": MessageLookupByLibrary.simpleMessage( @@ -1021,8 +1045,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Tipos de archivos"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Tipos de archivo y nombres"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("Archivos eliminados"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage( @@ -1040,26 +1064,26 @@ class MessageLookup extends MessageLookupByLibrary { "foundFaces": MessageLookupByLibrary.simpleMessage("Caras encontradas"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage( "Almacenamiento gratuito obtenido"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage( "Almacenamiento libre disponible"), "freeTrial": MessageLookupByLibrary.simpleMessage("Prueba gratuita"), - "freeTrialValidTill": m37, - "freeUpAccessPostDelete": m38, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAccessPostDelete": m39, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage( "Liberar espacio del dispositivo"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Ahorra espacio en tu dispositivo limpiando archivos que tienen copia de seguridad."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Liberar espacio"), - "freeUpSpaceSaving": m40, + "freeUpSpaceSaving": m41, "gallery": MessageLookupByLibrary.simpleMessage("Galería"), "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Hasta 1000 memorias mostradas en la galería"), "general": MessageLookupByLibrary.simpleMessage("General"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Generando claves de cifrado..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("Ir a Ajustes"), "googlePlayId": MessageLookupByLibrary.simpleMessage("ID de Google Play"), @@ -1089,7 +1113,7 @@ class MessageLookup extends MessageLookupByLibrary { "hideSharedItemsFromHomeGallery": MessageLookupByLibrary.simpleMessage( "Ocultar elementos compartidos de la galería de inicio"), "hiding": MessageLookupByLibrary.simpleMessage("Ocultando..."), - "hikingWithThem": m42, + "hikingWithThem": m43, "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("Alojado en OSM France"), "howItWorks": MessageLookupByLibrary.simpleMessage("Cómo funciona"), @@ -1146,7 +1170,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Parece que algo salió mal. Por favor, vuelve a intentarlo después de algún tiempo. Si el error persiste, ponte en contacto con nuestro equipo de soporte."), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Los artículos muestran el número de días restantes antes de ser borrados permanente"), @@ -1167,7 +1191,7 @@ class MessageLookup extends MessageLookupByLibrary { "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( "Por favor ayúdanos con esta información"), "language": MessageLookupByLibrary.simpleMessage("Idioma"), - "lastTimeWithThem": m44, + "lastTimeWithThem": m45, "lastUpdated": MessageLookupByLibrary.simpleMessage("Última actualización"), "lastYearsTrip": @@ -1182,7 +1206,7 @@ class MessageLookup extends MessageLookupByLibrary { "legacy": MessageLookupByLibrary.simpleMessage("Legado"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("Cuentas legadas"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage( "Legado permite a los contactos de confianza acceder a su cuenta en su ausencia."), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( @@ -1200,7 +1224,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("para compartir más rápido"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Habilitado"), "linkExpired": MessageLookupByLibrary.simpleMessage("Vencido"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Enlace vence"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("El enlace ha caducado"), @@ -1208,8 +1232,8 @@ class MessageLookup extends MessageLookupByLibrary { "linkPerson": MessageLookupByLibrary.simpleMessage("Vincular persona"), "linkPersonCaption": MessageLookupByLibrary.simpleMessage( "para una mejor experiencia compartida"), - "linkPersonToEmail": m47, - "linkPersonToEmailConfirmation": m48, + "linkPersonToEmail": m48, + "linkPersonToEmailConfirmation": m49, "livePhotos": MessageLookupByLibrary.simpleMessage("Foto en vivo"), "loadMessage1": MessageLookupByLibrary.simpleMessage( "Puedes compartir tu suscripción con tu familia"), @@ -1270,8 +1294,6 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Manten presionado un elemento para ver en pantalla completa"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "loopVideoOff": MessageLookupByLibrary.simpleMessage("Vídeo en bucle desactivado"), "loopVideoOn": @@ -1303,7 +1325,7 @@ class MessageLookup extends MessageLookupByLibrary { "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), "me": MessageLookupByLibrary.simpleMessage("Yo"), - "memoryCount": m49, + "memoryCount": m50, "merchandise": MessageLookupByLibrary.simpleMessage("Mercancías"), "mergeWithExisting": MessageLookupByLibrary.simpleMessage("Combinar con existente"), @@ -1335,13 +1357,13 @@ class MessageLookup extends MessageLookupByLibrary { "mostRecent": MessageLookupByLibrary.simpleMessage("Más reciente"), "mostRelevant": MessageLookupByLibrary.simpleMessage("Más relevante"), "mountains": MessageLookupByLibrary.simpleMessage("Sobre las colinas"), - "moveItem": m50, + "moveItem": m51, "moveSelectedPhotosToOneDate": MessageLookupByLibrary.simpleMessage( "Mover las fotos seleccionadas a una fecha"), "moveToAlbum": MessageLookupByLibrary.simpleMessage("Mover al álbum"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Mover al álbum oculto"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("Movido a la papelera"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1357,7 +1379,6 @@ class MessageLookup extends MessageLookupByLibrary { "newLocation": MessageLookupByLibrary.simpleMessage("Nueva localización"), "newPerson": MessageLookupByLibrary.simpleMessage("Nueva persona"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "newRange": MessageLookupByLibrary.simpleMessage("Nuevo rango"), "newToEnte": MessageLookupByLibrary.simpleMessage("Nuevo en Ente"), "newest": MessageLookupByLibrary.simpleMessage("Más reciente"), @@ -1396,10 +1417,10 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Sin resultados"), "noResultsFound": MessageLookupByLibrary.simpleMessage( "No se han encontrado resultados"), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage( "Bloqueo de sistema no encontrado"), - "notPersonLabel": m53, + "notPersonLabel": m54, "notThisPerson": MessageLookupByLibrary.simpleMessage("¿No es esta persona?"), "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( @@ -1413,10 +1434,7 @@ class MessageLookup extends MessageLookupByLibrary { "En ente"), "onTheRoad": MessageLookupByLibrary.simpleMessage("De nuevo en la carretera"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("Solo ellos"), "oops": MessageLookupByLibrary.simpleMessage("Ups"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( @@ -1447,7 +1465,7 @@ class MessageLookup extends MessageLookupByLibrary { "pairingComplete": MessageLookupByLibrary.simpleMessage("Emparejamiento completo"), "panorama": MessageLookupByLibrary.simpleMessage("Panorama"), - "partyWithThem": m55, + "partyWithThem": m56, "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage( "La verificación aún está pendiente"), "passkey": MessageLookupByLibrary.simpleMessage("Clave de acceso"), @@ -1458,7 +1476,7 @@ class MessageLookup extends MessageLookupByLibrary { "Contraseña cambiada correctamente"), "passwordLock": MessageLookupByLibrary.simpleMessage("Bloqueo con contraseña"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "La fortaleza de la contraseña se calcula teniendo en cuenta la longitud de la contraseña, los caracteres utilizados, y si la contraseña aparece o no en el top 10.000 de contraseñas más usadas"), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -1468,7 +1486,7 @@ class MessageLookup extends MessageLookupByLibrary { "paymentFailed": MessageLookupByLibrary.simpleMessage("Pago fallido"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Lamentablemente tu pago falló. Por favor, ¡contacta con el soporte técnico y te ayudaremos!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("Elementos pendientes"), "pendingSync": @@ -1482,22 +1500,22 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Borrar permanentemente"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage( "¿Eliminar permanentemente del dispositivo?"), - "personIsAge": m58, + "personIsAge": m59, "personName": MessageLookupByLibrary.simpleMessage("Nombre de la persona"), - "personTurningAge": m59, + "personTurningAge": m60, "pets": MessageLookupByLibrary.simpleMessage("Compañeros peludos"), "photoDescriptions": MessageLookupByLibrary.simpleMessage("Descripciones de fotos"), "photoGridSize": MessageLookupByLibrary.simpleMessage( "Tamaño de la cuadrícula de fotos"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("foto"), - "photocountPhotos": m60, + "photocountPhotos": m61, "photos": MessageLookupByLibrary.simpleMessage("Fotos"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage( "Las fotos añadidas por ti serán removidas del álbum"), - "photosCount": m61, + "photosCount": m62, "photosKeepRelativeTimeDifference": MessageLookupByLibrary.simpleMessage( "Las fotos mantienen una diferencia de tiempo relativa"), @@ -1509,7 +1527,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Reproducir álbum en TV"), "playOriginal": MessageLookupByLibrary.simpleMessage("Reproducir original"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playStream": MessageLookupByLibrary.simpleMessage("Reproducir transmisión"), "playstoreSubscription": @@ -1523,14 +1541,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Por favor, contacta a soporte técnico si el problema persiste"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage("Por favor, concede permiso"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage( "Por favor, vuelve a iniciar sesión"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Por favor, selecciona enlaces rápidos para eliminar"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Por favor, inténtalo nuevamente"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1545,7 +1563,7 @@ class MessageLookup extends MessageLookupByLibrary { "Por favor, espera un momento antes de volver a intentarlo"), "pleaseWaitThisWillTakeAWhile": MessageLookupByLibrary.simpleMessage( "Espera. Esto tardará un poco."), - "posingWithThem": m65, + "posingWithThem": m66, "preparingLogs": MessageLookupByLibrary.simpleMessage("Preparando registros..."), "preserveMore": MessageLookupByLibrary.simpleMessage("Preservar más"), @@ -1564,7 +1582,7 @@ class MessageLookup extends MessageLookupByLibrary { "proceed": MessageLookupByLibrary.simpleMessage("Continuar"), "processed": MessageLookupByLibrary.simpleMessage("Procesado"), "processing": MessageLookupByLibrary.simpleMessage("Procesando"), - "processingImport": m66, + "processingImport": m67, "processingVideos": MessageLookupByLibrary.simpleMessage("Procesando vídeos"), "publicLinkCreated": @@ -1578,9 +1596,9 @@ class MessageLookup extends MessageLookupByLibrary { "rateTheApp": MessageLookupByLibrary.simpleMessage("Evalúa la aplicación"), "rateUs": MessageLookupByLibrary.simpleMessage("Califícanos"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "reassignMe": MessageLookupByLibrary.simpleMessage("Reasignar \"Yo\""), - "reassignedToName": m68, + "reassignedToName": m69, "reassigningLoading": MessageLookupByLibrary.simpleMessage("Reasignando..."), "recover": MessageLookupByLibrary.simpleMessage("Recuperar"), @@ -1591,7 +1609,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Recuperar cuenta"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage("Recuperación iniciada"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("Clave de recuperación"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( @@ -1606,12 +1624,12 @@ class MessageLookup extends MessageLookupByLibrary { "Clave de recuperación verificada"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "Tu clave de recuperación es la única forma de recuperar tus fotos si olvidas tu contraseña. Puedes encontrar tu clave de recuperación en Ajustes > Cuenta.\n\nPor favor, introduce tu clave de recuperación aquí para verificar que la has guardado correctamente."), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage("¡Recuperación exitosa!"), "recoveryWarning": MessageLookupByLibrary.simpleMessage( "Un contacto de confianza está intentando acceder a tu cuenta"), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "El dispositivo actual no es lo suficientemente potente para verificar su contraseña, pero podemos regenerarla de una manera que funcione con todos los dispositivos.\n\nPor favor inicie sesión usando su clave de recuperación y regenere su contraseña (puede volver a utilizar la misma si lo desea)."), "recreatePasswordTitle": @@ -1626,7 +1644,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Dale este código a tus amigos"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Se suscriben a un plan de pago"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("Referidos"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Las referencias están actualmente en pausa"), @@ -1657,7 +1675,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Eliminar enlace"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Quitar participante"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage( "Eliminar etiqueta de persona"), "removePublicLink": @@ -1677,7 +1695,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("Renombrar archivo"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Renovar suscripción"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Reportar un error"), "reportBug": MessageLookupByLibrary.simpleMessage("Reportar error"), "resendEmail": @@ -1703,7 +1721,7 @@ class MessageLookup extends MessageLookupByLibrary { "reviewSuggestions": MessageLookupByLibrary.simpleMessage("Revisar sugerencias"), "right": MessageLookupByLibrary.simpleMessage("Derecha"), - "roadtripWithThem": m75, + "roadtripWithThem": m76, "rotate": MessageLookupByLibrary.simpleMessage("Girar"), "rotateLeft": MessageLookupByLibrary.simpleMessage("Girar a la izquierda"), @@ -1761,8 +1779,8 @@ class MessageLookup extends MessageLookupByLibrary { "Invita a gente y verás todas las fotos compartidas aquí"), "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage( "Las personas se mostrarán aquí cuando se complete el procesado y la sincronización"), - "searchResultCount": m76, - "searchSectionsLengthMismatch": m77, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("Seguridad"), "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage( "Ver enlaces del álbum público en la aplicación"), @@ -1813,9 +1831,9 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeRemovedFromThisPerson": MessageLookupByLibrary.simpleMessage( "Los elementos seleccionados se eliminarán de esta persona, pero no se eliminarán de tu biblioteca."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, - "selfiesWithThem": m80, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, + "selfiesWithThem": m82, "send": MessageLookupByLibrary.simpleMessage("Enviar"), "sendEmail": MessageLookupByLibrary.simpleMessage("Enviar correo electrónico"), @@ -1849,16 +1867,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Compartir un álbum ahora"), "shareLink": MessageLookupByLibrary.simpleMessage("Compartir enlace"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Comparte sólo con la gente que quieres"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Descarga Ente para que podamos compartir fácilmente fotos y videos en calidad original.\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Compartir con usuarios fuera de Ente"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage("Comparte tu primer álbum"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1870,7 +1888,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Nuevas fotos compartidas"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "Recibir notificaciones cuando alguien agrega una foto a un álbum compartido contigo"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Compartido conmigo"), "sharedWithYou": @@ -1889,11 +1907,11 @@ class MessageLookup extends MessageLookupByLibrary { "Cerrar la sesión de otros dispositivos"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Estoy de acuerdo con los términos del servicio y la política de privacidad"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "Se borrará de todos los álbumes."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("Omitir"), "social": MessageLookupByLibrary.simpleMessage("Social"), "someItemsAreInBothEnteAndYourDevice": @@ -1922,8 +1940,6 @@ class MessageLookup extends MessageLookupByLibrary { "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "Lo sentimos, no hemos podido generar claves seguras en este dispositivo.\n\nPor favor, regístrate desde un dispositivo diferente."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "sort": MessageLookupByLibrary.simpleMessage("Ordenar"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Ordenar por"), "sortNewestFirst": @@ -1931,8 +1947,8 @@ class MessageLookup extends MessageLookupByLibrary { "sortOldestFirst": MessageLookupByLibrary.simpleMessage("Más antiguos primero"), "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ Éxito"), - "sportsWithThem": m89, - "spotlightOnThem": m90, + "sportsWithThem": m91, + "spotlightOnThem": m92, "spotlightOnYourself": MessageLookupByLibrary.simpleMessage("Enfócate a ti mismo"), "startAccountRecoveryTitle": @@ -1947,15 +1963,15 @@ class MessageLookup extends MessageLookupByLibrary { "storage": MessageLookupByLibrary.simpleMessage("Almacenamiento"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Familia"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Usted"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage("Límite de datos excedido"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "streamDetails": MessageLookupByLibrary.simpleMessage("Detalles de la transmisión"), "strongStrength": MessageLookupByLibrary.simpleMessage("Segura"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("Suscribirse"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "Necesitas una suscripción activa de pago para habilitar el compartir."), @@ -1973,7 +1989,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Sugerir una característica"), "sunrise": MessageLookupByLibrary.simpleMessage("Sobre el horizonte"), "support": MessageLookupByLibrary.simpleMessage("Soporte"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("Sincronización detenida"), "syncing": MessageLookupByLibrary.simpleMessage("Sincronizando..."), @@ -1984,7 +2000,7 @@ class MessageLookup extends MessageLookupByLibrary { "tapToUnlock": MessageLookupByLibrary.simpleMessage("Toca para desbloquear"), "tapToUpload": MessageLookupByLibrary.simpleMessage("Toca para subir"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Parece que algo salió mal. Por favor, vuelve a intentarlo después de algún tiempo. Si el error persiste, ponte en contacto con nuestro equipo de soporte."), "terminate": MessageLookupByLibrary.simpleMessage("Terminar"), @@ -2008,7 +2024,7 @@ class MessageLookup extends MessageLookupByLibrary { "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage( "Estos elementos se eliminarán de tu dispositivo."), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage( "Se borrarán de todos los álbumes."), "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( @@ -2026,12 +2042,12 @@ class MessageLookup extends MessageLookupByLibrary { "Esta imagen no tiene datos exif"), "thisIsMeExclamation": MessageLookupByLibrary.simpleMessage("¡Este soy yo!"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( "Esta es tu ID de verificación"), "thisWeekThroughTheYears": MessageLookupByLibrary.simpleMessage( "Esta semana a través de los años"), - "thisWeekXYearsAgo": m99, + "thisWeekXYearsAgo": m101, "thisWillLogYouOutOfTheFollowingDevice": MessageLookupByLibrary.simpleMessage( "Esto cerrará la sesión del siguiente dispositivo:"), @@ -2043,7 +2059,7 @@ class MessageLookup extends MessageLookupByLibrary { "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( "Esto eliminará los enlaces públicos de todos los enlaces rápidos seleccionados."), - "throughTheYears": m100, + "throughTheYears": m102, "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": MessageLookupByLibrary.simpleMessage( "Para habilitar el bloqueo de la aplicación, por favor configura el código de acceso del dispositivo o el bloqueo de pantalla en los ajustes del sistema."), @@ -2057,13 +2073,13 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("total"), "totalSize": MessageLookupByLibrary.simpleMessage("Tamaño total"), "trash": MessageLookupByLibrary.simpleMessage("Papelera"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("Ajustar duración"), - "tripInYear": m102, - "tripToLocation": m103, + "tripInYear": m104, + "tripToLocation": m105, "trustedContacts": MessageLookupByLibrary.simpleMessage("Contactos de confianza"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("Inténtalo de nuevo"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "Activar la copia de seguridad para subir automáticamente archivos añadidos a la carpeta de este dispositivo a Ente."), @@ -2081,7 +2097,7 @@ class MessageLookup extends MessageLookupByLibrary { "Autenticación de doble factor restablecida con éxito"), "twofactorSetup": MessageLookupByLibrary.simpleMessage("Configuración de dos pasos"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("Desarchivar"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("Desarchivar álbum"), @@ -2106,10 +2122,10 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage( "Actualizando la selección de carpeta..."), "upgrade": MessageLookupByLibrary.simpleMessage("Mejorar"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Subiendo archivos al álbum..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage("Preservando 1 memoria..."), "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( @@ -2128,7 +2144,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("Usar foto seleccionada"), "usedSpace": MessageLookupByLibrary.simpleMessage("Espacio usado"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Verificación fallida, por favor inténtalo de nuevo"), @@ -2137,7 +2153,7 @@ class MessageLookup extends MessageLookupByLibrary { "verify": MessageLookupByLibrary.simpleMessage("Verificar"), "verifyEmail": MessageLookupByLibrary.simpleMessage( "Verificar correo electrónico"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Verificar"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("Verificar clave de acceso"), @@ -2165,7 +2181,7 @@ class MessageLookup extends MessageLookupByLibrary { "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("Ver código de recuperación"), "viewer": MessageLookupByLibrary.simpleMessage("Espectador"), - "viewersSuccessfullyAdded": m111, + "viewersSuccessfullyAdded": m113, "visitWebToManage": MessageLookupByLibrary.simpleMessage( "Por favor, visita web.ente.io para administrar tu suscripción"), "waitingForVerification": @@ -2178,16 +2194,17 @@ class MessageLookup extends MessageLookupByLibrary { "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "No admitimos la edición de fotos y álbumes que aún no son tuyos"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Poco segura"), "welcomeBack": MessageLookupByLibrary.simpleMessage("¡Bienvenido de nuevo!"), "whatsNew": MessageLookupByLibrary.simpleMessage("Qué hay de nuevo"), "whyAddTrustContact": MessageLookupByLibrary.simpleMessage( "Un contacto de confianza puede ayudar a recuperar sus datos."), + "wishThemAHappyBirthday": m115, "yearShort": MessageLookupByLibrary.simpleMessage("año"), "yearly": MessageLookupByLibrary.simpleMessage("Anualmente"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Sí"), "yesCancel": MessageLookupByLibrary.simpleMessage("Sí, cancelar"), "yesConvertToViewer": @@ -2201,7 +2218,7 @@ class MessageLookup extends MessageLookupByLibrary { "yesResetPerson": MessageLookupByLibrary.simpleMessage("Si, eliminar persona"), "you": MessageLookupByLibrary.simpleMessage("Tu"), - "youAndThem": m114, + "youAndThem": m117, "youAreOnAFamilyPlan": MessageLookupByLibrary.simpleMessage("¡Estás en un plan familiar!"), "youAreOnTheLatestVersion": MessageLookupByLibrary.simpleMessage( @@ -2220,7 +2237,7 @@ class MessageLookup extends MessageLookupByLibrary { "No puedes compartir contigo mismo"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( "No tienes ningún elemento archivado."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("Tu cuenta ha sido eliminada"), "yourMap": MessageLookupByLibrary.simpleMessage("Tu mapa"), diff --git a/mobile/lib/generated/intl/messages_et.dart b/mobile/lib/generated/intl/messages_et.dart index c583ea0bb2..65c40f7792 100644 --- a/mobile/lib/generated/intl/messages_et.dart +++ b/mobile/lib/generated/intl/messages_et.dart @@ -20,6 +20,8 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'et'; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { "about": MessageLookupByLibrary.simpleMessage("Info"), @@ -49,8 +51,6 @@ class MessageLookup extends MessageLookupByLibrary { "checkStatus": MessageLookupByLibrary.simpleMessage("Kontrolli staatust"), "checking": MessageLookupByLibrary.simpleMessage("Kontrollimine..."), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "collaborator": MessageLookupByLibrary.simpleMessage("Kaastööline"), "collectPhotos": MessageLookupByLibrary.simpleMessage("Kogu fotod"), "color": MessageLookupByLibrary.simpleMessage("Värv"), @@ -151,8 +151,6 @@ class MessageLookup extends MessageLookupByLibrary { "lockButtonLabel": MessageLookupByLibrary.simpleMessage("Lukusta"), "logInLabel": MessageLookupByLibrary.simpleMessage("Logi sisse"), "logout": MessageLookupByLibrary.simpleMessage("Logi välja"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "manage": MessageLookupByLibrary.simpleMessage("Halda"), "manageLink": MessageLookupByLibrary.simpleMessage("Halda linki"), "manageParticipants": MessageLookupByLibrary.simpleMessage("Halda"), @@ -166,14 +164,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Liigutatud prügikasti"), "name": MessageLookupByLibrary.simpleMessage("Nimi"), "never": MessageLookupByLibrary.simpleMessage("Mitte kunagi"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "newest": MessageLookupByLibrary.simpleMessage("Uusimad"), "no": MessageLookupByLibrary.simpleMessage("Ei"), "noDeviceLimit": MessageLookupByLibrary.simpleMessage("Puudub"), "ok": MessageLookupByLibrary.simpleMessage("OK"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), "oops": MessageLookupByLibrary.simpleMessage("Oih"), "oopsSomethingWentWrong": MessageLookupByLibrary.simpleMessage("Oih, midagi läks valesti"), @@ -229,8 +223,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Midagi läks valesti, palun proovi uuesti"), "sorry": MessageLookupByLibrary.simpleMessage("Vabandust"), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Sorteeri"), "sortNewestFirst": MessageLookupByLibrary.simpleMessage("Uuemad eespool"), @@ -268,6 +260,7 @@ class MessageLookup extends MessageLookupByLibrary { "weakStrength": MessageLookupByLibrary.simpleMessage("Nõrk"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Tere tulemast tagasi!"), + "wishThemAHappyBirthday": m115, "yes": MessageLookupByLibrary.simpleMessage("Jah"), "yesConvertToViewer": MessageLookupByLibrary.simpleMessage("Jah, muuda vaatajaks"), diff --git a/mobile/lib/generated/intl/messages_eu.dart b/mobile/lib/generated/intl/messages_eu.dart index 7327bbec18..2835aecade 100644 --- a/mobile/lib/generated/intl/messages_eu.dart +++ b/mobile/lib/generated/intl/messages_eu.dart @@ -33,72 +33,74 @@ class MessageLookup extends MessageLookupByLibrary { 'other': 'Zuk ${storageAmountInGb} GB eskatu duzu dagoeneko!', })}"; - static String m23(albumName) => + static String m24(albumName) => "Honen bidez ${albumName} eskuratzeko esteka publikoa ezabatuko da."; - static String m24(supportEmail) => + static String m25(supportEmail) => "Mesedez, bidali e-maila ${supportEmail}-era zure erregistratutako e-mail helbidetik"; - static String m30(email) => + static String m31(email) => "${email}-(e)k ez du Ente konturik. \n\nBidali gonbidapena argazkiak partekatzeko."; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "${storageAmountInGB} GB norbaitek ordainpeko plan batean sartzen denean zure kodea aplikatzen badu"; - static String m46(expiryTime) => + static String m47(expiryTime) => "Esteka epe honetan iraungiko da: ${expiryTime}"; - static String m49(count, formattedCount) => + static String m50(count, formattedCount) => "${Intl.plural(count, zero: 'oroitzapenik ez', one: 'oroitzapen ${formattedCount}', other: '${formattedCount} oroitzapen')}"; - static String m54(familyAdminEmail) => + static String m55(familyAdminEmail) => "Mesedez, jarri harremanetan ${familyAdminEmail}-(r)ekin zure kodea aldatzeko."; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Pasahitzaren indarra: ${passwordStrengthValue}"; - static String m72(storageInGB) => + static String m73(storageInGB) => "3. Bai zuk bai haiek ${storageInGB} GB* dohainik izango duzue"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} partekatutako album honetatik ezabatuko da \n\nHaiek gehitutako argazki guztiak ere ezabatuak izango dira albumetik"; - static String m78(count) => "${count} hautatuta"; + static String m80(count) => "${count} hautatuta"; - static String m79(count, yourCount) => + static String m81(count, yourCount) => "${count} hautatuta (${yourCount} zureak)"; - static String m81(verificationID) => + static String m83(verificationID) => "Hau da nire Egiaztatze IDa: ${verificationID} ente.io-rako."; - static String m82(verificationID) => + static String m84(verificationID) => "Ei, baieztatu ahal duzu hau dela zure ente.io Egiaztatze IDa?: ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Sartu erreferentzia kodea: ${referralCode}\n\nAplikatu hemen: Ezarpenak → Orokorra→ Erreferentziak, ${referralStorageInGB} GB dohainik izateko ordainpeko plan batean \n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Partekatu pertsona zehatz batzuekin', one: 'Partekatu pertsona batekin', other: 'Partekatu ${numberOfPeople} pertsonarekin')}"; - static String m86(fileType) => "${fileType} hau zure gailutik ezabatuko da."; + static String m88(fileType) => "${fileType} hau zure gailutik ezabatuko da."; - static String m87(fileType) => + static String m89(fileType) => "${fileType} hau Ente-n eta zure gailuan dago."; - static String m88(fileType) => "${fileType} hau Ente-tik ezabatuko da."; + static String m90(fileType) => "${fileType} hau Ente-tik ezabatuko da."; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "Haiek ere lortuko dute ${storageAmountInGB} GB"; - static String m98(email) => "Hau da ${email}-(r)en Egiaztatze IDa"; + static String m100(email) => "Hau da ${email}-(r)en Egiaztatze IDa"; - static String m109(email) => "Egiaztatu ${email}"; + static String m111(email) => "Egiaztatu ${email}"; - static String m112(email) => + static String m114(email) => "Mezua bidali dugu ${email} helbidera"; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { "accountWelcomeBack": @@ -184,8 +186,6 @@ class MessageLookup extends MessageLookupByLibrary { "claimMore": MessageLookupByLibrary.simpleMessage("Eskatu gehiago!"), "claimed": MessageLookupByLibrary.simpleMessage("Eskatuta"), "claimedStorageSoFar": m14, - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "codeAppliedPageTitle": MessageLookupByLibrary.simpleMessage("Kodea aplikatuta"), "codeChangeLimitReached": MessageLookupByLibrary.simpleMessage( @@ -273,7 +273,7 @@ class MessageLookup extends MessageLookupByLibrary { "Ikusleek pantaila-irudiak atera ahal dituzte, edo kanpoko tresnen bidez zure argazkien kopiak gorde"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Mesedez, ohartu"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "discover": MessageLookupByLibrary.simpleMessage("Aurkitu"), "discover_babies": MessageLookupByLibrary.simpleMessage("Umeak"), "discover_celebrations": @@ -298,12 +298,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Horma-paperak"), "doThisLater": MessageLookupByLibrary.simpleMessage("Egin hau geroago"), "done": MessageLookupByLibrary.simpleMessage("Eginda"), - "dropSupportEmail": m24, + "dropSupportEmail": m25, "eligible": MessageLookupByLibrary.simpleMessage("aukerakoak"), "email": MessageLookupByLibrary.simpleMessage("E-maila"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage( "Helbide hau badago erregistratuta lehendik."), - "emailNoEnteAccount": m30, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage( "Helbide hau ez dago erregistratuta."), "encryption": MessageLookupByLibrary.simpleMessage("Zifratzea"), @@ -348,7 +348,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ahaztu pasahitza"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage( "Debaldeko biltegiratzea eskatuta"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage( "Debaldeko biltegiratzea erabilgarri"), "generatingEncryptionKeys": @@ -387,7 +387,7 @@ class MessageLookup extends MessageLookupByLibrary { "linkDeviceLimit": MessageLookupByLibrary.simpleMessage("Gailu muga"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Indarrean"), "linkExpired": MessageLookupByLibrary.simpleMessage("Iraungita"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Estekaren epemuga"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("Esteka iraungi da"), @@ -396,8 +396,6 @@ class MessageLookup extends MessageLookupByLibrary { "logInLabel": MessageLookupByLibrary.simpleMessage("Sartu"), "loginTerms": MessageLookupByLibrary.simpleMessage( "Sartzeko klikatuz, zerbitzu baldintzak eta pribatutasun politikak onartzen ditut"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "lostDevice": MessageLookupByLibrary.simpleMessage("Gailua galdu duzu?"), "machineLearning": @@ -410,7 +408,7 @@ class MessageLookup extends MessageLookupByLibrary { "Berrikusi eta garbitu katxe lokalaren biltegiratzea."), "manageLink": MessageLookupByLibrary.simpleMessage("Kudeatu esteka"), "manageParticipants": MessageLookupByLibrary.simpleMessage("Kudeatu"), - "memoryCount": m49, + "memoryCount": m50, "mlConsent": MessageLookupByLibrary.simpleMessage( "Aktibatu ikasketa automatikoa"), "mlConsentConfirmation": MessageLookupByLibrary.simpleMessage( @@ -425,17 +423,13 @@ class MessageLookup extends MessageLookupByLibrary { "movedToTrash": MessageLookupByLibrary.simpleMessage("Zarama mugituta"), "never": MessageLookupByLibrary.simpleMessage("Inoiz ez"), "newAlbum": MessageLookupByLibrary.simpleMessage("Album berria"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "noDeviceLimit": MessageLookupByLibrary.simpleMessage("Bat ere ez"), "noRecoveryKey": MessageLookupByLibrary.simpleMessage("Berreskuratze giltzarik ez?"), "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( "Gure puntutik-puntura zifratze protokoloa dela eta, zure data ezin da deszifratu zure pasahitza edo berreskuratze giltzarik gabe"), "ok": MessageLookupByLibrary.simpleMessage("Ondo"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "onlyFamilyAdminCanChangeCode": m55, "oops": MessageLookupByLibrary.simpleMessage("Ai!"), "oopsSomethingWentWrong": MessageLookupByLibrary.simpleMessage( "Oops, zerbait txarto joan da"), @@ -446,7 +440,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Pasahitza zuzenki aldatuta"), "passwordLock": MessageLookupByLibrary.simpleMessage("Pasahitza blokeoa"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordWarning": MessageLookupByLibrary.simpleMessage( "Ezin dugu zure pasahitza gorde, beraz, ahazten baduzu, ezin dugu zure data deszifratu"), "peopleUsingYourCode": MessageLookupByLibrary.simpleMessage( @@ -490,7 +484,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Eman kode hau zure lagunei"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Haiek ordainpeko plan batean sinatu behar dute"), - "referralStep3": m72, + "referralStep3": m73, "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Erreferentziak momentuz geldituta daude"), "remove": MessageLookupByLibrary.simpleMessage("Kendu"), @@ -501,7 +495,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Ezabatu esteka"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Kendu parte hartzailea"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePublicLink": MessageLookupByLibrary.simpleMessage("Ezabatu esteka publikoa"), "removeShareItemsWarning": MessageLookupByLibrary.simpleMessage( @@ -524,8 +518,8 @@ class MessageLookup extends MessageLookupByLibrary { "Eskaneatu barra kode hau zure autentifikazio aplikazioaz"), "selectReason": MessageLookupByLibrary.simpleMessage("Aukeratu arrazoia"), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, "sendEmail": MessageLookupByLibrary.simpleMessage("Bidali mezua"), "sendInvite": MessageLookupByLibrary.simpleMessage("Bidali gonbidapena"), @@ -537,24 +531,24 @@ class MessageLookup extends MessageLookupByLibrary { "setupComplete": MessageLookupByLibrary.simpleMessage("Prestaketa burututa"), "shareALink": MessageLookupByLibrary.simpleMessage("Partekatu esteka"), - "shareMyVerificationID": m81, - "shareTextConfirmOthersVerificationID": m82, + "shareMyVerificationID": m83, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Jaitsi Ente argazkiak eta bideoak jatorrizko kalitatean errez partekatu ahal izateko \n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Partekatu Ente erabiltzen ez dutenekin"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( "Sortu partekatutako eta parte hartzeko albumak beste Ente erabiltzaileekin, debaldeko planak dituztenak barne."), "sharing": MessageLookupByLibrary.simpleMessage("Partekatzen..."), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Zerbitzu baldintzak eta pribatutasun politikak onartzen ditut"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "Album guztietatik ezabatuko da."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "someoneSharingAlbumsWithYouShouldSeeTheSameId": MessageLookupByLibrary.simpleMessage( "Zurekin albumak partekatzen dituen norbaitek ID berbera ikusi beharko luke bere gailuan."), @@ -572,9 +566,7 @@ class MessageLookup extends MessageLookupByLibrary { "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "Tamalez, ezin dugu giltza segururik sortu gailu honetan. \n\nMesedez, eman izena beste gailu batetik."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), - "storageInGB": m91, + "storageInGB": m93, "strongStrength": MessageLookupByLibrary.simpleMessage("Gogorra"), "subscribe": MessageLookupByLibrary.simpleMessage("Harpidetu"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( @@ -587,12 +579,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Saioa bukatu?"), "termsOfServicesTitle": MessageLookupByLibrary.simpleMessage("Baldintzak"), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "thisCanBeUsedToRecoverYourAccountIfYou": MessageLookupByLibrary.simpleMessage( "Hau zure kontua berreskuratzeko erabili ahal duzu, zure bigarren faktorea ahaztuz gero"), "thisDevice": MessageLookupByLibrary.simpleMessage("Gailu hau"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage("Hau da zure Egiaztatze IDa"), "thisWillLogYouOutOfTheFollowingDevice": @@ -626,7 +618,7 @@ class MessageLookup extends MessageLookupByLibrary { "verify": MessageLookupByLibrary.simpleMessage("Egiaztatu"), "verifyEmail": MessageLookupByLibrary.simpleMessage("Egiaztatu e-maila"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyPassword": MessageLookupByLibrary.simpleMessage("Egiaztatu pasahitza"), "verifyingRecoveryKey": MessageLookupByLibrary.simpleMessage( @@ -635,10 +627,11 @@ class MessageLookup extends MessageLookupByLibrary { "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("Ikusi berreskuratze kodea"), "viewer": MessageLookupByLibrary.simpleMessage("Ikuslea"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Ahula"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Ongi etorri berriro!"), + "wishThemAHappyBirthday": m115, "yesConvertToViewer": MessageLookupByLibrary.simpleMessage("Bai, egin ikusle"), "yesDelete": MessageLookupByLibrary.simpleMessage("Bai, ezabatu"), diff --git a/mobile/lib/generated/intl/messages_fa.dart b/mobile/lib/generated/intl/messages_fa.dart index 585296885c..52d3a0ab25 100644 --- a/mobile/lib/generated/intl/messages_fa.dart +++ b/mobile/lib/generated/intl/messages_fa.dart @@ -25,23 +25,25 @@ class MessageLookup extends MessageLookupByLibrary { static String m10(freeAmount, storageUnit) => "${freeAmount} ${storageUnit} رایگان"; - static String m24(supportEmail) => + static String m25(supportEmail) => "لطفا یک ایمیل از آدرس ایمیلی که ثبت نام کردید به ${supportEmail} ارسال کنید"; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "قدرت رمز عبور: ${passwordStrengthValue}"; - static String m67(storeName) => "به ما در ${storeName} امتیاز دهید"; + static String m68(storeName) => "به ما در ${storeName} امتیاز دهید"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} از ${totalAmount} ${totalStorageUnit} استفاده شده"; - static String m109(email) => "تایید ${email}"; + static String m111(email) => "تایید ${email}"; - static String m112(email) => + static String m114(email) => "ما یک ایمیل به ${email} ارسال کرده‌ایم"; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { "aNewVersionOfEnteIsAvailable": MessageLookupByLibrary.simpleMessage( @@ -103,8 +105,6 @@ class MessageLookup extends MessageLookupByLibrary { "لطفا صندوق ورودی (و هرزنامه) خود را برای تایید کامل بررسی کنید"), "checkStatus": MessageLookupByLibrary.simpleMessage("بررسی وضعیت"), "checking": MessageLookupByLibrary.simpleMessage("در حال بررسی..."), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "collabLinkSectionDescription": MessageLookupByLibrary.simpleMessage( "پیوندی ایجاد کنید تا به افراد اجازه دهید بدون نیاز به برنامه یا حساب کاربری Ente عکس‌ها را در آلبوم اشتراک گذاشته شده شما اضافه و مشاهده کنند. برای جمع‌آوری عکس‌های رویداد عالی است."), "collaborator": MessageLookupByLibrary.simpleMessage("همکار"), @@ -168,7 +168,7 @@ class MessageLookup extends MessageLookupByLibrary { "discord": MessageLookupByLibrary.simpleMessage("دیسکورد"), "doThisLater": MessageLookupByLibrary.simpleMessage("بعداً انجام شود"), "downloading": MessageLookupByLibrary.simpleMessage("در حال دانلود..."), - "dropSupportEmail": m24, + "dropSupportEmail": m25, "editLocationTagTitle": MessageLookupByLibrary.simpleMessage("ویرایش مکان"), "email": MessageLookupByLibrary.simpleMessage("ایمیل"), @@ -249,8 +249,6 @@ class MessageLookup extends MessageLookupByLibrary { "loginTerms": MessageLookupByLibrary.simpleMessage( "با کلیک بر روی ورود به سیستم، من با شرایط خدمات و سیاست حفظ حریم خصوصی موافقم"), "logout": MessageLookupByLibrary.simpleMessage("خروج"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "manage": MessageLookupByLibrary.simpleMessage("مدیریت"), "manageFamily": MessageLookupByLibrary.simpleMessage("مدیریت خانواده"), "manageLink": MessageLookupByLibrary.simpleMessage("مدیریت پیوند"), @@ -262,7 +260,6 @@ class MessageLookup extends MessageLookupByLibrary { "merchandise": MessageLookupByLibrary.simpleMessage("کالا"), "moderateStrength": MessageLookupByLibrary.simpleMessage("متوسط"), "never": MessageLookupByLibrary.simpleMessage("هرگز"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "newToEnte": MessageLookupByLibrary.simpleMessage("کاربر جدید Ente"), "no": MessageLookupByLibrary.simpleMessage("خیر"), "noRecoveryKey": @@ -271,14 +268,11 @@ class MessageLookup extends MessageLookupByLibrary { "با توجه به ماهیت پروتکل رمزگذاری سرتاسر ما، اطلاعات شما بدون رمز عبور یا کلید بازیابی شما قابل رمزگشایی نیست"), "notifications": MessageLookupByLibrary.simpleMessage("آگاه‌سازی‌ها"), "ok": MessageLookupByLibrary.simpleMessage("تایید"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), "oops": MessageLookupByLibrary.simpleMessage("اوه"), "password": MessageLookupByLibrary.simpleMessage("رمز عبور"), "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage( "رمز عبور با موفقیت تغییر کرد"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordWarning": MessageLookupByLibrary.simpleMessage( "ما این رمز عبور را ذخیره نمی‌کنیم، بنابراین اگر فراموش کنید، نمی‌توانیم اطلاعات شما را رمزگشایی کنیم"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("عکس"), @@ -298,7 +292,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("پشتیبان گیری خصوصی"), "privateSharing": MessageLookupByLibrary.simpleMessage("اشتراک گذاری خصوصی"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "recover": MessageLookupByLibrary.simpleMessage("بازیابی"), "recoverAccount": MessageLookupByLibrary.simpleMessage("بازیابی حساب کاربری"), @@ -361,8 +355,6 @@ class MessageLookup extends MessageLookupByLibrary { "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "با عرض پوزش، ما نمی‌توانیم کلیدهای امن را در این دستگاه تولید کنیم.\n\nلطفا از دستگاه دیگری ثبت نام کنید."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("مرتب‌سازی براساس"), "sortNewestFirst": @@ -376,7 +368,7 @@ class MessageLookup extends MessageLookupByLibrary { "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("خانوادگی"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("شما"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "strongStrength": MessageLookupByLibrary.simpleMessage("قوی"), "support": MessageLookupByLibrary.simpleMessage("پشتیبانی"), "systemTheme": MessageLookupByLibrary.simpleMessage("سیستم"), @@ -417,7 +409,7 @@ class MessageLookup extends MessageLookupByLibrary { "از کلید بازیابی استفاده کنید"), "verify": MessageLookupByLibrary.simpleMessage("تایید"), "verifyEmail": MessageLookupByLibrary.simpleMessage("تایید ایمیل"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("تایید"), "verifyPassword": MessageLookupByLibrary.simpleMessage("تایید رمز عبور"), @@ -430,10 +422,11 @@ class MessageLookup extends MessageLookupByLibrary { "viewer": MessageLookupByLibrary.simpleMessage("بیننده"), "weAreOpenSource": MessageLookupByLibrary.simpleMessage("ما متن‌باز هستیم!"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("ضعیف"), "welcomeBack": MessageLookupByLibrary.simpleMessage("خوش آمدید!"), "whatsNew": MessageLookupByLibrary.simpleMessage("تغییرات جدید"), + "wishThemAHappyBirthday": m115, "yes": MessageLookupByLibrary.simpleMessage("بله"), "yesConvertToViewer": MessageLookupByLibrary.simpleMessage("بله، تبدیل به بیننده شود"), diff --git a/mobile/lib/generated/intl/messages_fr.dart b/mobile/lib/generated/intl/messages_fr.dart index e8f927a21c..5fcc40e6cf 100644 --- a/mobile/lib/generated/intl/messages_fr.dart +++ b/mobile/lib/generated/intl/messages_fr.dart @@ -22,9 +22,18 @@ class MessageLookup extends MessageLookupByLibrary { static String m0(title) => "${title} (Moi)"; + static String m1(count) => + "${Intl.plural(count, zero: 'Ajouter un collaborateur', one: 'Ajouter un collaborateur', other: 'Ajouter des collaborateurs')}"; + + static String m2(count) => + "${Intl.plural(count, one: 'Ajouter un élément', other: 'Ajouter des éléments')}"; + static String m3(storageAmount, endDate) => "Votre extension de ${storageAmount} est valable jusqu\'au ${endDate}"; + static String m4(count) => + "${Intl.plural(count, zero: 'Ajouter un spectateur', one: 'Ajouter une spectateur', other: 'Ajouter des spectateurs')}"; + static String m5(emailOrName) => "Ajouté par ${emailOrName}"; static String m6(albumName) => "Ajouté avec succès à ${albumName}"; @@ -76,226 +85,250 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'Supprimer le fichier', other: 'Supprimer ${count} fichiers')}"; - static String m22(currentlyDeleting, totalCount) => + static String m22(count) => + "Supprimer également les photos (et les vidéos) présentes dans ces ${count} albums de tous les autres albums dont ils font partie ?"; + + static String m23(currentlyDeleting, totalCount) => "Suppression de ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "Cela supprimera le lien public pour accéder à \"${albumName}\"."; - static String m24(supportEmail) => + static String m25(supportEmail) => "Veuillez envoyer un e-mail à ${supportEmail} depuis votre adresse enregistrée"; - static String m25(count, storageSaved) => + static String m26(count, storageSaved) => "Vous avez nettoyé ${Intl.plural(count, one: '${count} fichier dupliqué', other: '${count} fichiers dupliqués')}, en libérant (${storageSaved}!)"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} fichiers, ${formattedSize} chacun"; - static String m28(newEmail) => "L\'email a été changé par ${newEmail}"; + static String m28(name) => "Cet e-mail est déjà lié à ${name}."; - static String m29(email) => "${email} n\'a pas de compte Ente."; + static String m29(newEmail) => "L\'email a été changé par ${newEmail}"; - static String m30(email) => + static String m30(email) => "${email} n\'a pas de compte Ente."; + + static String m31(email) => "${email} n\'a pas de compte Ente.\n\nEnvoyez une invitation pour partager des photos."; - static String m31(name) => "Embrasse ${name}"; + static String m32(name) => "Embrasse ${name}"; - static String m32(text) => "Photos supplémentaires trouvées pour ${text}"; + static String m33(text) => "Photos supplémentaires trouvées pour ${text}"; - static String m33(name) => "Fête avec ${name}"; - - static String m34(count, formattedNumber) => - "${Intl.plural(count, one: '1 fichier sur cet appareil a été sauvegardé en toute sécurité', other: '${formattedNumber} fichiers sur cet appareil ont été sauvegardés en toute sécurité')}"; + static String m34(name) => "Fête avec ${name}"; static String m35(count, formattedNumber) => + "${Intl.plural(count, one: '1 fichier sur cet appareil a été sauvegardé en toute sécurité', other: '${formattedNumber} fichiers sur cet appareil ont été sauvegardés en toute sécurité')}"; + + static String m36(count, formattedNumber) => "${Intl.plural(count, one: '1 fichier dans cet album a été sauvegardé en toute sécurité', other: '${formattedNumber} fichiers dans cet album ont été sauvegardés en toute sécurité')}"; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "${storageAmountInGB} Go chaque fois que quelqu\'un s\'inscrit à une offre payante et applique votre code"; - static String m37(endDate) => "Essai gratuit valide jusqu’au ${endDate}"; + static String m38(endDate) => "Essai gratuit valide jusqu’au ${endDate}"; - static String m39(sizeInMBorGB) => "Libérer ${sizeInMBorGB}"; + static String m39(count) => + "Vous pouvez toujours ${Intl.plural(count, one: 'l\'', other: 'les')} accéder sur Ente tant que vous avez un abonnement actif"; - static String m41(currentlyProcessing, totalCount) => + static String m40(sizeInMBorGB) => "Libérer ${sizeInMBorGB}"; + + static String m41(count, formattedSize) => + "${Intl.plural(count, one: 'Il peut être supprimé de l\'appareil pour libérer ${formattedSize}', other: 'Ils peuvent être supprimés de l\'appareil pour libérer ${formattedSize}')}"; + + static String m42(currentlyProcessing, totalCount) => "Traitement en cours ${currentlyProcessing} / ${totalCount}"; - static String m42(name) => "Randonnée avec ${name}"; + static String m43(name) => "Randonnée avec ${name}"; - static String m43(count) => + static String m44(count) => "${Intl.plural(count, one: '${count} objet', other: '${count} objets')}"; - static String m44(name) => "Dernière fois avec ${name}"; + static String m45(name) => "Dernière fois avec ${name}"; - static String m45(email) => + static String m46(email) => "${email} vous a invité à être un contact de confiance"; - static String m46(expiryTime) => "Le lien expirera le ${expiryTime}"; + static String m47(expiryTime) => "Le lien expirera le ${expiryTime}"; - static String m47(email) => "Associer la personne à ${email}"; + static String m48(email) => "Associer la personne à ${email}"; - static String m48(personName, email) => + static String m49(personName, email) => "Cela va associer ${personName} à ${email}"; - static String m49(count, formattedCount) => + static String m50(count, formattedCount) => "${Intl.plural(count, zero: 'aucun souvenir', one: '${formattedCount} souvenir', other: '${formattedCount} souvenirs')}"; - static String m51(albumName) => "Déplacé avec succès vers ${albumName}"; + static String m51(count) => + "${Intl.plural(count, one: 'Déplacer un élément', other: 'Déplacer des éléments')}"; - static String m52(personName) => "Aucune suggestion pour ${personName}"; + static String m52(albumName) => "Déplacé avec succès vers ${albumName}"; - static String m53(name) => "Pas ${name}?"; + static String m53(personName) => "Aucune suggestion pour ${personName}"; - static String m54(familyAdminEmail) => + static String m54(name) => "Pas ${name}?"; + + static String m55(familyAdminEmail) => "Veuillez contacter ${familyAdminEmail} pour modifier votre code."; - static String m55(name) => "En soirée avec ${name}"; + static String m56(name) => "En soirée avec ${name}"; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Sécurité du mot de passe : ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "Veuillez contacter le support ${providerName} si vous avez été facturé"; - static String m58(name, age) => "${name} a ${age}!"; + static String m59(name, age) => "${name} a ${age}!"; - static String m59(name, age) => "${name} aura bientôt ${age}"; + static String m60(name, age) => "${name} aura bientôt ${age}"; - static String m60(count) => + static String m61(count) => "${Intl.plural(count, zero: 'No photos', one: '1 photo', other: '${count} photos')}"; - static String m62(endDate) => + static String m62(count) => + "${Intl.plural(count, zero: '0 photo', one: '1 photo', other: '${count} photos')}"; + + static String m63(endDate) => "Essai gratuit valable jusqu\'à ${endDate}.\nVous pouvez choisir un plan payant par la suite."; - static String m63(toEmail) => "Merci de nous envoyer un email à ${toEmail}"; + static String m64(toEmail) => "Merci de nous envoyer un email à ${toEmail}"; - static String m64(toEmail) => "Envoyez les logs à ${toEmail}"; + static String m65(toEmail) => "Envoyez les logs à ${toEmail}"; - static String m65(name) => "Pose avec ${name}"; + static String m66(name) => "Pose avec ${name}"; - static String m66(folderName) => "Traitement de ${folderName}..."; + static String m67(folderName) => "Traitement de ${folderName}..."; - static String m67(storeName) => "Laissez une note sur ${storeName}"; + static String m68(storeName) => "Laissez une note sur ${storeName}"; - static String m68(name) => "Vous a réassigné à ${name}"; + static String m69(name) => "Vous a réassigné à ${name}"; - static String m69(days, email) => + static String m70(days, email) => "Vous pourrez accéder au compte d\'ici ${days} jours. Une notification sera envoyée à ${email}."; - static String m70(email) => + static String m71(email) => "Vous pouvez maintenant récupérer le compte de ${email} en définissant un nouveau mot de passe."; - static String m71(email) => "${email} tente de récupérer votre compte."; + static String m72(email) => "${email} tente de récupérer votre compte."; - static String m72(storageInGB) => + static String m73(storageInGB) => "3. Vous recevez tous les deux ${storageInGB} Go* gratuits"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} sera retiré de cet album partagé\n\nToutes les photos ajoutées par eux seront également retirées de l\'album"; - static String m74(endDate) => "Renouvellement le ${endDate}"; + static String m75(endDate) => "Renouvellement le ${endDate}"; - static String m75(name) => "En route avec ${name}"; + static String m76(name) => "En route avec ${name}"; - static String m76(count) => + static String m77(count) => "${Intl.plural(count, one: '${count} résultat trouvé', other: '${count} résultats trouvés')}"; - static String m77(snapshotLength, searchLength) => + static String m78(snapshotLength, searchLength) => "Incompatibilité de longueur des sections : ${snapshotLength} != ${searchLength}"; - static String m78(count) => "${count} sélectionné(s)"; + static String m79(count) => "${count} sélectionné(s)"; - static String m79(count, yourCount) => + static String m80(count) => "${count} sélectionné(s)"; + + static String m81(count, yourCount) => "${count} sélectionné(s) (${yourCount} à vous)"; - static String m80(name) => "Selfies avec ${name}"; + static String m82(name) => "Selfies avec ${name}"; - static String m81(verificationID) => + static String m83(verificationID) => "Voici mon ID de vérification : ${verificationID} pour ente.io."; - static String m82(verificationID) => + static String m84(verificationID) => "Hé, pouvez-vous confirmer qu\'il s\'agit de votre ID de vérification ente.io : ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Code de parrainage Ente : ${referralCode} \n\nValidez le dans Paramètres → Général → Références pour obtenir ${referralStorageInGB} Go gratuitement après votre inscription à un plan payant\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Partagez avec des personnes spécifiques', one: 'Partagé avec 1 personne', other: 'Partagé avec ${numberOfPeople} personnes')}"; - static String m85(emailIDs) => "Partagé avec ${emailIDs}"; + static String m87(emailIDs) => "Partagé avec ${emailIDs}"; - static String m86(fileType) => + static String m88(fileType) => "Elle ${fileType} sera supprimée de votre appareil."; - static String m87(fileType) => + static String m89(fileType) => "Cette ${fileType} est à la fois sur ente et sur votre appareil."; - static String m88(fileType) => "Cette ${fileType} sera supprimée de l\'Ente."; + static String m90(fileType) => "Cette ${fileType} sera supprimée de l\'Ente."; - static String m89(name) => "Sports avec ${name}"; + static String m91(name) => "Sports avec ${name}"; - static String m90(name) => "Spotlight sur ${name}"; + static String m92(name) => "Spotlight sur ${name}"; - static String m91(storageAmountInGB) => "${storageAmountInGB} Go"; + static String m93(storageAmountInGB) => "${storageAmountInGB} Go"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} sur ${totalAmount} ${totalStorageUnit} utilisés"; - static String m93(id) => + static String m95(id) => "Votre ${id} est déjà lié à un autre compte Ente.\nSi vous souhaitez utiliser votre ${id} avec ce compte, veuillez contacter notre support"; - static String m94(endDate) => "Votre abonnement sera annulé le ${endDate}"; + static String m96(endDate) => "Votre abonnement sera annulé le ${endDate}"; - static String m95(completed, total) => + static String m97(completed, total) => "${completed}/${total} souvenirs sauvegardés"; - static String m96(ignoreReason) => + static String m98(ignoreReason) => "Appuyer pour envoyer, l\'envoi est actuellement ignoré en raison de ${ignoreReason}"; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "Ils obtiennent aussi ${storageAmountInGB} Go"; - static String m98(email) => "Ceci est l\'ID de vérification de ${email}"; - - static String m99(count) => - "${Intl.plural(count, one: 'Cette semaine, ${count} il y a l\'année', other: 'Cette semaine, ${count} il y a des années')}"; - - static String m100(dateFormat) => "${dateFormat} au fil des années"; + static String m100(email) => "Ceci est l\'ID de vérification de ${email}"; static String m101(count) => + "${Intl.plural(count, one: 'Cette semaine, ${count} il y a l\'année', other: 'Cette semaine, ${count} il y a des années')}"; + + static String m102(dateFormat) => "${dateFormat} au fil des années"; + + static String m103(count) => "${Intl.plural(count, zero: 'Bientôt', one: '1 jour', other: '${count} jours')}"; - static String m102(year) => "Voyage en ${year}"; + static String m104(year) => "Voyage en ${year}"; - static String m103(location) => "Voyage vers ${location}"; + static String m105(location) => "Voyage vers ${location}"; - static String m104(email) => + static String m106(email) => "Vous avez été invité(e) à être un(e) héritier(e) par ${email}."; - static String m105(galleryType) => + static String m107(galleryType) => "Les galeries de type \'${galleryType}\' ne peuvent être renommées"; - static String m106(ignoreReason) => + static String m108(ignoreReason) => "L\'envoi est ignoré en raison de ${ignoreReason}"; - static String m107(count) => "Sauvegarde de ${count} souvenirs..."; + static String m109(count) => "Sauvegarde de ${count} souvenirs..."; - static String m108(endDate) => "Valable jusqu\'au ${endDate}"; + static String m110(endDate) => "Valable jusqu\'au ${endDate}"; - static String m109(email) => "Vérifier ${email}"; + static String m111(email) => "Vérifier ${email}"; - static String m110(name) => "Voir ${name} pour délier"; - - static String m112(email) => - "Nous avons envoyé un email à ${email}"; + static String m112(name) => "Voir ${name} pour délier"; static String m113(count) => + "${Intl.plural(count, zero: '0 spectateur ajouté', one: 'Un spectateur ajouté', other: '${count} spectateurs ajoutés')}"; + + static String m114(email) => + "Nous avons envoyé un email à ${email}"; + + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + + static String m116(count) => "${Intl.plural(count, one: 'il y a ${count} an', other: 'il y a ${count} ans')}"; - static String m114(name) => "Vous et ${name}"; + static String m117(name) => "Vous et ${name}"; - static String m115(storageSaved) => + static String m118(storageSaved) => "Vous avez libéré ${storageSaved} avec succès !"; final messages = _notInlinedMessages(_notInlinedMessages); @@ -313,21 +346,30 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Bon retour parmi nous !"), "ackPasswordLostWarning": MessageLookupByLibrary.simpleMessage( "Je comprends que si je perds mon mot de passe, je perdrai mes données puisque mes données sont chiffrées de bout en bout."), + "actionNotSupportedOnFavouritesAlbum": + MessageLookupByLibrary.simpleMessage( + "Action non prise en charge sur l\'album des Favoris"), "activeSessions": MessageLookupByLibrary.simpleMessage("Sessions actives"), "add": MessageLookupByLibrary.simpleMessage("Ajouter"), "addAName": MessageLookupByLibrary.simpleMessage("Ajouter un nom"), "addANewEmail": MessageLookupByLibrary.simpleMessage("Ajouter un nouvel email"), + "addAlbumWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Ajoutez un gadget d\'album à votre écran d\'accueil et revenez ici pour le personnaliser."), "addCollaborator": MessageLookupByLibrary.simpleMessage("Ajouter un collaborateur"), + "addCollaborators": m1, "addFiles": MessageLookupByLibrary.simpleMessage("Ajouter des fichiers"), "addFromDevice": MessageLookupByLibrary.simpleMessage("Ajouter depuis l\'appareil"), + "addItem": m2, "addLocation": MessageLookupByLibrary.simpleMessage("Ajouter la localisation"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Ajouter"), + "addMemoriesWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Ajoutez un gadget des souvenirs à votre écran d\'accueil et revenez ici pour le personnaliser."), "addMore": MessageLookupByLibrary.simpleMessage("Ajouter"), "addName": MessageLookupByLibrary.simpleMessage("Ajouter un nom"), "addNameOrMerge": @@ -340,6 +382,10 @@ class MessageLookup extends MessageLookupByLibrary { "addOnValidTill": m3, "addOns": MessageLookupByLibrary.simpleMessage("Modules complémentaires"), + "addParticipants": + MessageLookupByLibrary.simpleMessage("Ajouter des participants"), + "addPeopleWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Ajoutez un gadget des personnes à votre écran d\'accueil et revenez ici pour le personnaliser."), "addPhotos": MessageLookupByLibrary.simpleMessage("Ajouter des photos"), "addSelected": MessageLookupByLibrary.simpleMessage("Ajouter la sélection"), @@ -352,6 +398,7 @@ class MessageLookup extends MessageLookupByLibrary { "Ajouter un contact de confiance"), "addViewer": MessageLookupByLibrary.simpleMessage("Ajouter un observateur"), + "addViewers": m4, "addYourPhotosNow": MessageLookupByLibrary.simpleMessage( "Ajoutez vos photos maintenant"), "addedAs": MessageLookupByLibrary.simpleMessage("Ajouté comme"), @@ -373,6 +420,8 @@ class MessageLookup extends MessageLookupByLibrary { "albumUpdated": MessageLookupByLibrary.simpleMessage("Album mis à jour"), "albums": MessageLookupByLibrary.simpleMessage("Albums"), + "albumsWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Sélectionnez les personnes que vous souhaitez voir sur votre écran d\'accueil."), "allClear": MessageLookupByLibrary.simpleMessage("✨ Tout est effacé"), "allMemoriesPreserved": MessageLookupByLibrary.simpleMessage( "Tous les souvenirs sont sauvegardés"), @@ -527,9 +576,36 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Sauvegarde des vidéos"), "beach": MessageLookupByLibrary.simpleMessage("Sable et mer"), "birthday": MessageLookupByLibrary.simpleMessage("Anniversaire"), + "birthdayNotifications": MessageLookupByLibrary.simpleMessage( + "Notifications d’anniversaire"), + "birthdays": MessageLookupByLibrary.simpleMessage("Anniversaires"), "blackFridaySale": MessageLookupByLibrary.simpleMessage("Offre Black Friday"), "blog": MessageLookupByLibrary.simpleMessage("Blog"), + "cLDesc1": MessageLookupByLibrary.simpleMessage( + "Suite à la version bêta du streaming vidéo et au travail sur les téléchargements reprenables, nous avons maintenant augmenté la limite de téléchargement de fichiers à 10 Go. Ceci est maintenant disponible dans les applications desktop et mobiles."), + "cLDesc2": MessageLookupByLibrary.simpleMessage( + "Les téléchargements en arrière-plan sont maintenant pris en charge sur iOS également, en plus des appareils Android. Pas besoin d\'ouvrir l\'application pour sauvegarder vos dernières photos et vidéos."), + "cLDesc3": MessageLookupByLibrary.simpleMessage( + "Nous avons apporté des améliorations significatives à notre expérience de souvenirs, y compris la lecture automatique, le balayage vers le souvenir suivant et bien plus encore."), + "cLDesc4": MessageLookupByLibrary.simpleMessage( + "Avec un tas d\'améliorations internes, il est maintenant beaucoup plus facile de voir tous les visages détectés, de donner des commentaires sur les visages similaires et d\'ajouter/supprimer des visages d\'une seule photo."), + "cLDesc5": MessageLookupByLibrary.simpleMessage( + "Vous recevrez maintenant une notification optionnelle pour tous les anniversaires que vous avez sauvegardés sur Ente, ainsi qu\'une collection de leurs meilleures photos."), + "cLDesc6": MessageLookupByLibrary.simpleMessage( + "Plus besoin d\'attendre que les téléchargements se terminent avant de pouvoir fermer l\'application. Tous les téléchargements ont maintenant la capacité d\'être mis en pause à mi-chemin et de reprendre là où vous vous êtes arrêté."), + "cLTitle1": MessageLookupByLibrary.simpleMessage( + "Téléchargement de fichiers vidéo volumineux"), + "cLTitle2": MessageLookupByLibrary.simpleMessage( + "Téléchargement en arrière-plan"), + "cLTitle3": MessageLookupByLibrary.simpleMessage( + "Lecture automatique des souvenirs"), + "cLTitle4": MessageLookupByLibrary.simpleMessage( + "Reconnaissance faciale améliorée"), + "cLTitle5": MessageLookupByLibrary.simpleMessage( + "Notifications d\'anniversaire"), + "cLTitle6": + MessageLookupByLibrary.simpleMessage("Téléchargements reprenables"), "cachedData": MessageLookupByLibrary.simpleMessage("Données mises en cache"), "calculating": @@ -604,7 +680,7 @@ class MessageLookup extends MessageLookupByLibrary { "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage( "• Cliquez sur le menu de débordement"), "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), + "Cliquez pour installer notre meilleure version"), "close": MessageLookupByLibrary.simpleMessage("Fermer"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage("Grouper par durée"), @@ -757,9 +833,10 @@ class MessageLookup extends MessageLookupByLibrary { "deleteItemCount": m21, "deleteLocation": MessageLookupByLibrary.simpleMessage("Supprimer la localisation"), + "deleteMultipleAlbumDialog": m22, "deletePhotos": MessageLookupByLibrary.simpleMessage("Supprimer des photos"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Il manque une fonction clé dont j\'ai besoin"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -800,7 +877,7 @@ class MessageLookup extends MessageLookupByLibrary { "Les observateurs peuvent toujours prendre des captures d\'écran ou enregistrer une copie de vos photos en utilisant des outils externes"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Veuillez remarquer"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Désactiver l\'authentification à deux facteurs"), "disablingTwofactorAuthentication": @@ -845,10 +922,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Échec du téléchargement"), "downloading": MessageLookupByLibrary.simpleMessage("Téléchargement en cours..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("Éditer"), + "editEmailAlreadyLinked": m28, "editLocation": MessageLookupByLibrary.simpleMessage("Modifier l’emplacement"), "editLocationTagTitle": @@ -865,16 +943,16 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("E-mail"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage("Email déjà enregistré."), - "emailChangedTo": m28, - "emailDoesNotHaveEnteAccount": m29, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailDoesNotHaveEnteAccount": m30, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage("E-mail non enregistré."), "emailVerificationToggle": MessageLookupByLibrary.simpleMessage( "Authentification à deux facteurs par email"), "emailYourLogs": MessageLookupByLibrary.simpleMessage( "Envoyez vos journaux par email"), - "embracingThem": m31, + "embracingThem": m32, "emergencyContacts": MessageLookupByLibrary.simpleMessage("Contacts d\'urgence"), "empty": MessageLookupByLibrary.simpleMessage("Vider"), @@ -936,6 +1014,8 @@ class MessageLookup extends MessageLookupByLibrary { "Veuillez entrer une adresse email valide."), "enterYourEmailAddress": MessageLookupByLibrary.simpleMessage("Entrez votre adresse e-mail"), + "enterYourNewEmailAddress": MessageLookupByLibrary.simpleMessage( + "Entrez votre nouvelle adresse e-mail"), "enterYourPassword": MessageLookupByLibrary.simpleMessage("Entrez votre mot de passe"), "enterYourRecoveryKey": MessageLookupByLibrary.simpleMessage( @@ -952,7 +1032,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Exportez vos données"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage( "Photos supplémentaires trouvées"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage( "Ce visage n\'a pas encore été regroupé, veuillez revenir plus tard"), "faceRecognition": @@ -991,7 +1071,7 @@ class MessageLookup extends MessageLookupByLibrary { "faq": MessageLookupByLibrary.simpleMessage("FAQ"), "faqs": MessageLookupByLibrary.simpleMessage("FAQ"), "favorite": MessageLookupByLibrary.simpleMessage("Favori"), - "feastingWithThem": m33, + "feastingWithThem": m34, "feedback": MessageLookupByLibrary.simpleMessage("Commentaires"), "file": MessageLookupByLibrary.simpleMessage("Fichier"), "fileFailedToSaveToGallery": MessageLookupByLibrary.simpleMessage( @@ -1005,8 +1085,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Types de fichiers"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Types et noms de fichiers"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("Fichiers supprimés"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage( @@ -1024,25 +1104,27 @@ class MessageLookup extends MessageLookupByLibrary { "foundFaces": MessageLookupByLibrary.simpleMessage("Visages trouvés"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("Stockage gratuit obtenu"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("Stockage gratuit disponible"), "freeTrial": MessageLookupByLibrary.simpleMessage("Essai gratuit"), - "freeTrialValidTill": m37, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAccessPostDelete": m39, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage( "Libérer de l\'espace sur l\'appareil"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Économisez de l\'espace sur votre appareil en effaçant les fichiers qui ont déjà été sauvegardés."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Libérer de l\'espace"), + "freeUpSpaceSaving": m41, "gallery": MessageLookupByLibrary.simpleMessage("Galerie"), "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Jusqu\'à 1000 souvenirs affichés dans la galerie"), "general": MessageLookupByLibrary.simpleMessage("Général"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Génération des clés de chiffrement..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("Allez aux réglages"), "googlePlayId": @@ -1057,6 +1139,8 @@ class MessageLookup extends MessageLookupByLibrary { "guestView": MessageLookupByLibrary.simpleMessage("Vue invité"), "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( "Pour activer la vue invité, veuillez configurer le code d\'accès de l\'appareil ou le verrouillage de l\'écran dans les paramètres de votre système."), + "happyBirthday": + MessageLookupByLibrary.simpleMessage("Joyeux anniversaire ! 🥳"), "hearUsExplanation": MessageLookupByLibrary.simpleMessage( "Nous ne suivons pas les installations d\'applications. Il serait utile que vous nous disiez comment vous nous avez trouvés !"), "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( @@ -1073,7 +1157,7 @@ class MessageLookup extends MessageLookupByLibrary { "hideSharedItemsFromHomeGallery": MessageLookupByLibrary.simpleMessage( "Masquer les éléments partagés avec vous dans la galerie"), "hiding": MessageLookupByLibrary.simpleMessage("Masquage en cours..."), - "hikingWithThem": m42, + "hikingWithThem": m43, "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("Hébergé chez OSM France"), "howItWorks": @@ -1133,7 +1217,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Il semble qu\'une erreur s\'est produite. Veuillez réessayer après un certain temps. Si l\'erreur persiste, veuillez contacter notre équipe d\'assistance."), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Les éléments montrent le nombre de jours restants avant la suppression définitive"), @@ -1155,7 +1239,7 @@ class MessageLookup extends MessageLookupByLibrary { "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( "Merci de nous aider avec cette information"), "language": MessageLookupByLibrary.simpleMessage("Langue"), - "lastTimeWithThem": m44, + "lastTimeWithThem": m45, "lastUpdated": MessageLookupByLibrary.simpleMessage("Dernière mise à jour"), "lastYearsTrip": @@ -1170,7 +1254,7 @@ class MessageLookup extends MessageLookupByLibrary { "legacy": MessageLookupByLibrary.simpleMessage("Héritage"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("Comptes hérités"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage( "L\'héritage permet aux contacts de confiance d\'accéder à votre compte en votre absence."), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( @@ -1187,7 +1271,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("pour un partage plus rapide"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Activé"), "linkExpired": MessageLookupByLibrary.simpleMessage("Expiré"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Expiration du lien"), "linkHasExpired": @@ -1196,11 +1280,13 @@ class MessageLookup extends MessageLookupByLibrary { "linkPerson": MessageLookupByLibrary.simpleMessage("Lier la personne"), "linkPersonCaption": MessageLookupByLibrary.simpleMessage( "pour une meilleure expérience de partage"), - "linkPersonToEmail": m47, - "linkPersonToEmailConfirmation": m48, + "linkPersonToEmail": m48, + "linkPersonToEmailConfirmation": m49, "livePhotos": MessageLookupByLibrary.simpleMessage("Photos en direct"), "loadMessage1": MessageLookupByLibrary.simpleMessage( "Vous pouvez partager votre abonnement avec votre famille"), + "loadMessage2": MessageLookupByLibrary.simpleMessage( + "Nous avons préservé plus de 200 millions de souvenirs jusqu\'à présent"), "loadMessage3": MessageLookupByLibrary.simpleMessage( "Nous conservons 3 copies de vos données, l\'une dans un abri anti-atomique"), "loadMessage4": MessageLookupByLibrary.simpleMessage( @@ -1258,7 +1344,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Appuyez longuement sur un élément pour le voir en plein écran"), "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), + "Regarde tes souvenirs passés 🌄"), "loopVideoOff": MessageLookupByLibrary.simpleMessage("Vidéo en boucle désactivée"), "loopVideoOn": @@ -1288,7 +1374,10 @@ class MessageLookup extends MessageLookupByLibrary { "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), "me": MessageLookupByLibrary.simpleMessage("Moi"), - "memoryCount": m49, + "memories": MessageLookupByLibrary.simpleMessage("Souvenirs"), + "memoriesWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Sélectionnez le type de souvenirs que vous souhaitez voir sur votre écran d\'accueil."), + "memoryCount": m50, "merchandise": MessageLookupByLibrary.simpleMessage("Boutique"), "mergeWithExisting": MessageLookupByLibrary.simpleMessage("Fusionner avec existant"), @@ -1322,13 +1411,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Les plus pertinents"), "mountains": MessageLookupByLibrary.simpleMessage("Au-dessus des collines"), + "moveItem": m51, "moveSelectedPhotosToOneDate": MessageLookupByLibrary.simpleMessage( "Déplacer les photos sélectionnées vers une date"), "moveToAlbum": MessageLookupByLibrary.simpleMessage("Déplacer vers l\'album"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage( "Déplacer vers un album masqué"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("Déplacé dans la corbeille"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1343,7 +1433,7 @@ class MessageLookup extends MessageLookupByLibrary { "newAlbum": MessageLookupByLibrary.simpleMessage("Nouvel album"), "newLocation": MessageLookupByLibrary.simpleMessage("Nouveau lieu"), "newPerson": MessageLookupByLibrary.simpleMessage("Nouvelle personne"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), + "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" nouveau 📸"), "newRange": MessageLookupByLibrary.simpleMessage("Nouvelle plage"), "newToEnte": MessageLookupByLibrary.simpleMessage("Nouveau sur Ente"), "newest": MessageLookupByLibrary.simpleMessage("Le plus récent"), @@ -1383,10 +1473,10 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Aucun résultat"), "noResultsFound": MessageLookupByLibrary.simpleMessage("Aucun résultat trouvé"), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage("Aucun verrou système trouvé"), - "notPersonLabel": m53, + "notPersonLabel": m54, "notThisPerson": MessageLookupByLibrary.simpleMessage( "Ce n\'est pas cette personne ?"), "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( @@ -1400,10 +1490,12 @@ class MessageLookup extends MessageLookupByLibrary { "Sur Ente"), "onTheRoad": MessageLookupByLibrary.simpleMessage("De nouveau sur la route"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), + "onThisDay": MessageLookupByLibrary.simpleMessage("Ce jour-ci"), + "onThisDayMemories": + MessageLookupByLibrary.simpleMessage("Souvenirs du jour"), "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "Recevoir des rappels sur les souvenirs de cette journée des années précédentes."), + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("Seulement eux"), "oops": MessageLookupByLibrary.simpleMessage("Oups"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( @@ -1435,7 +1527,7 @@ class MessageLookup extends MessageLookupByLibrary { "pairingComplete": MessageLookupByLibrary.simpleMessage("Appairage terminé"), "panorama": MessageLookupByLibrary.simpleMessage("Panorama"), - "partyWithThem": m55, + "partyWithThem": m56, "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage( "La vérification est toujours en attente"), "passkey": MessageLookupByLibrary.simpleMessage( @@ -1447,18 +1539,20 @@ class MessageLookup extends MessageLookupByLibrary { "Le mot de passe a été modifié"), "passwordLock": MessageLookupByLibrary.simpleMessage( "Verrouillage par mot de passe"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "La force du mot de passe est calculée en tenant compte de la longueur du mot de passe, des caractères utilisés et du fait que le mot de passe figure ou non parmi les 10 000 mots de passe les plus utilisés"), "passwordWarning": MessageLookupByLibrary.simpleMessage( "Nous ne stockons pas ce mot de passe, donc si vous l\'oubliez, nous ne pouvons pas déchiffrer vos données"), + "pastYearsMemories": MessageLookupByLibrary.simpleMessage( + "Souvenirs de ces dernières années"), "paymentDetails": MessageLookupByLibrary.simpleMessage("Détails de paiement"), "paymentFailed": MessageLookupByLibrary.simpleMessage("Échec du paiement"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Malheureusement votre paiement a échoué. Veuillez contacter le support et nous vous aiderons !"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("Éléments en attente"), "pendingSync": @@ -1466,16 +1560,18 @@ class MessageLookup extends MessageLookupByLibrary { "people": MessageLookupByLibrary.simpleMessage("Personnes"), "peopleUsingYourCode": MessageLookupByLibrary.simpleMessage( "Filleul·e·s utilisant votre code"), + "peopleWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Sélectionnez les personnes que vous souhaitez voir sur votre écran d\'accueil."), "permDeleteWarning": MessageLookupByLibrary.simpleMessage( "Tous les éléments de la corbeille seront définitivement supprimés\n\nCette action ne peut pas être annulée"), "permanentlyDelete": MessageLookupByLibrary.simpleMessage("Supprimer définitivement"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage( "Supprimer définitivement de l\'appareil ?"), - "personIsAge": m58, + "personIsAge": m59, "personName": MessageLookupByLibrary.simpleMessage("Nom de la personne"), - "personTurningAge": m59, + "personTurningAge": m60, "pets": MessageLookupByLibrary.simpleMessage("Compagnons à quatre pattes"), "photoDescriptions": @@ -1483,11 +1579,12 @@ class MessageLookup extends MessageLookupByLibrary { "photoGridSize": MessageLookupByLibrary.simpleMessage("Taille de la grille photo"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("photo"), - "photocountPhotos": m60, + "photocountPhotos": m61, "photos": MessageLookupByLibrary.simpleMessage("Photos"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage( "Les photos ajoutées par vous seront retirées de l\'album"), + "photosCount": m62, "photosKeepRelativeTimeDifference": MessageLookupByLibrary.simpleMessage( "Les photos gardent une différence de temps relative"), @@ -1500,7 +1597,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Lire l\'album sur la TV"), "playOriginal": MessageLookupByLibrary.simpleMessage("Lire l\'original"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playStream": MessageLookupByLibrary.simpleMessage("Lire le stream"), "playstoreSubscription": MessageLookupByLibrary.simpleMessage("Abonnement au PlayStore"), @@ -1513,14 +1610,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Merci de contacter l\'assistance si cette erreur persiste"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage( "Veuillez accorder la permission"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Veuillez vous reconnecter"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Veuillez sélectionner les liens rapides à supprimer"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Veuillez réessayer"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1535,7 +1632,7 @@ class MessageLookup extends MessageLookupByLibrary { "Veuillez attendre quelque temps avant de réessayer"), "pleaseWaitThisWillTakeAWhile": MessageLookupByLibrary.simpleMessage( "Veuillez patienter, cela prendra un peu de temps."), - "posingWithThem": m65, + "posingWithThem": m66, "preparingLogs": MessageLookupByLibrary.simpleMessage("Préparation des journaux..."), "preserveMore": MessageLookupByLibrary.simpleMessage("Conserver plus"), @@ -1555,7 +1652,7 @@ class MessageLookup extends MessageLookupByLibrary { "processed": MessageLookupByLibrary.simpleMessage("Appris"), "processing": MessageLookupByLibrary.simpleMessage("Traitement en cours"), - "processingImport": m66, + "processingImport": m67, "processingVideos": MessageLookupByLibrary.simpleMessage("Traitement des vidéos"), "publicLinkCreated": @@ -1569,12 +1666,14 @@ class MessageLookup extends MessageLookupByLibrary { "rateTheApp": MessageLookupByLibrary.simpleMessage("Évaluer l\'application"), "rateUs": MessageLookupByLibrary.simpleMessage("Évaluez-nous"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "reassignMe": MessageLookupByLibrary.simpleMessage("Réassigner \"Moi\""), - "reassignedToName": m68, + "reassignedToName": m69, "reassigningLoading": MessageLookupByLibrary.simpleMessage("Réassignation..."), + "receiveRemindersOnBirthdays": MessageLookupByLibrary.simpleMessage( + "Recevoir des rappels quand c\'est l\'anniversaire de quelqu\'un. Appuyer sur la notification vous amènera à des photos de son anniversaire."), "recover": MessageLookupByLibrary.simpleMessage("Récupérer"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Récupérer un compte"), @@ -1583,7 +1682,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Récupérer un compte"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage("Récupération initiée"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("Clé de secours"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( "Clé de secours copiée dans le presse-papiers"), @@ -1597,12 +1696,12 @@ class MessageLookup extends MessageLookupByLibrary { "Clé de récupération vérifiée"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "Votre clé de récupération est la seule façon de récupérer vos photos si vous oubliez votre mot de passe. Vous pouvez trouver votre clé de récupération dans Paramètres > Compte.\n\nVeuillez saisir votre clé de récupération ici pour vous assurer de l\'avoir enregistré correctement."), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage("Restauration réussie !"), "recoveryWarning": MessageLookupByLibrary.simpleMessage( "Un contact de confiance tente d\'accéder à votre compte"), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "L\'appareil actuel n\'est pas assez puissant pour vérifier votre mot de passe, mais nous pouvons le régénérer d\'une manière qui fonctionne avec tous les appareils.\n\nVeuillez vous connecter à l\'aide de votre clé de secours et régénérer votre mot de passe (vous pouvez réutiliser le même si vous le souhaitez)."), "recreatePasswordTitle": @@ -1618,7 +1717,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Donnez ce code à vos ami·e·s"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Ils souscrivent à une offre payante"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("Parrainages"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Les recommandations sont actuellement en pause"), @@ -1650,7 +1749,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Supprimer le lien"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Supprimer le participant"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage( "Supprimer le libellé d\'une personne"), "removePublicLink": @@ -1672,7 +1771,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Renommer le fichier"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Renouveler l’abonnement"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Signaler un bogue"), "reportBug": MessageLookupByLibrary.simpleMessage("Signaler un bogue"), "resendEmail": @@ -1698,7 +1797,7 @@ class MessageLookup extends MessageLookupByLibrary { "reviewSuggestions": MessageLookupByLibrary.simpleMessage("Examiner les suggestions"), "right": MessageLookupByLibrary.simpleMessage("Droite"), - "roadtripWithThem": m75, + "roadtripWithThem": m76, "rotate": MessageLookupByLibrary.simpleMessage("Pivoter"), "rotateLeft": MessageLookupByLibrary.simpleMessage("Pivoter à gauche"), "rotateRight": @@ -1758,8 +1857,8 @@ class MessageLookup extends MessageLookupByLibrary { "Invitez quelqu\'un·e et vous verrez ici toutes les photos partagées"), "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage( "Les personnes seront affichées ici une fois le traitement terminé"), - "searchResultCount": m76, - "searchSectionsLengthMismatch": m77, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("Sécurité"), "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage( "Ouvrir les liens des albums publics dans l\'application"), @@ -1801,6 +1900,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Sélectionnez votre visage"), "selectYourPlan": MessageLookupByLibrary.simpleMessage("Sélectionner votre offre"), + "selectedAlbums": m79, "selectedFilesAreNotOnEnte": MessageLookupByLibrary.simpleMessage( "Les fichiers sélectionnés ne sont pas sur Ente"), "selectedFoldersWillBeEncryptedAndBackedUp": @@ -1812,9 +1912,9 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeRemovedFromThisPerson": MessageLookupByLibrary.simpleMessage( "Les éléments sélectionnés seront retirés de cette personne, mais pas supprimés de votre bibliothèque."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, - "selfiesWithThem": m80, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, + "selfiesWithThem": m82, "send": MessageLookupByLibrary.simpleMessage("Envoyer"), "sendEmail": MessageLookupByLibrary.simpleMessage("Envoyer un e-mail"), "sendInvite": @@ -1848,16 +1948,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage( "Partagez un album maintenant"), "shareLink": MessageLookupByLibrary.simpleMessage("Partager le lien"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Partagez uniquement avec les personnes que vous souhaitez"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Téléchargez Ente pour pouvoir facilement partager des photos et vidéos en qualité originale\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Partager avec des utilisateurs non-Ente"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage( "Partagez votre premier album"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1868,7 +1968,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Nouvelles photos partagées"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "Recevoir des notifications quand quelqu\'un·e ajoute une photo à un album partagé dont vous faites partie"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Partagés avec moi"), "sharedWithYou": @@ -1888,12 +1988,14 @@ class MessageLookup extends MessageLookupByLibrary { "Déconnecter les autres appareils"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "J\'accepte les conditions d\'utilisation et la politique de confidentialité"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "Elle sera supprimée de tous les albums."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("Ignorer"), + "smartMemories": + MessageLookupByLibrary.simpleMessage("Souvenirs intelligents"), "social": MessageLookupByLibrary.simpleMessage("Retrouvez nous"), "someItemsAreInBothEnteAndYourDevice": MessageLookupByLibrary.simpleMessage( @@ -1910,6 +2012,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Quelque chose s\'est mal passé, veuillez recommencer"), "sorry": MessageLookupByLibrary.simpleMessage("Désolé"), + "sorryBackupFailedDesc": MessageLookupByLibrary.simpleMessage( + "Désolé, nous n\'avons pas pu sauvegarder ce fichier maintenant, nous allons réessayer plus tard."), "sorryCouldNotAddToFavorites": MessageLookupByLibrary.simpleMessage( "Désolé, impossible d\'ajouter aux favoris !"), "sorryCouldNotRemoveFromFavorites": @@ -1922,7 +2026,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Désolé, nous n\'avons pas pu générer de clés sécurisées sur cet appareil.\n\nVeuillez vous inscrire depuis un autre appareil."), "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), + "Désolé, nous avons dû mettre en pause vos sauvegardes"), "sort": MessageLookupByLibrary.simpleMessage("Trier"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Trier par"), "sortNewestFirst": @@ -1930,8 +2034,8 @@ class MessageLookup extends MessageLookupByLibrary { "sortOldestFirst": MessageLookupByLibrary.simpleMessage("Plus ancien en premier"), "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ Succès"), - "sportsWithThem": m89, - "spotlightOnThem": m90, + "sportsWithThem": m91, + "spotlightOnThem": m92, "spotlightOnYourself": MessageLookupByLibrary.simpleMessage("Éclairage sur vous-même"), "startAccountRecoveryTitle": @@ -1946,15 +2050,15 @@ class MessageLookup extends MessageLookupByLibrary { "storage": MessageLookupByLibrary.simpleMessage("Stockage"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Famille"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Vous"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage("Limite de stockage atteinte"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "streamDetails": MessageLookupByLibrary.simpleMessage("Détails du stream"), "strongStrength": MessageLookupByLibrary.simpleMessage("Forte"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("S\'abonner"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "Vous avez besoin d\'un abonnement payant actif pour activer le partage."), @@ -1972,7 +2076,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Suggérer une fonctionnalité"), "sunrise": MessageLookupByLibrary.simpleMessage("À l\'horizon"), "support": MessageLookupByLibrary.simpleMessage("Support"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("Synchronisation arrêtée ?"), "syncing": MessageLookupByLibrary.simpleMessage( @@ -1985,7 +2089,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Appuyer pour déverrouiller"), "tapToUpload": MessageLookupByLibrary.simpleMessage("Appuyer pour envoyer"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Il semble qu\'une erreur s\'est produite. Veuillez réessayer après un certain temps. Si l\'erreur persiste, veuillez contacter notre équipe d\'assistance."), "terminate": MessageLookupByLibrary.simpleMessage("Se déconnecter"), @@ -2009,7 +2113,7 @@ class MessageLookup extends MessageLookupByLibrary { "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage( "Ces éléments seront supprimés de votre appareil."), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage( "Ils seront supprimés de tous les albums."), "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( @@ -2027,12 +2131,12 @@ class MessageLookup extends MessageLookupByLibrary { "Cette image n\'a pas de données exif"), "thisIsMeExclamation": MessageLookupByLibrary.simpleMessage("C\'est moi !"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( "Ceci est votre ID de vérification"), "thisWeekThroughTheYears": MessageLookupByLibrary.simpleMessage( "Cette semaine au fil des années"), - "thisWeekXYearsAgo": m99, + "thisWeekXYearsAgo": m101, "thisWillLogYouOutOfTheFollowingDevice": MessageLookupByLibrary.simpleMessage( "Cela vous déconnectera de l\'appareil suivant :"), @@ -2044,7 +2148,7 @@ class MessageLookup extends MessageLookupByLibrary { "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( "Ceci supprimera les liens publics de tous les liens rapides sélectionnés."), - "throughTheYears": m100, + "throughTheYears": m102, "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": MessageLookupByLibrary.simpleMessage( "Pour activer le verrouillage de l\'application vous devez configurer le code d\'accès de l\'appareil ou le verrouillage de l\'écran dans les paramètres de votre système."), @@ -2058,13 +2162,13 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("total"), "totalSize": MessageLookupByLibrary.simpleMessage("Taille totale"), "trash": MessageLookupByLibrary.simpleMessage("Corbeille"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("Recadrer"), - "tripInYear": m102, - "tripToLocation": m103, + "tripInYear": m104, + "tripToLocation": m105, "trustedContacts": MessageLookupByLibrary.simpleMessage("Contacts de confiance"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("Réessayer"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "Activez la sauvegarde pour charger automatiquement sur Ente les fichiers ajoutés à ce dossier de l\'appareil."), @@ -2084,7 +2188,7 @@ class MessageLookup extends MessageLookupByLibrary { "L\'authentification à deux facteurs a été réinitialisée avec succès "), "twofactorSetup": MessageLookupByLibrary.simpleMessage( "Configuration de l\'authentification à deux facteurs"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("Désarchiver"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("Désarchiver l\'album"), @@ -2112,10 +2216,10 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage( "Mise à jour de la sélection du dossier..."), "upgrade": MessageLookupByLibrary.simpleMessage("Améliorer"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Envoi des fichiers vers l\'album..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage( "Sauvegarde d\'un souvenir..."), "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( @@ -2133,7 +2237,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage( "Utiliser la photo sélectionnée"), "usedSpace": MessageLookupByLibrary.simpleMessage("Stockage utilisé"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "La vérification a échouée, veuillez réessayer"), @@ -2142,7 +2246,7 @@ class MessageLookup extends MessageLookupByLibrary { "verify": MessageLookupByLibrary.simpleMessage("Vérifier"), "verifyEmail": MessageLookupByLibrary.simpleMessage("Vérifier l\'email"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Vérifier"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("Vérifier la clé de sécurité"), @@ -2154,6 +2258,8 @@ class MessageLookup extends MessageLookupByLibrary { "Vérification de la clé de récupération..."), "videoInfo": MessageLookupByLibrary.simpleMessage("Informations vidéo"), "videoSmallCase": MessageLookupByLibrary.simpleMessage("vidéo"), + "videoStreaming": + MessageLookupByLibrary.simpleMessage("Vidéos diffusables"), "videos": MessageLookupByLibrary.simpleMessage("Vidéos"), "viewActiveSessions": MessageLookupByLibrary.simpleMessage( "Afficher les connexions actives"), @@ -2168,10 +2274,11 @@ class MessageLookup extends MessageLookupByLibrary { "Affichez les fichiers qui consomment le plus de stockage."), "viewLogs": MessageLookupByLibrary.simpleMessage("Afficher les journaux"), - "viewPersonToUnlink": m110, + "viewPersonToUnlink": m112, "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("Voir la clé de récupération"), "viewer": MessageLookupByLibrary.simpleMessage("Observateur"), + "viewersSuccessfullyAdded": m113, "visitWebToManage": MessageLookupByLibrary.simpleMessage( "Vous pouvez gérer votre abonnement sur web.ente.io"), "waitingForVerification": MessageLookupByLibrary.simpleMessage( @@ -2184,15 +2291,17 @@ class MessageLookup extends MessageLookupByLibrary { "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "Nous ne prenons pas en charge l\'édition des photos et des albums que vous ne possédez pas encore"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Securité Faible"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Bienvenue !"), "whatsNew": MessageLookupByLibrary.simpleMessage("Nouveautés"), "whyAddTrustContact": MessageLookupByLibrary.simpleMessage( "Un contact de confiance peut vous aider à récupérer vos données."), + "widgets": MessageLookupByLibrary.simpleMessage("Gadgets"), + "wishThemAHappyBirthday": m115, "yearShort": MessageLookupByLibrary.simpleMessage("an"), "yearly": MessageLookupByLibrary.simpleMessage("Annuel"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Oui"), "yesCancel": MessageLookupByLibrary.simpleMessage("Oui, annuler"), "yesConvertToViewer": MessageLookupByLibrary.simpleMessage( @@ -2207,7 +2316,7 @@ class MessageLookup extends MessageLookupByLibrary { "yesResetPerson": MessageLookupByLibrary.simpleMessage( "Oui, réinitialiser la personne"), "you": MessageLookupByLibrary.simpleMessage("Vous"), - "youAndThem": m114, + "youAndThem": m117, "youAreOnAFamilyPlan": MessageLookupByLibrary.simpleMessage( "Vous êtes sur un plan familial !"), "youAreOnTheLatestVersion": MessageLookupByLibrary.simpleMessage( @@ -2226,7 +2335,7 @@ class MessageLookup extends MessageLookupByLibrary { "Vous ne pouvez pas partager avec vous-même"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( "Vous n\'avez aucun élément archivé."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("Votre compte a été supprimé"), "yourMap": MessageLookupByLibrary.simpleMessage("Votre carte"), diff --git a/mobile/lib/generated/intl/messages_gu.dart b/mobile/lib/generated/intl/messages_gu.dart index 9defce9a5d..886d0aadff 100644 --- a/mobile/lib/generated/intl/messages_gu.dart +++ b/mobile/lib/generated/intl/messages_gu.dart @@ -20,17 +20,9 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'gu'; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => { - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups") - }; + static Map _notInlinedMessages(_) => + {"wishThemAHappyBirthday": m115}; } diff --git a/mobile/lib/generated/intl/messages_he.dart b/mobile/lib/generated/intl/messages_he.dart index 1dc7ace827..b0d3ee8e5c 100644 --- a/mobile/lib/generated/intl/messages_he.dart +++ b/mobile/lib/generated/intl/messages_he.dart @@ -43,81 +43,83 @@ class MessageLookup extends MessageLookupByLibrary { "אנא צור איתנו קשר ב-support@ente.io על מנת לנהל את המנוי ${provider}."; static String m21(count) => - "${Intl.plural(count, one: 'מחק ${count} פריט', two: 'מחק ${count} פריטים', other: 'מחק ${count} פריטים')}"; + "${Intl.plural(count, one: 'מחק ${count} פריט', other: 'מחק ${count} פריטים')}"; - static String m22(currentlyDeleting, totalCount) => + static String m23(currentlyDeleting, totalCount) => "מוחק ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "זה יסיר את הלינק הפומבי שדרכו ניתן לגשת ל\"${albumName}\"."; - static String m24(supportEmail) => + static String m25(supportEmail) => "אנא תשלח דוא\"ל ל${supportEmail} מהכתובת דוא\"ל שנרשמת איתה"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} קבצים, כל אחד ${formattedSize}"; - static String m30(email) => + static String m31(email) => "לא נמצא חשבון ente ל-${email}.\n\nשלח להם הזמנה על מנת לשתף תמונות."; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "${storageAmountInGB} GB כל פעם שמישהו נרשם עבור תוכנית בתשלום ומחיל את הקוד שלך"; - static String m37(endDate) => "ניסיון חינם בתוקף עד ל-${endDate}"; + static String m38(endDate) => "ניסיון חינם בתוקף עד ל-${endDate}"; - static String m43(count) => - "${Intl.plural(count, one: '${count} פריט', two: '${count} פריטים', many: '${count} פריטים', other: '${count} פריטים')}"; + static String m44(count) => + "${Intl.plural(count, one: '${count} פריט', other: '${count} פריטים')}"; - static String m46(expiryTime) => "תוקף הקישור יפוג ב-${expiryTime}"; + static String m47(expiryTime) => "תוקף הקישור יפוג ב-${expiryTime}"; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "חוזק הסיסמא: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "אנא דבר עם התמיכה של ${providerName} אם אתה חוייבת"; - static String m67(storeName) => "דרג אותנו ב-${storeName}"; + static String m68(storeName) => "דרג אותנו ב-${storeName}"; - static String m72(storageInGB) => "3. שניכים מקבלים ${storageInGB} GB* בחינם"; + static String m73(storageInGB) => "3. שניכים מקבלים ${storageInGB} GB* בחינם"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} יוסר מהאלבום המשותף הזה\n\nגם תמונות שנוספו על ידיהם יוסרו מהאלבום"; - static String m78(count) => "${count} נבחרו"; + static String m80(count) => "${count} נבחרו"; - static String m79(count, yourCount) => "${count} נבחרו (${yourCount} שלך)"; + static String m81(count, yourCount) => "${count} נבחרו (${yourCount} שלך)"; - static String m81(verificationID) => + static String m83(verificationID) => "הנה מזהה האימות שלי: ${verificationID} עבור ente.io."; - static String m82(verificationID) => + static String m84(verificationID) => "היי, תוכל לוודא שזה מזהה האימות שלך של ente.io: ${verificationID}"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'שתף עם אנשים ספציפיים', one: 'שותף עם איש 1', two: 'שותף עם 2 אנשים', other: 'שותף עם ${numberOfPeople} אנשים')}"; - static String m85(emailIDs) => "הושתף ע\"י ${emailIDs}"; + static String m87(emailIDs) => "הושתף ע\"י ${emailIDs}"; - static String m86(fileType) => "${fileType} יימחק מהמכשיר שלך."; + static String m88(fileType) => "${fileType} יימחק מהמכשיר שלך."; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; - static String m94(endDate) => "המנוי שלך יבוטל ב-${endDate}"; + static String m96(endDate) => "המנוי שלך יבוטל ב-${endDate}"; - static String m95(completed, total) => "${completed}/${total} זכרונות נשמרו"; + static String m97(completed, total) => "${completed}/${total} זכרונות נשמרו"; - static String m97(storageAmountInGB) => "הם גם יקבלו ${storageAmountInGB} GB"; + static String m99(storageAmountInGB) => "הם גם יקבלו ${storageAmountInGB} GB"; - static String m98(email) => "זה מזהה האימות של ${email}"; + static String m100(email) => "זה מזהה האימות של ${email}"; - static String m109(email) => "אמת ${email}"; + static String m111(email) => "אמת ${email}"; - static String m112(email) => "שלחנו דוא\"ל ל${email}"; + static String m114(email) => "שלחנו דוא\"ל ל${email}"; - static String m113(count) => - "${Intl.plural(count, one: 'לפני ${count} שנה', two: 'לפני ${count} שנים', many: 'לפני ${count} שנים', other: 'לפני ${count} שנים')}"; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; - static String m115(storageSaved) => "הצלחת לפנות ${storageSaved}!"; + static String m116(count) => + "${Intl.plural(count, one: 'לפני ${count} שנה', other: 'לפני ${count} שנים')}"; + + static String m118(storageSaved) => "הצלחת לפנות ${storageSaved}!"; final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { @@ -254,8 +256,6 @@ class MessageLookup extends MessageLookupByLibrary { "claimed": MessageLookupByLibrary.simpleMessage("נתבע"), "claimedStorageSoFar": m14, "click": MessageLookupByLibrary.simpleMessage("• לחץ"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "close": MessageLookupByLibrary.simpleMessage("סגור"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage("קבץ לפי זמן הצילום"), @@ -357,7 +357,7 @@ class MessageLookup extends MessageLookupByLibrary { "deleteFromDevice": MessageLookupByLibrary.simpleMessage("מחק מהמכשיר"), "deleteItemCount": m21, "deletePhotos": MessageLookupByLibrary.simpleMessage("מחק תמונות"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage("חסר מאפיין מרכזי שאני צריך"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -382,7 +382,7 @@ class MessageLookup extends MessageLookupByLibrary { "צופים יכולים עדיין לקחת צילומי מסך או לשמור עותק של התמונות שלך בעזרת כלים חיצוניים"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("שים לב"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage("השבת דו-גורמי"), "discord": MessageLookupByLibrary.simpleMessage("Discord"), @@ -393,12 +393,12 @@ class MessageLookup extends MessageLookupByLibrary { "download": MessageLookupByLibrary.simpleMessage("הורד"), "downloadFailed": MessageLookupByLibrary.simpleMessage("ההורדה נכשלה"), "downloading": MessageLookupByLibrary.simpleMessage("מוריד..."), - "dropSupportEmail": m24, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("ערוך"), "eligible": MessageLookupByLibrary.simpleMessage("זכאי"), "email": MessageLookupByLibrary.simpleMessage("דוא\"ל"), - "emailNoEnteAccount": m30, + "emailNoEnteAccount": m31, "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("אימות מייל"), "empty": MessageLookupByLibrary.simpleMessage("ריק"), @@ -467,11 +467,11 @@ class MessageLookup extends MessageLookupByLibrary { "forgotPassword": MessageLookupByLibrary.simpleMessage("שכחתי סיסמה"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("מקום אחסון בחינם נתבע"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("מקום אחסון שמיש"), "freeTrial": MessageLookupByLibrary.simpleMessage("ניסיון חינמי"), - "freeTrialValidTill": m37, + "freeTrialValidTill": m38, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("פנה אחסון במכשיר"), "freeUpSpace": MessageLookupByLibrary.simpleMessage("פנה מקום"), @@ -509,7 +509,7 @@ class MessageLookup extends MessageLookupByLibrary { "invite": MessageLookupByLibrary.simpleMessage("הזמן"), "inviteYourFriends": MessageLookupByLibrary.simpleMessage("הזמן את חברייך"), - "itemCount": m43, + "itemCount": m44, "itemsWillBeRemovedFromAlbum": MessageLookupByLibrary.simpleMessage( "הפריטים שנבחרו יוסרו מהאלבום הזה"), "keepPhotos": MessageLookupByLibrary.simpleMessage("השאר תמונות"), @@ -531,7 +531,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("מגבלת כמות מכשירים"), "linkEnabled": MessageLookupByLibrary.simpleMessage("מאופשר"), "linkExpired": MessageLookupByLibrary.simpleMessage("פג תוקף"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("תאריך תפוגה ללינק"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("הקישור פג תוקף"), @@ -547,8 +547,6 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "לחץ לחיצה ארוכה על פריט על מנת לראות אותו במסך מלא"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "lostDevice": MessageLookupByLibrary.simpleMessage("איבדת את המכשיר?"), "manage": MessageLookupByLibrary.simpleMessage("נהל"), "manageFamily": MessageLookupByLibrary.simpleMessage("נהל משפחה"), @@ -571,7 +569,6 @@ class MessageLookup extends MessageLookupByLibrary { "name": MessageLookupByLibrary.simpleMessage("שם"), "never": MessageLookupByLibrary.simpleMessage("לעולם לא"), "newAlbum": MessageLookupByLibrary.simpleMessage("אלבום חדש"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "newest": MessageLookupByLibrary.simpleMessage("החדש ביותר"), "no": MessageLookupByLibrary.simpleMessage("לא"), "noDeviceLimit": MessageLookupByLibrary.simpleMessage("אין"), @@ -591,9 +588,6 @@ class MessageLookup extends MessageLookupByLibrary { "onDevice": MessageLookupByLibrary.simpleMessage("על המכשיר"), "onEnte": MessageLookupByLibrary.simpleMessage("באנטע"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), "oops": MessageLookupByLibrary.simpleMessage("אופס"), "oopsSomethingWentWrong": MessageLookupByLibrary.simpleMessage("אופס, משהו השתבש"), @@ -606,12 +600,12 @@ class MessageLookup extends MessageLookupByLibrary { "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage("הססמה הוחלפה בהצלחה"), "passwordLock": MessageLookupByLibrary.simpleMessage("נעילת סיסמא"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordWarning": MessageLookupByLibrary.simpleMessage( "אנחנו לא שומרים את הסיסמא הזו, לכן אם אתה שוכח אותה, אנחנו לא יכולים לפענח את המידע שלך"), "paymentDetails": MessageLookupByLibrary.simpleMessage("פרטי תשלום"), "paymentFailed": MessageLookupByLibrary.simpleMessage("התשלום נכשל"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "peopleUsingYourCode": MessageLookupByLibrary.simpleMessage("אנשים משתמשים בקוד שלך"), "permanentlyDelete": @@ -653,7 +647,7 @@ class MessageLookup extends MessageLookupByLibrary { "raiseTicket": MessageLookupByLibrary.simpleMessage("צור ticket"), "rateTheApp": MessageLookupByLibrary.simpleMessage("דרג את האפליקציה"), "rateUs": MessageLookupByLibrary.simpleMessage("דרג אותנו"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "recover": MessageLookupByLibrary.simpleMessage("שחזר"), "recoverAccount": MessageLookupByLibrary.simpleMessage("שחזר חשבון"), "recoverButton": MessageLookupByLibrary.simpleMessage("שחזר"), @@ -679,7 +673,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. תמסור את הקוד הזה לחברייך"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. הם נרשמים עבור תוכנית בתשלום"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("הפניות"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage("הפניות כרגע מושהות"), @@ -695,7 +689,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("הסר מהאלבום?"), "removeLink": MessageLookupByLibrary.simpleMessage("הסרת קישור"), "removeParticipant": MessageLookupByLibrary.simpleMessage("הסר משתתף"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePublicLink": MessageLookupByLibrary.simpleMessage("הסר לינק ציבורי"), "removeShareItemsWarning": MessageLookupByLibrary.simpleMessage( @@ -746,8 +740,8 @@ class MessageLookup extends MessageLookupByLibrary { "selectedFoldersWillBeEncryptedAndBackedUp": MessageLookupByLibrary.simpleMessage( "התיקיות שנבחרו יוצפנו ויגובו"), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, "send": MessageLookupByLibrary.simpleMessage("שלח"), "sendEmail": MessageLookupByLibrary.simpleMessage("שלח דוא\"ל"), "sendInvite": MessageLookupByLibrary.simpleMessage("שלח הזמנה"), @@ -766,15 +760,15 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("שתף אלבום עכשיו"), "shareLink": MessageLookupByLibrary.simpleMessage("שתף קישור"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage("שתף רק אם אנשים שאתה בוחר"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "הורד את ente על מנת שנוכל לשתף תמונות וסרטונים באיכות המקור באופן קל\n\nhttps://ente.io"), "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "שתף עם משתמשים שהם לא של ente"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage("שתף את האלבום הראשון שלך"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -785,13 +779,13 @@ class MessageLookup extends MessageLookupByLibrary { "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "קבל התראות כשמישהו מוסיף תמונה לאלבום משותף שאתה חלק ממנו"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("שותף איתי"), "sharing": MessageLookupByLibrary.simpleMessage("משתף..."), "showMemories": MessageLookupByLibrary.simpleMessage("הצג זכרונות"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "אני מסכים לתנאי שירות ולמדיניות הפרטיות"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage("זה יימחק מכל האלבומים."), "skip": MessageLookupByLibrary.simpleMessage("דלג"), @@ -812,8 +806,6 @@ class MessageLookup extends MessageLookupByLibrary { "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "אנחנו מצטערים, לא הצלחנו ליצור מפתחות מאובטחים על מכשיר זה.\n\nאנא הירשם ממכשיר אחר."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("מיין לפי"), "sortOldestFirst": MessageLookupByLibrary.simpleMessage("הישן ביותר קודם"), @@ -822,18 +814,18 @@ class MessageLookup extends MessageLookupByLibrary { "storage": MessageLookupByLibrary.simpleMessage("אחסון"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("משפחה"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("אתה"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage("גבול מקום האחסון נחרג"), "strongStrength": MessageLookupByLibrary.simpleMessage("חזקה"), - "subWillBeCancelledOn": m94, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("הרשם"), "subscription": MessageLookupByLibrary.simpleMessage("מנוי"), "success": MessageLookupByLibrary.simpleMessage("הצלחה"), "suggestFeatures": MessageLookupByLibrary.simpleMessage("הציעו מאפיינים"), "support": MessageLookupByLibrary.simpleMessage("תמיכה"), - "syncProgress": m95, + "syncProgress": m97, "syncing": MessageLookupByLibrary.simpleMessage("מסנכרן..."), "systemTheme": MessageLookupByLibrary.simpleMessage("מערכת"), "tapToCopy": MessageLookupByLibrary.simpleMessage("הקש כדי להעתיק"), @@ -849,12 +841,12 @@ class MessageLookup extends MessageLookupByLibrary { "theDownloadCouldNotBeCompleted": MessageLookupByLibrary.simpleMessage("לא ניתן להשלים את ההורדה"), "theme": MessageLookupByLibrary.simpleMessage("ערכת נושא"), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "thisCanBeUsedToRecoverYourAccountIfYou": MessageLookupByLibrary.simpleMessage( "זה יכול לשמש לשחזור החשבון שלך במקרה ותאבד את הגורם השני"), "thisDevice": MessageLookupByLibrary.simpleMessage("מכשיר זה"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage("זה מזהה האימות שלך"), "thisWillLogYouOutOfTheFollowingDevice": @@ -898,7 +890,7 @@ class MessageLookup extends MessageLookupByLibrary { "verificationId": MessageLookupByLibrary.simpleMessage("מזהה אימות"), "verify": MessageLookupByLibrary.simpleMessage("אמת"), "verifyEmail": MessageLookupByLibrary.simpleMessage("אימות דוא\"ל"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("אמת"), "verifyPassword": MessageLookupByLibrary.simpleMessage("אמת סיסמא"), "verifyingRecoveryKey": @@ -915,11 +907,12 @@ class MessageLookup extends MessageLookupByLibrary { "אנא בקר ב-web.ente.io על מנת לנהל את המנוי שלך"), "weAreOpenSource": MessageLookupByLibrary.simpleMessage("הקוד שלנו פתוח!"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("חלשה"), "welcomeBack": MessageLookupByLibrary.simpleMessage("ברוך שובך!"), + "wishThemAHappyBirthday": m115, "yearly": MessageLookupByLibrary.simpleMessage("שנתי"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("כן"), "yesCancel": MessageLookupByLibrary.simpleMessage("כן, בטל"), "yesConvertToViewer": @@ -942,7 +935,7 @@ class MessageLookup extends MessageLookupByLibrary { "אתה לא יכול לשנמך לתוכנית הזו"), "youCannotShareWithYourself": MessageLookupByLibrary.simpleMessage("אתה לא יכול לשתף עם עצמך"), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("החשבון שלך נמחק"), "yourPlanWasSuccessfullyDowngraded": diff --git a/mobile/lib/generated/intl/messages_hi.dart b/mobile/lib/generated/intl/messages_hi.dart index 59162b906f..a8910cfd07 100644 --- a/mobile/lib/generated/intl/messages_hi.dart +++ b/mobile/lib/generated/intl/messages_hi.dart @@ -20,6 +20,8 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'hi'; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { "accountWelcomeBack": @@ -28,8 +30,6 @@ class MessageLookup extends MessageLookupByLibrary { "askDeleteReason": MessageLookupByLibrary.simpleMessage( "आपका अकाउंट हटाने का मुख्य कारण क्या है?"), "cancel": MessageLookupByLibrary.simpleMessage("रद्द करें"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage( "अकाउंट डिलीट करने की पुष्टि करें"), "confirmPassword": @@ -77,17 +77,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("अमान्य ईमेल ऐड्रेस"), "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( "कृपया हमें इस जानकारी के लिए सहायता करें"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "noRecoveryKey": MessageLookupByLibrary.simpleMessage("रिकवरी कुंजी नहीं है?"), "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( "हमारे एंड-टू-एंड एन्क्रिप्शन प्रोटोकॉल की प्रकृति के कारण, आपके डेटा को आपके पासवर्ड या रिकवरी कुंजी के बिना डिक्रिप्ट नहीं किया जा सकता है"), "ok": MessageLookupByLibrary.simpleMessage("ठीक है"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), "oops": MessageLookupByLibrary.simpleMessage("ओह!"), "password": MessageLookupByLibrary.simpleMessage("पासवर्ड"), "recoverButton": MessageLookupByLibrary.simpleMessage("पुनः प्राप्त"), @@ -99,8 +93,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "कुछ गड़बड़ हुई है। कृपया दोबारा प्रयास करें।"), "sorry": MessageLookupByLibrary.simpleMessage("क्षमा करें!"), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "terminate": MessageLookupByLibrary.simpleMessage("रद्द करें"), "terminateSession": MessageLookupByLibrary.simpleMessage("सेशन रद्द करें?"), @@ -115,6 +107,7 @@ class MessageLookup extends MessageLookupByLibrary { "verify": MessageLookupByLibrary.simpleMessage("सत्यापित करें"), "verifyEmail": MessageLookupByLibrary.simpleMessage("ईमेल सत्यापित करें"), + "wishThemAHappyBirthday": m115, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage( "आपका अकाउंट डिलीट कर दिया गया है") }; diff --git a/mobile/lib/generated/intl/messages_hu.dart b/mobile/lib/generated/intl/messages_hu.dart index 90bbe64bf5..466fc30549 100644 --- a/mobile/lib/generated/intl/messages_hu.dart +++ b/mobile/lib/generated/intl/messages_hu.dart @@ -20,6 +20,8 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'hu'; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { "accountWelcomeBack": @@ -27,8 +29,6 @@ class MessageLookup extends MessageLookupByLibrary { "askDeleteReason": MessageLookupByLibrary.simpleMessage("Miért törli a fiókját?"), "cancel": MessageLookupByLibrary.simpleMessage("Mégse"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "deleteAccount": MessageLookupByLibrary.simpleMessage("Fiók törlése"), "deleteAccountFeedbackPrompt": MessageLookupByLibrary.simpleMessage( "Sajnáljuk, hogy távozik. Kérjük, ossza meg velünk visszajelzéseit, hogy segítsen nekünk a fejlődésben."), @@ -40,14 +40,7 @@ class MessageLookup extends MessageLookupByLibrary { "feedback": MessageLookupByLibrary.simpleMessage("Visszajelzés"), "invalidEmailAddress": MessageLookupByLibrary.simpleMessage("Érvénytelen e-mail cím"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), - "verify": MessageLookupByLibrary.simpleMessage("Hitelesítés") + "verify": MessageLookupByLibrary.simpleMessage("Hitelesítés"), + "wishThemAHappyBirthday": m115 }; } diff --git a/mobile/lib/generated/intl/messages_id.dart b/mobile/lib/generated/intl/messages_id.dart index 131cd0fdab..bfd30d79be 100644 --- a/mobile/lib/generated/intl/messages_id.dart +++ b/mobile/lib/generated/intl/messages_id.dart @@ -62,129 +62,131 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'Hapus ${count} item', other: 'Hapus ${count} item')}"; - static String m22(currentlyDeleting, totalCount) => + static String m23(currentlyDeleting, totalCount) => "Menghapus ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "Ini akan menghapus link publik yang digunakan untuk mengakses \"${albumName}\"."; - static String m24(supportEmail) => + static String m25(supportEmail) => "Silakan kirimkan email ke ${supportEmail} dari alamat email terdaftar kamu"; - static String m25(count, storageSaved) => + static String m26(count, storageSaved) => "Kamu telah menghapus ${Intl.plural(count, other: '${count} file duplikat')} dan membersihkan (${storageSaved}!)"; - static String m28(newEmail) => "Email diubah menjadi ${newEmail}"; + static String m29(newEmail) => "Email diubah menjadi ${newEmail}"; - static String m30(email) => + static String m31(email) => "${email} tidak punya akun Ente.\n\nUndang dia untuk berbagi foto."; - static String m34(count, formattedNumber) => + static String m35(count, formattedNumber) => "${Intl.plural(count, other: '${formattedNumber} file')} di perangkat ini telah berhasil dicadangkan"; - static String m35(count, formattedNumber) => + static String m36(count, formattedNumber) => "${Intl.plural(count, other: '${formattedNumber} file')} dalam album ini telah berhasil dicadangkan"; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "${storageAmountInGB} GB setiap kali orang mendaftar dengan paket berbayar lalu menerapkan kode milikmu"; - static String m37(endDate) => "Percobaan gratis berlaku hingga ${endDate}"; + static String m38(endDate) => "Percobaan gratis berlaku hingga ${endDate}"; - static String m39(sizeInMBorGB) => "Bersihkan ${sizeInMBorGB}"; + static String m40(sizeInMBorGB) => "Bersihkan ${sizeInMBorGB}"; - static String m41(currentlyProcessing, totalCount) => + static String m42(currentlyProcessing, totalCount) => "Memproses ${currentlyProcessing} / ${totalCount}"; - static String m43(count) => "${Intl.plural(count, other: '${count} item')}"; + static String m44(count) => "${Intl.plural(count, other: '${count} item')}"; - static String m46(expiryTime) => "Link akan kedaluwarsa pada ${expiryTime}"; + static String m47(expiryTime) => "Link akan kedaluwarsa pada ${expiryTime}"; - static String m51(albumName) => "Berhasil dipindahkan ke ${albumName}"; + static String m52(albumName) => "Berhasil dipindahkan ke ${albumName}"; - static String m54(familyAdminEmail) => + static String m55(familyAdminEmail) => "Harap hubungi ${familyAdminEmail} untuk mengubah kode kamu."; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Keamanan sandi: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "Harap hubungi dukungan ${providerName} jika kamu dikenai biaya"; - static String m62(endDate) => + static String m63(endDate) => "Percobaan gratis berlaku hingga ${endDate}.\nKamu dapat memilih paket berbayar setelahnya."; - static String m63(toEmail) => "Silakan kirimi kami email di ${toEmail}"; + static String m64(toEmail) => "Silakan kirimi kami email di ${toEmail}"; - static String m64(toEmail) => "Silakan kirim log-nya ke \n${toEmail}"; + static String m65(toEmail) => "Silakan kirim log-nya ke \n${toEmail}"; - static String m67(storeName) => "Beri nilai di ${storeName}"; + static String m68(storeName) => "Beri nilai di ${storeName}"; - static String m72(storageInGB) => + static String m73(storageInGB) => "3. Kalian berdua mendapat ${storageInGB} GB* gratis"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} akan dikeluarkan dari album berbagi ini\n\nSemua foto yang ia tambahkan juga akan dihapus dari album ini"; - static String m74(endDate) => "Langganan akan diperpanjang pada ${endDate}"; + static String m75(endDate) => "Langganan akan diperpanjang pada ${endDate}"; - static String m76(count) => + static String m77(count) => "${Intl.plural(count, other: '${count} hasil ditemukan')}"; - static String m78(count) => "${count} terpilih"; + static String m80(count) => "${count} terpilih"; - static String m79(count, yourCount) => + static String m81(count, yourCount) => "${count} dipilih (${yourCount} milikmu)"; - static String m81(verificationID) => + static String m83(verificationID) => "Ini ID Verifikasi saya di ente.io: ${verificationID}."; - static String m82(verificationID) => + static String m84(verificationID) => "Halo, bisakah kamu pastikan bahwa ini adalah ID Verifikasi ente.io milikmu: ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Kode rujukan Ente: ${referralCode} \n\nTerapkan pada Pengaturan → Umum → Rujukan untuk mendapatkan ${referralStorageInGB} GB gratis setelah kamu mendaftar paket berbayar\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Bagikan dengan orang tertentu', one: 'Berbagi dengan 1 orang', other: 'Berbagi dengan ${numberOfPeople} orang')}"; - static String m85(emailIDs) => "Dibagikan dengan ${emailIDs}"; + static String m87(emailIDs) => "Dibagikan dengan ${emailIDs}"; - static String m86(fileType) => + static String m88(fileType) => "${fileType} ini akan dihapus dari perangkat ini."; - static String m87(fileType) => + static String m89(fileType) => "${fileType} ini tersimpan di Ente dan juga di perangkat ini."; - static String m88(fileType) => "${fileType} ini akan dihapus dari Ente."; + static String m90(fileType) => "${fileType} ini akan dihapus dari Ente."; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} dari ${totalAmount} ${totalStorageUnit} terpakai"; - static String m93(id) => + static String m95(id) => "${id} kamu telah terhubung dengan akun Ente lain.\nJika kamu ingin menggunakan ${id} kamu untuk akun ini, silahkan hubungi tim bantuan kami"; - static String m94(endDate) => + static String m96(endDate) => "Langganan kamu akan dibatalkan pada ${endDate}"; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "Ia juga mendapat ${storageAmountInGB} GB"; - static String m98(email) => "Ini adalah ID Verifikasi milik ${email}"; + static String m100(email) => "Ini adalah ID Verifikasi milik ${email}"; - static String m108(endDate) => "Berlaku hingga ${endDate}"; + static String m110(endDate) => "Berlaku hingga ${endDate}"; - static String m109(email) => "Verifikasi ${email}"; + static String m111(email) => "Verifikasi ${email}"; - static String m112(email) => + static String m114(email) => "Kami telah mengirimkan email ke ${email}"; - static String m113(count) => + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + + static String m116(count) => "${Intl.plural(count, other: '${count} tahun lalu')}"; - static String m115(storageSaved) => + static String m118(storageSaved) => "Kamu telah berhasil membersihkan ${storageSaved}!"; final messages = _notInlinedMessages(_notInlinedMessages); @@ -246,6 +248,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Izinkan pengunduhan"), "allowPeopleToAddPhotos": MessageLookupByLibrary.simpleMessage( "Izinkan orang lain menambahkan foto"), + "allowPermBody": MessageLookupByLibrary.simpleMessage( + "Ijinkan akses ke foto Anda dari Pengaturan agar Ente dapat menampilkan dan mencadangkan pustaka Anda."), + "allowPermTitle": + MessageLookupByLibrary.simpleMessage("Izinkan akses ke foto"), "androidBiometricHint": MessageLookupByLibrary.simpleMessage("Verifikasi identitas"), "androidBiometricNotRecognized": @@ -388,8 +394,6 @@ class MessageLookup extends MessageLookupByLibrary { "claimedStorageSoFar": m14, "clearIndexes": MessageLookupByLibrary.simpleMessage("Hapus indeks"), "click": MessageLookupByLibrary.simpleMessage("• Click"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "close": MessageLookupByLibrary.simpleMessage("Tutup"), "codeAppliedPageTitle": MessageLookupByLibrary.simpleMessage("Kode diterapkan"), @@ -505,7 +509,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Hapus dari Ente"), "deleteItemCount": m21, "deletePhotos": MessageLookupByLibrary.simpleMessage("Hapus foto"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Fitur penting yang saya perlukan tidak ada"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -541,20 +545,25 @@ class MessageLookup extends MessageLookupByLibrary { "Orang yang melihat masih bisa mengambil tangkapan layar atau menyalin foto kamu menggunakan alat eksternal"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Perlu diketahui"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Nonaktifkan autentikasi dua langkah"), "disablingTwofactorAuthentication": MessageLookupByLibrary.simpleMessage( "Menonaktifkan autentikasi dua langkah..."), "discord": MessageLookupByLibrary.simpleMessage("Discord"), + "discover": MessageLookupByLibrary.simpleMessage("Temukan"), "discover_babies": MessageLookupByLibrary.simpleMessage("Bayi"), + "discover_celebrations": + MessageLookupByLibrary.simpleMessage("Perayaan"), "discover_food": MessageLookupByLibrary.simpleMessage("Makanan"), "discover_hills": MessageLookupByLibrary.simpleMessage("Bukit"), "discover_identity": MessageLookupByLibrary.simpleMessage("Identitas"), "discover_memes": MessageLookupByLibrary.simpleMessage("Meme"), "discover_notes": MessageLookupByLibrary.simpleMessage("Catatan"), "discover_pets": MessageLookupByLibrary.simpleMessage("Hewan"), + "discover_receipts": + MessageLookupByLibrary.simpleMessage("Tanda Terima"), "discover_screenshots": MessageLookupByLibrary.simpleMessage("Tangkapan layar"), "discover_selfies": MessageLookupByLibrary.simpleMessage("Swafoto"), @@ -576,8 +585,8 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("Gagal mengunduh"), "downloading": MessageLookupByLibrary.simpleMessage("Mengunduh..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, "edit": MessageLookupByLibrary.simpleMessage("Edit"), "editLocation": MessageLookupByLibrary.simpleMessage("Edit lokasi"), "editLocationTagTitle": @@ -589,8 +598,12 @@ class MessageLookup extends MessageLookupByLibrary { "Perubahan lokasi hanya akan terlihat di Ente"), "eligible": MessageLookupByLibrary.simpleMessage("memenuhi syarat"), "email": MessageLookupByLibrary.simpleMessage("Email"), - "emailChangedTo": m28, - "emailNoEnteAccount": m30, + "emailAlreadyRegistered": + MessageLookupByLibrary.simpleMessage("Email sudah terdaftar."), + "emailChangedTo": m29, + "emailNoEnteAccount": m31, + "emailNotRegistered": + MessageLookupByLibrary.simpleMessage("Email belum terdaftar."), "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("Verifikasi email"), "empty": MessageLookupByLibrary.simpleMessage("Kosongkan"), @@ -638,6 +651,8 @@ class MessageLookup extends MessageLookupByLibrary { "Harap masukkan alamat email yang sah."), "enterYourEmailAddress": MessageLookupByLibrary.simpleMessage("Masukkan alamat email kamu"), + "enterYourNewEmailAddress": MessageLookupByLibrary.simpleMessage( + "Masukkan alamat email baru anda"), "enterYourPassword": MessageLookupByLibrary.simpleMessage("Masukkan sandi kamu"), "enterYourRecoveryKey": MessageLookupByLibrary.simpleMessage( @@ -688,8 +703,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Jenis file"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Nama dan jenis file"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("File terhapus"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage("File tersimpan ke galeri"), @@ -703,12 +718,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Wajah yang ditemukan"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("Kuota gratis diperoleh"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage( "Kuota gratis yang dapat digunakan"), "freeTrial": MessageLookupByLibrary.simpleMessage("Percobaan gratis"), - "freeTrialValidTill": m37, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage( "Bersihkan penyimpanan perangkat"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( @@ -717,7 +732,7 @@ class MessageLookup extends MessageLookupByLibrary { "general": MessageLookupByLibrary.simpleMessage("Umum"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Menghasilkan kunci enkripsi..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("Buka pengaturan"), "googlePlayId": MessageLookupByLibrary.simpleMessage("ID Google Play"), "grantFullAccessPrompt": MessageLookupByLibrary.simpleMessage( @@ -777,7 +792,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Sepertinya terjadi kesalahan. Silakan coba lagi setelah beberapa saat. Jika kesalahan terus terjadi, silakan hubungi tim dukungan kami."), - "itemCount": m43, + "itemCount": m44, "itemsWillBeRemovedFromAlbum": MessageLookupByLibrary.simpleMessage( "Item yang dipilih akan dihapus dari album ini"), "joinDiscord": @@ -804,7 +819,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Batas perangkat"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Aktif"), "linkExpired": MessageLookupByLibrary.simpleMessage("Kedaluwarsa"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Waktu kedaluwarsa link"), "linkHasExpired": @@ -846,14 +861,16 @@ class MessageLookup extends MessageLookupByLibrary { "longPressAnEmailToVerifyEndToEndEncryption": MessageLookupByLibrary.simpleMessage( "Tekan dan tahan email untuk membuktikan enkripsi ujung ke ujung."), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "lostDevice": MessageLookupByLibrary.simpleMessage("Perangkat hilang?"), "machineLearning": MessageLookupByLibrary.simpleMessage("Pemelajaran mesin"), "magicSearch": MessageLookupByLibrary.simpleMessage("Penelusuran ajaib"), "manage": MessageLookupByLibrary.simpleMessage("Atur"), + "manageDeviceStorage": + MessageLookupByLibrary.simpleMessage("Mengelola cache perangkat"), + "manageDeviceStorageDesc": MessageLookupByLibrary.simpleMessage( + "Tinjau dan hapus penyimpanan cache lokal."), "manageFamily": MessageLookupByLibrary.simpleMessage("Atur Keluarga"), "manageLink": MessageLookupByLibrary.simpleMessage("Atur link"), "manageParticipants": MessageLookupByLibrary.simpleMessage("Atur"), @@ -887,7 +904,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Pindahkan ke album"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage( "Pindahkan ke album tersembunyi"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("Pindah ke sampah"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -899,7 +916,6 @@ class MessageLookup extends MessageLookupByLibrary { "Tidak dapat terhubung dengan Ente, harap periksa pengaturan jaringan kamu dan hubungi dukungan jika masalah berlanjut."), "never": MessageLookupByLibrary.simpleMessage("Tidak pernah"), "newAlbum": MessageLookupByLibrary.simpleMessage("Album baru"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "newToEnte": MessageLookupByLibrary.simpleMessage("Baru di Ente"), "newest": MessageLookupByLibrary.simpleMessage("Terbaru"), "no": MessageLookupByLibrary.simpleMessage("Tidak"), @@ -939,10 +955,7 @@ class MessageLookup extends MessageLookupByLibrary { "onDevice": MessageLookupByLibrary.simpleMessage("Di perangkat ini"), "onEnte": MessageLookupByLibrary.simpleMessage( "Di ente"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "onlyFamilyAdminCanChangeCode": m55, "oops": MessageLookupByLibrary.simpleMessage("Aduh"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( "Aduh, tidak dapat menyimpan perubahan"), @@ -969,7 +982,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Sandi berhasil diubah"), "passwordLock": MessageLookupByLibrary.simpleMessage("Kunci dengan sandi"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordWarning": MessageLookupByLibrary.simpleMessage( "Kami tidak menyimpan sandi ini, jadi jika kamu melupakannya, kami tidak akan bisa mendekripsi data kamu"), "paymentDetails": @@ -978,7 +991,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Pembayaran gagal"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Sayangnya, pembayaranmu gagal. Silakan hubungi tim bantuan agar dapat kami bantu!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("Item menunggu"), "pendingSync": MessageLookupByLibrary.simpleMessage("Sinkronisasi tertunda"), @@ -1001,7 +1014,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Foto yang telah kamu tambahkan akan dihapus dari album ini"), "playOnTv": MessageLookupByLibrary.simpleMessage("Putar album di TV"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("Langganan PlayStore"), "pleaseCheckYourInternetConnectionAndTryAgain": @@ -1013,12 +1026,12 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Silakan hubungi tim bantuan jika masalah terus terjadi"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage("Harap berikan izin"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Silakan masuk akun lagi"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Silakan coba lagi"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1052,7 +1065,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Buat tiket dukungan"), "rateTheApp": MessageLookupByLibrary.simpleMessage("Nilai app ini"), "rateUs": MessageLookupByLibrary.simpleMessage("Beri kami nilai"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "recover": MessageLookupByLibrary.simpleMessage("Pulihkan"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Pulihkan akun"), "recoverButton": MessageLookupByLibrary.simpleMessage("Pulihkan"), @@ -1080,7 +1093,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Berikan kode ini ke teman kamu"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Ia perlu daftar ke paket berbayar"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("Referensi"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage("Rujukan sedang dijeda"), @@ -1102,7 +1115,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Hapus link"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Hapus peserta"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Hapus label orang"), "removePublicLink": @@ -1118,7 +1131,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("Ubah nama file"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Perpanjang langganan"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Laporkan bug"), "reportBug": MessageLookupByLibrary.simpleMessage("Laporkan bug"), "resendEmail": @@ -1169,7 +1182,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Album, nama dan jenis file"), "searchHint5": MessageLookupByLibrary.simpleMessage( "Segera tiba: Penelusuran wajah & ajaib ✨"), - "searchResultCount": m76, + "searchResultCount": m77, "security": MessageLookupByLibrary.simpleMessage("Keamanan"), "selectALocation": MessageLookupByLibrary.simpleMessage("Pilih lokasi"), "selectALocationFirst": MessageLookupByLibrary.simpleMessage( @@ -1194,8 +1207,8 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage( "Item terpilih akan dihapus dari semua album dan dipindahkan ke sampah."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, "send": MessageLookupByLibrary.simpleMessage("Kirim"), "sendEmail": MessageLookupByLibrary.simpleMessage("Kirim email"), "sendInvite": MessageLookupByLibrary.simpleMessage("Kirim undangan"), @@ -1216,16 +1229,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Bagikan album sekarang"), "shareLink": MessageLookupByLibrary.simpleMessage("Bagikan link"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Bagikan hanya dengan orang yang kamu inginkan"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Unduh Ente agar kita bisa berbagi foto dan video kualitas asli dengan mudah\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Bagikan ke pengguna non-Ente"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage("Bagikan album pertamamu"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1238,7 +1251,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Foto terbagi baru"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "Terima notifikasi apabila seseorang menambahkan foto ke album bersama yang kamu ikuti"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Dibagikan dengan saya"), "sharedWithYou": @@ -1253,11 +1266,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Keluar di perangkat lain"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Saya menyetujui ketentuan layanan dan kebijakan privasi Ente"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "Ia akan dihapus dari semua album."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("Lewati"), "social": MessageLookupByLibrary.simpleMessage("Sosial"), "someItemsAreInBothEnteAndYourDevice": @@ -1272,6 +1285,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Terjadi kesalahan, silakan coba lagi"), "sorry": MessageLookupByLibrary.simpleMessage("Maaf"), + "sorryBackupFailedDesc": MessageLookupByLibrary.simpleMessage( + "Maaf, kami tidak dapat mencadangkan berkas ini sekarang, kami akan mencobanya kembali nanti."), "sorryCouldNotAddToFavorites": MessageLookupByLibrary.simpleMessage( "Maaf, tidak dapat menambahkan ke favorit!"), "sorryCouldNotRemoveFromFavorites": @@ -1283,8 +1298,6 @@ class MessageLookup extends MessageLookupByLibrary { "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "Maaf, kami tidak dapat menghasilkan kunci yang aman di perangkat ini.\n\nHarap mendaftar dengan perangkat lain."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Urut berdasarkan"), "sortNewestFirst": MessageLookupByLibrary.simpleMessage("Terbaru dulu"), @@ -1301,14 +1314,16 @@ class MessageLookup extends MessageLookupByLibrary { "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Keluarga"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Kamu"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage( "Batas penyimpanan terlampaui"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "strongStrength": MessageLookupByLibrary.simpleMessage("Kuat"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("Berlangganan"), + "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( + "Anda memerlukan langganan berbayar yang aktif untuk bisa berbagi."), "subscription": MessageLookupByLibrary.simpleMessage("Langganan"), "success": MessageLookupByLibrary.simpleMessage("Berhasil"), "successfullyArchived": @@ -1347,7 +1362,7 @@ class MessageLookup extends MessageLookupByLibrary { "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage( "Item ini akan dihapus dari perangkat ini."), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( "Tindakan ini tidak dapat dibatalkan"), "thisAlbumAlreadyHDACollaborativeLink": @@ -1361,7 +1376,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Email ini telah digunakan"), "thisImageHasNoExifData": MessageLookupByLibrary.simpleMessage( "Gambar ini tidak memiliki data exif"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( "Ini adalah ID Verifikasi kamu"), "thisWillLogYouOutOfTheFollowingDevice": @@ -1427,14 +1442,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Gunakan kunci pemulihan"), "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("Gunakan foto terpilih"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Verifikasi gagal, silakan coba lagi"), "verificationId": MessageLookupByLibrary.simpleMessage("ID Verifikasi"), "verify": MessageLookupByLibrary.simpleMessage("Verifikasi"), "verifyEmail": MessageLookupByLibrary.simpleMessage("Verifikasi email"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyPasskey": MessageLookupByLibrary.simpleMessage("Verifikasi passkey"), "verifyPassword": @@ -1464,13 +1479,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Menunggu WiFi..."), "weAreOpenSource": MessageLookupByLibrary.simpleMessage("Kode sumber kami terbuka!"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Lemah"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Selamat datang kembali!"), "whatsNew": MessageLookupByLibrary.simpleMessage("Hal yang baru"), + "wishThemAHappyBirthday": m115, "yearly": MessageLookupByLibrary.simpleMessage("Tahunan"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Ya"), "yesCancel": MessageLookupByLibrary.simpleMessage("Ya, batalkan"), "yesConvertToViewer": @@ -1497,7 +1513,7 @@ class MessageLookup extends MessageLookupByLibrary { "Kamu tidak bisa berbagi dengan dirimu sendiri"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( "Kamu tidak memiliki item di arsip."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("Akunmu telah dihapus"), "yourMap": MessageLookupByLibrary.simpleMessage("Peta kamu"), diff --git a/mobile/lib/generated/intl/messages_it.dart b/mobile/lib/generated/intl/messages_it.dart index b08b489223..a21f77dc1c 100644 --- a/mobile/lib/generated/intl/messages_it.dart +++ b/mobile/lib/generated/intl/messages_it.dart @@ -22,13 +22,24 @@ class MessageLookup extends MessageLookupByLibrary { static String m0(title) => "${title} (Io)"; + static String m1(count) => + "${Intl.plural(count, zero: 'Aggiungi collaboratore', one: 'Aggiungi collaboratore', other: 'Aggiungi collaboratori')}"; + + static String m2(count) => + "${Intl.plural(count, one: 'Aggiungi elemento', other: 'Aggiungi elementi')}"; + static String m3(storageAmount, endDate) => "Il tuo spazio aggiuntivo di ${storageAmount} è valido fino al ${endDate}"; + static String m4(count) => + "${Intl.plural(count, zero: 'Aggiungi visualizzatore', one: 'Add viewer', other: 'Aggiungi visualizzatori')}"; + static String m5(emailOrName) => "Aggiunto da ${emailOrName}"; static String m6(albumName) => "Aggiunto con successo su ${albumName}"; + static String m7(name) => "Ammirando ${name}"; + static String m8(count) => "${Intl.plural(count, zero: 'Nessun partecipante', one: '1 Partecipante', other: '${count} Partecipanti')}"; @@ -37,6 +48,8 @@ class MessageLookup extends MessageLookupByLibrary { static String m10(freeAmount, storageUnit) => "${freeAmount} ${storageUnit} liberi"; + static String m11(name) => "Bellissimi panorami con ${name}"; + static String m12(paymentProvider) => "Annulla prima il tuo abbonamento esistente da ${paymentProvider}"; @@ -70,175 +83,248 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'Elimina ${count} elemento', other: 'Elimina ${count} elementi')}"; - static String m22(currentlyDeleting, totalCount) => + static String m22(count) => + "Eliminare anche le foto (e i video) presenti su ${count} album da tutti gli altri album di cui fanno parte?"; + + static String m23(currentlyDeleting, totalCount) => "Eliminazione di ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "Questo rimuoverà il link pubblico per accedere a \"${albumName}\"."; - static String m24(supportEmail) => + static String m25(supportEmail) => "Per favore invia un\'email a ${supportEmail} dall\'indirizzo email con cui ti sei registrato"; - static String m25(count, storageSaved) => + static String m26(count, storageSaved) => "Hai ripulito ${Intl.plural(count, one: '${count} doppione', other: '${count} doppioni')}, salvando (${storageSaved}!)"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} file, ${formattedSize} l\'uno"; - static String m28(newEmail) => "Email cambiata in ${newEmail}"; + static String m28(name) => "Questa email è già collegata a ${name}."; - static String m29(email) => "${email} non ha un account Ente."; + static String m29(newEmail) => "Email cambiata in ${newEmail}"; - static String m30(email) => + static String m30(email) => "${email} non ha un account Ente."; + + static String m31(email) => "${email} non ha un account Ente.\n\nInvia un invito per condividere foto."; - static String m32(text) => "Trovate foto aggiuntive per ${text}"; + static String m32(name) => "Abbracciando ${name}"; - static String m34(count, formattedNumber) => - "${Intl.plural(count, one: '1 file', other: '${formattedNumber} file')} di quest\'album sono stati salvati in modo sicuro"; + static String m33(text) => "Trovate foto aggiuntive per ${text}"; + + static String m34(name) => "Festeggiando con ${name}"; static String m35(count, formattedNumber) => "${Intl.plural(count, one: '1 file', other: '${formattedNumber} file')} di quest\'album sono stati salvati in modo sicuro"; - static String m36(storageAmountInGB) => + static String m36(count, formattedNumber) => + "${Intl.plural(count, one: '1 file', other: '${formattedNumber} file')} di quest\'album sono stati salvati in modo sicuro"; + + static String m37(storageAmountInGB) => "${storageAmountInGB} GB ogni volta che qualcuno si iscrive a un piano a pagamento e applica il tuo codice"; - static String m37(endDate) => "La prova gratuita termina il ${endDate}"; + static String m38(endDate) => "La prova gratuita termina il ${endDate}"; - static String m39(sizeInMBorGB) => "Libera ${sizeInMBorGB}"; + static String m40(sizeInMBorGB) => "Libera ${sizeInMBorGB}"; - static String m41(currentlyProcessing, totalCount) => + static String m41(count, formattedSize) => + "${Intl.plural(count, one: 'Può essere cancellato per liberare ${formattedSize}', other: 'Possono essere cancellati per liberare ${formattedSize}')}"; + + static String m42(currentlyProcessing, totalCount) => "Elaborazione ${currentlyProcessing} / ${totalCount}"; - static String m43(count) => + static String m43(name) => "Escursioni con ${name}"; + + static String m44(count) => "${Intl.plural(count, one: '${count} elemento', other: '${count} elementi')}"; - static String m45(email) => + static String m45(name) => "Ultima volta con ${name}"; + + static String m46(email) => "${email} ti ha invitato a essere un contatto fidato"; - static String m46(expiryTime) => "Il link scadrà il ${expiryTime}"; + static String m47(expiryTime) => "Il link scadrà il ${expiryTime}"; - static String m47(email) => "Collega persona a ${email}"; + static String m48(email) => "Collega persona a ${email}"; - static String m51(albumName) => "Spostato con successo su ${albumName}"; + static String m49(personName, email) => + "Questo collegherà ${personName} a ${email}"; - static String m52(personName) => "Nessun suggerimento per ${personName}"; + static String m50(count, formattedCount) => + "${Intl.plural(count, zero: 'nessun ricordo', one: '${formattedCount} ricordo', other: '${formattedCount} ricordi')}"; - static String m53(name) => "Non è ${name}?"; + static String m51(count) => + "${Intl.plural(count, one: 'Sposta elemento', other: 'Sposta elementi')}"; - static String m54(familyAdminEmail) => + static String m52(albumName) => "Spostato con successo su ${albumName}"; + + static String m53(personName) => "Nessun suggerimento per ${personName}"; + + static String m54(name) => "Non è ${name}?"; + + static String m55(familyAdminEmail) => "Per favore contatta ${familyAdminEmail} per cambiare il tuo codice."; - static String m56(passwordStrengthValue) => + static String m56(name) => "Festa con ${name}"; + + static String m57(passwordStrengthValue) => "Sicurezza password: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "Si prega di parlare con il supporto di ${providerName} se ti è stato addebitato qualcosa"; - static String m62(endDate) => + static String m59(name, age) => "${name} ha ${age}!"; + + static String m60(name, age) => "${name} sta per compiere ${age} anni"; + + static String m61(count) => + "${Intl.plural(count, zero: 'Nessuna foto', one: '1 foto', other: '${count} foto')}"; + + static String m62(count) => + "${Intl.plural(count, zero: '0 foto', one: '1 foto', other: '${count} foto')}"; + + static String m63(endDate) => "Prova gratuita valida fino al ${endDate}.\nIn seguito potrai scegliere un piano a pagamento."; - static String m63(toEmail) => "Per favore invia un\'email a ${toEmail}"; + static String m64(toEmail) => "Per favore invia un\'email a ${toEmail}"; - static String m64(toEmail) => "Invia i log a \n${toEmail}"; + static String m65(toEmail) => "Invia i log a \n${toEmail}"; - static String m66(folderName) => "Elaborando ${folderName}..."; + static String m66(name) => "In posa con ${name}"; - static String m67(storeName) => "Valutaci su ${storeName}"; + static String m67(folderName) => "Elaborando ${folderName}..."; - static String m68(name) => "Riassegnato a ${name}"; + static String m68(storeName) => "Valutaci su ${storeName}"; - static String m69(days, email) => + static String m69(name) => "Riassegnato a ${name}"; + + static String m70(days, email) => "Puoi accedere all\'account dopo ${days} giorni. Una notifica verrà inviata a ${email}."; - static String m70(email) => + static String m71(email) => "Ora puoi recuperare l\'account di ${email} impostando una nuova password."; - static String m71(email) => + static String m72(email) => "${email} sta cercando di recuperare il tuo account."; - static String m72(storageInGB) => + static String m73(storageInGB) => "3. Ottenete entrambi ${storageInGB} GB* gratis"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} verrà rimosso da questo album condiviso\n\nQualsiasi foto aggiunta dall\'utente verrà rimossa dall\'album"; - static String m74(endDate) => "Si rinnova il ${endDate}"; + static String m75(endDate) => "Si rinnova il ${endDate}"; - static String m76(count) => + static String m76(name) => "Viaggio con ${name}"; + + static String m77(count) => "${Intl.plural(count, one: '${count} risultato trovato', other: '${count} risultati trovati')}"; - static String m78(count) => "${count} selezionati"; + static String m78(snapshotLength, searchLength) => + "Lunghezza sezioni non corrisponde: ${snapshotLength} != ${searchLength}"; - static String m79(count, yourCount) => + static String m79(count) => "${count} selezionati"; + + static String m80(count) => "${count} selezionati"; + + static String m81(count, yourCount) => "${count} selezionato (${yourCount} tuoi)"; - static String m81(verificationID) => + static String m82(name) => "Selfie con ${name}"; + + static String m83(verificationID) => "Ecco il mio ID di verifica: ${verificationID} per ente.io."; - static String m82(verificationID) => + static String m84(verificationID) => "Hey, puoi confermare che questo è il tuo ID di verifica: ${verificationID} su ente.io"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Codice invito Ente: ${referralCode} \n\nInseriscilo in Impostazioni → Generali → Inviti per ottenere ${referralStorageInGB} GB gratis dopo la sottoscrizione a un piano a pagamento\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Condividi con persone specifiche', one: 'Condividi con una persona', other: 'Condividi con ${numberOfPeople} persone')}"; - static String m85(emailIDs) => "Condiviso con ${emailIDs}"; + static String m87(emailIDs) => "Condiviso con ${emailIDs}"; - static String m86(fileType) => + static String m88(fileType) => "Questo ${fileType} verrà eliminato dal tuo dispositivo."; - static String m87(fileType) => + static String m89(fileType) => "Questo ${fileType} è sia su Ente che sul tuo dispositivo."; - static String m88(fileType) => "Questo ${fileType} verrà eliminato da Ente."; + static String m90(fileType) => "Questo ${fileType} verrà eliminato da Ente."; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m91(name) => "Sport con ${name}"; - static String m92( + static String m92(name) => "Riflettori su ${name}"; + + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; + + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} di ${totalAmount} ${totalStorageUnit} utilizzati"; - static String m93(id) => + static String m95(id) => "Il tuo ${id} è già collegato a un altro account Ente.\nSe desideri utilizzare il tuo ${id} con questo account, per favore contatta il nostro supporto\'\'"; - static String m94(endDate) => "L\'abbonamento verrà cancellato il ${endDate}"; + static String m96(endDate) => "L\'abbonamento verrà cancellato il ${endDate}"; - static String m95(completed, total) => + static String m97(completed, total) => "${completed}/${total} ricordi conservati"; - static String m96(ignoreReason) => + static String m98(ignoreReason) => "Tocca per caricare, il caricamento è attualmente ignorato a causa di ${ignoreReason}"; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "Anche loro riceveranno ${storageAmountInGB} GB"; - static String m98(email) => "Questo è l\'ID di verifica di ${email}"; + static String m100(email) => "Questo è l\'ID di verifica di ${email}"; static String m101(count) => + "${Intl.plural(count, one: 'Questa settimana, ${count} anno fa', other: 'Questa settimana, ${count} anni fa')}"; + + static String m102(dateFormat) => "${dateFormat} negli anni"; + + static String m103(count) => "${Intl.plural(count, zero: 'Presto', one: '1 giorno', other: '${count} giorni')}"; - static String m104(email) => + static String m104(year) => "Viaggio nel ${year}"; + + static String m105(location) => "Viaggio a ${location}"; + + static String m106(email) => "Sei stato invitato a essere un contatto Legacy da ${email}."; - static String m106(ignoreReason) => + static String m107(galleryType) => + "Il tipo di galleria ${galleryType} non è supportato per la rinomina"; + + static String m108(ignoreReason) => "Il caricamento è ignorato a causa di ${ignoreReason}"; - static String m107(count) => "Conservando ${count} ricordi..."; + static String m109(count) => "Conservando ${count} ricordi..."; - static String m108(endDate) => "Valido fino al ${endDate}"; + static String m110(endDate) => "Valido fino al ${endDate}"; - static String m109(email) => "Verifica ${email}"; + static String m111(email) => "Verifica ${email}"; - static String m112(email) => - "Abbiamo inviato una mail a ${email}"; + static String m112(name) => "Visualizza ${name} per scollegare"; static String m113(count) => + "${Intl.plural(count, zero: 'Added 0 visualizzatori', one: 'Added 1 visualizzatore', other: 'Added ${count} visualizzatori')}"; + + static String m114(email) => + "Abbiamo inviato una mail a ${email}"; + + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + + static String m116(count) => "${Intl.plural(count, one: '${count} anno fa', other: '${count} anni fa')}"; - static String m115(storageSaved) => + static String m117(name) => "Tu e ${name}"; + + static String m118(storageSaved) => "Hai liberato con successo ${storageSaved}!"; final messages = _notInlinedMessages(_notInlinedMessages); @@ -256,19 +342,28 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Bentornato!"), "ackPasswordLostWarning": MessageLookupByLibrary.simpleMessage( "Comprendo che se perdo la password potrei perdere l\'accesso ai miei dati poiché sono criptati end-to-end."), + "actionNotSupportedOnFavouritesAlbum": + MessageLookupByLibrary.simpleMessage( + "Questa azione non è supportata nei Preferiti"), "activeSessions": MessageLookupByLibrary.simpleMessage("Sessioni attive"), "add": MessageLookupByLibrary.simpleMessage("Aggiungi"), "addAName": MessageLookupByLibrary.simpleMessage("Aggiungi un nome"), "addANewEmail": MessageLookupByLibrary.simpleMessage("Aggiungi una nuova email"), + "addAlbumWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Aggiungi un widget per gli album nella schermata iniziale e torna qui per personalizzarlo."), "addCollaborator": MessageLookupByLibrary.simpleMessage("Aggiungi collaboratore"), + "addCollaborators": m1, "addFiles": MessageLookupByLibrary.simpleMessage("Aggiungi File"), "addFromDevice": MessageLookupByLibrary.simpleMessage("Aggiungi dal dispositivo"), + "addItem": m2, "addLocation": MessageLookupByLibrary.simpleMessage("Aggiungi luogo"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Aggiungi"), + "addMemoriesWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Aggiungi un widget dei ricordi nella schermata iniziale e torna qui per personalizzarlo."), "addMore": MessageLookupByLibrary.simpleMessage("Aggiungi altri"), "addName": MessageLookupByLibrary.simpleMessage("Aggiungi nome"), "addNameOrMerge": @@ -280,6 +375,10 @@ class MessageLookup extends MessageLookupByLibrary { "Dettagli dei componenti aggiuntivi"), "addOnValidTill": m3, "addOns": MessageLookupByLibrary.simpleMessage("Componenti aggiuntivi"), + "addParticipants": + MessageLookupByLibrary.simpleMessage("Aggiungi Partecipanti"), + "addPeopleWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Aggiungi un widget delle persone nella schermata iniziale e torna qui per personalizzarlo."), "addPhotos": MessageLookupByLibrary.simpleMessage("Aggiungi foto"), "addSelected": MessageLookupByLibrary.simpleMessage("Aggiungi selezionate"), @@ -292,6 +391,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Aggiungi contatto fidato"), "addViewer": MessageLookupByLibrary.simpleMessage("Aggiungi in sola lettura"), + "addViewers": m4, "addYourPhotosNow": MessageLookupByLibrary.simpleMessage("Aggiungi le tue foto ora"), "addedAs": MessageLookupByLibrary.simpleMessage("Aggiunto come"), @@ -299,6 +399,7 @@ class MessageLookup extends MessageLookupByLibrary { "addedSuccessfullyTo": m6, "addingToFavorites": MessageLookupByLibrary.simpleMessage("Aggiunto ai preferiti..."), + "admiringThem": m7, "advanced": MessageLookupByLibrary.simpleMessage("Avanzate"), "advancedSettings": MessageLookupByLibrary.simpleMessage("Avanzate"), "after1Day": MessageLookupByLibrary.simpleMessage("Dopo un giorno"), @@ -313,11 +414,15 @@ class MessageLookup extends MessageLookupByLibrary { "albumUpdated": MessageLookupByLibrary.simpleMessage("Album aggiornato"), "albums": MessageLookupByLibrary.simpleMessage("Album"), + "albumsWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Seleziona gli album che desideri vedere nella schermata principale."), "allClear": MessageLookupByLibrary.simpleMessage("✨ Tutto pulito"), "allMemoriesPreserved": MessageLookupByLibrary.simpleMessage("Tutti i ricordi conservati"), "allPersonGroupingWillReset": MessageLookupByLibrary.simpleMessage( "Tutti i raggruppamenti per questa persona saranno resettati e perderai tutti i suggerimenti fatti per questa persona"), + "allWillShiftRangeBasedOnFirst": MessageLookupByLibrary.simpleMessage( + "Questo è il primo nel gruppo. Altre foto selezionate si sposteranno automaticamente in base a questa nuova data"), "allow": MessageLookupByLibrary.simpleMessage("Consenti"), "allowAddPhotosDescription": MessageLookupByLibrary.simpleMessage( "Permetti anche alle persone con il link di aggiungere foto all\'album condiviso."), @@ -354,6 +459,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Android, iOS, Web, Desktop"), "androidSignInTitle": MessageLookupByLibrary.simpleMessage("Autenticazione necessaria"), + "appIcon": MessageLookupByLibrary.simpleMessage("Icona dell\'app"), "appLock": MessageLookupByLibrary.simpleMessage("Blocco app"), "appLockDescriptions": MessageLookupByLibrary.simpleMessage( "Scegli tra la schermata di blocco predefinita del dispositivo e una schermata di blocco personalizzata con PIN o password."), @@ -444,6 +550,7 @@ class MessageLookup extends MessageLookupByLibrary { "availableStorageSpace": m10, "backedUpFolders": MessageLookupByLibrary.simpleMessage("Cartelle salvate"), + "backgroundWithThem": m11, "backup": MessageLookupByLibrary.simpleMessage("Backup"), "backupFailed": MessageLookupByLibrary.simpleMessage("Backup fallito"), "backupFile": MessageLookupByLibrary.simpleMessage("File di backup"), @@ -456,10 +563,38 @@ class MessageLookup extends MessageLookupByLibrary { "Gli elementi che sono stati sottoposti a backup verranno mostrati qui"), "backupVideos": MessageLookupByLibrary.simpleMessage("Backup dei video"), + "beach": MessageLookupByLibrary.simpleMessage("Sabbia e mare"), "birthday": MessageLookupByLibrary.simpleMessage("Compleanno"), + "birthdayNotifications": + MessageLookupByLibrary.simpleMessage("Notifiche dei compleanni"), + "birthdays": MessageLookupByLibrary.simpleMessage("Compleanni"), "blackFridaySale": MessageLookupByLibrary.simpleMessage("Offerta del Black Friday"), "blog": MessageLookupByLibrary.simpleMessage("Blog"), + "cLDesc1": MessageLookupByLibrary.simpleMessage( + "Dopo la versione beta dello streaming video e il lavoro sui caricamenti e download ripresi, abbiamo ora aumentato il limite di caricamento file a 10GB. Questo è ora disponibile sia nelle app desktop che mobili."), + "cLDesc2": MessageLookupByLibrary.simpleMessage( + "I caricamenti in background sono ora supportati anche su iOS, oltre ai dispositivi Android. Non è necessario aprire l\'app per eseguire il backup delle tue foto e video più recenti."), + "cLDesc3": MessageLookupByLibrary.simpleMessage( + "Abbiamo apportato miglioramenti significativi alla nostra esperienza dei ricordi, inclusa la riproduzione automatica, scorrimento al ricordo successivo e molto altro."), + "cLDesc4": MessageLookupByLibrary.simpleMessage( + "Insieme a un sacco di miglioramenti interni, ora è molto più facile vedere tutti i volti rilevati, fornire feedback sui volti simili e aggiungere/rimuovere volti da una singola foto."), + "cLDesc5": MessageLookupByLibrary.simpleMessage( + "Ora riceverai una notifica opzionale per tutti i compleanni che hai salvato su Ente, insieme a una raccolta delle loro migliori foto."), + "cLDesc6": MessageLookupByLibrary.simpleMessage( + "Non più attese per il completamento di caricamenti/download prima di poter chiudere l\'app. Tutti i caricamenti e download ora hanno la capacità di essere messi in pausa a metà e ripresi da dove hai lasciato."), + "cLTitle1": MessageLookupByLibrary.simpleMessage( + "Caricamento di file video di grandi dimensioni"), + "cLTitle2": + MessageLookupByLibrary.simpleMessage("Caricamento in background"), + "cLTitle3": MessageLookupByLibrary.simpleMessage( + "Riproduzione automatica dei ricordi"), + "cLTitle4": MessageLookupByLibrary.simpleMessage( + "Riconoscimento facciale migliorato"), + "cLTitle5": + MessageLookupByLibrary.simpleMessage("Notifiche di compleanno"), + "cLTitle6": MessageLookupByLibrary.simpleMessage( + "Caricamenti e download ripresi"), "cachedData": MessageLookupByLibrary.simpleMessage("Dati nella cache"), "calculating": MessageLookupByLibrary.simpleMessage("Calcolando..."), "canNotOpenBody": MessageLookupByLibrary.simpleMessage( @@ -514,6 +649,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Controllo in corso..."), "checkingModels": MessageLookupByLibrary.simpleMessage("Verifica dei modelli..."), + "city": MessageLookupByLibrary.simpleMessage("In città"), "claimFreeStorage": MessageLookupByLibrary.simpleMessage("Richiedi spazio gratuito"), "claimMore": MessageLookupByLibrary.simpleMessage("Richiedine di più!"), @@ -529,7 +665,7 @@ class MessageLookup extends MessageLookupByLibrary { "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage("• Fai clic sul menu"), "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), + "Clicca per installare l\'ultima versione dell\'app"), "close": MessageLookupByLibrary.simpleMessage("Chiudi"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage("Club per tempo di cattura"), @@ -630,6 +766,8 @@ class MessageLookup extends MessageLookupByLibrary { "criticalUpdateAvailable": MessageLookupByLibrary.simpleMessage( "Un aggiornamento importante è disponibile"), "crop": MessageLookupByLibrary.simpleMessage("Ritaglia"), + "curatedMemories": + MessageLookupByLibrary.simpleMessage("Ricordi importanti"), "currentUsageIs": MessageLookupByLibrary.simpleMessage( "Spazio attualmente utilizzato "), "currentlyRunning": @@ -676,8 +814,9 @@ class MessageLookup extends MessageLookupByLibrary { "deleteItemCount": m21, "deleteLocation": MessageLookupByLibrary.simpleMessage("Elimina posizione"), + "deleteMultipleAlbumDialog": m22, "deletePhotos": MessageLookupByLibrary.simpleMessage("Elimina foto"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Manca una caratteristica chiave di cui ho bisogno"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -718,7 +857,7 @@ class MessageLookup extends MessageLookupByLibrary { "I visualizzatori possono scattare screenshot o salvare una copia delle foto utilizzando strumenti esterni"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Nota bene"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Disabilita autenticazione a due fattori"), "disablingTwofactorAuthentication": @@ -762,14 +901,16 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Scaricamento fallito"), "downloading": MessageLookupByLibrary.simpleMessage("Scaricamento in corso..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("Modifica"), + "editEmailAlreadyLinked": m28, "editLocation": MessageLookupByLibrary.simpleMessage("Modifica luogo"), "editLocationTagTitle": MessageLookupByLibrary.simpleMessage("Modifica luogo"), "editPerson": MessageLookupByLibrary.simpleMessage("Modifica persona"), + "editTime": MessageLookupByLibrary.simpleMessage("Modifica orario"), "editsSaved": MessageLookupByLibrary.simpleMessage("Modifiche salvate"), "editsToLocationWillOnlyBeSeenWithinEnte": MessageLookupByLibrary.simpleMessage( @@ -778,15 +919,16 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("Email"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage("Email già registrata."), - "emailChangedTo": m28, - "emailDoesNotHaveEnteAccount": m29, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailDoesNotHaveEnteAccount": m30, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage("Email non registrata."), "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("Verifica Email"), "emailYourLogs": MessageLookupByLibrary.simpleMessage( "Invia una mail con i tuoi log"), + "embracingThem": m32, "emergencyContacts": MessageLookupByLibrary.simpleMessage("Contatti di emergenza"), "empty": MessageLookupByLibrary.simpleMessage("Svuota"), @@ -848,6 +990,8 @@ class MessageLookup extends MessageLookupByLibrary { "Inserisci un indirizzo email valido."), "enterYourEmailAddress": MessageLookupByLibrary.simpleMessage( "Inserisci il tuo indirizzo email"), + "enterYourNewEmailAddress": MessageLookupByLibrary.simpleMessage( + "Inserisci il tuo nuovo indirizzo email"), "enterYourPassword": MessageLookupByLibrary.simpleMessage("Inserisci la tua password"), "enterYourRecoveryKey": MessageLookupByLibrary.simpleMessage( @@ -862,12 +1006,13 @@ class MessageLookup extends MessageLookupByLibrary { "exportYourData": MessageLookupByLibrary.simpleMessage("Esporta dati"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage("Trovate foto aggiuntive"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage( "Faccia non ancora raggruppata, per favore torna più tardi"), "faceRecognition": MessageLookupByLibrary.simpleMessage("Riconoscimento facciale"), "faces": MessageLookupByLibrary.simpleMessage("Volti"), + "failed": MessageLookupByLibrary.simpleMessage("Non riuscito"), "failedToApplyCode": MessageLookupByLibrary.simpleMessage( "Impossibile applicare il codice"), "failedToCancel": @@ -899,6 +1044,7 @@ class MessageLookup extends MessageLookupByLibrary { "faq": MessageLookupByLibrary.simpleMessage("FAQ"), "faqs": MessageLookupByLibrary.simpleMessage("FAQ"), "favorite": MessageLookupByLibrary.simpleMessage("Preferito"), + "feastingWithThem": m34, "feedback": MessageLookupByLibrary.simpleMessage("Suggerimenti"), "file": MessageLookupByLibrary.simpleMessage("File"), "fileFailedToSaveToGallery": MessageLookupByLibrary.simpleMessage( @@ -912,8 +1058,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Tipi di file"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Tipi e nomi di file"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("File eliminati"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage("File salvati nella galleria"), @@ -922,6 +1068,7 @@ class MessageLookup extends MessageLookupByLibrary { "findThemQuickly": MessageLookupByLibrary.simpleMessage("Trovali rapidamente"), "flip": MessageLookupByLibrary.simpleMessage("Capovolgi"), + "food": MessageLookupByLibrary.simpleMessage("Delizia culinaria"), "forYourMemories": MessageLookupByLibrary.simpleMessage("per i tuoi ricordi"), "forgotPassword": @@ -929,24 +1076,25 @@ class MessageLookup extends MessageLookupByLibrary { "foundFaces": MessageLookupByLibrary.simpleMessage("Volti trovati"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("Spazio gratuito richiesto"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("Spazio libero utilizzabile"), "freeTrial": MessageLookupByLibrary.simpleMessage("Prova gratuita"), - "freeTrialValidTill": m37, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("Libera spazio"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Risparmia spazio sul tuo dispositivo cancellando i file che sono già stati salvati online."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Libera spazio"), + "freeUpSpaceSaving": m41, "gallery": MessageLookupByLibrary.simpleMessage("Galleria"), "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Fino a 1000 ricordi mostrati nella galleria"), "general": MessageLookupByLibrary.simpleMessage("Generali"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Generazione delle chiavi di crittografia..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("Vai alle impostazioni"), "googlePlayId": MessageLookupByLibrary.simpleMessage("Google Play ID"), @@ -954,11 +1102,14 @@ class MessageLookup extends MessageLookupByLibrary { "Consenti l\'accesso a tutte le foto nelle Impostazioni"), "grantPermission": MessageLookupByLibrary.simpleMessage("Concedi il permesso"), + "greenery": MessageLookupByLibrary.simpleMessage("In mezzo al verde"), "groupNearbyPhotos": MessageLookupByLibrary.simpleMessage( "Raggruppa foto nelle vicinanze"), "guestView": MessageLookupByLibrary.simpleMessage("Vista ospite"), "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( "Per abilitare la vista ospite, configura il codice di accesso del dispositivo o il blocco schermo nelle impostazioni di sistema."), + "happyBirthday": + MessageLookupByLibrary.simpleMessage("Buon compleanno! 🥳"), "hearUsExplanation": MessageLookupByLibrary.simpleMessage( "Non teniamo traccia del numero di installazioni dell\'app. Sarebbe utile se ci dicesse dove ci ha trovato!"), "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( @@ -975,6 +1126,7 @@ class MessageLookup extends MessageLookupByLibrary { "hideSharedItemsFromHomeGallery": MessageLookupByLibrary.simpleMessage( "Nascondi gli elementi condivisi dalla galleria principale"), "hiding": MessageLookupByLibrary.simpleMessage("Nascondendo..."), + "hikingWithThem": m43, "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("Ospitato presso OSM France"), "howItWorks": MessageLookupByLibrary.simpleMessage("Come funziona"), @@ -1008,6 +1160,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Elementi indicizzati"), "indexingIsPaused": MessageLookupByLibrary.simpleMessage( "L\'indicizzazione è in pausa. Riprenderà automaticamente quando il dispositivo è pronto."), + "ineligible": MessageLookupByLibrary.simpleMessage("Non idoneo"), "info": MessageLookupByLibrary.simpleMessage("Info"), "insecureDevice": MessageLookupByLibrary.simpleMessage("Dispositivo non sicuro"), @@ -1031,14 +1184,21 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Sembra che qualcosa sia andato storto. Riprova tra un po\'. Se l\'errore persiste, contatta il nostro team di supporto."), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Gli elementi mostrano il numero di giorni rimanenti prima della cancellazione permanente"), "itemsWillBeRemovedFromAlbum": MessageLookupByLibrary.simpleMessage( "Gli elementi selezionati saranno rimossi da questo album"), + "join": MessageLookupByLibrary.simpleMessage("Unisciti"), + "joinAlbum": + MessageLookupByLibrary.simpleMessage("Unisciti all\'album"), "joinAlbumConfirmationDialogBody": MessageLookupByLibrary.simpleMessage( "Unirsi a un album renderà visibile la tua email ai suoi partecipanti."), + "joinAlbumSubtext": MessageLookupByLibrary.simpleMessage( + "per visualizzare e aggiungere le tue foto"), + "joinAlbumSubtextViewer": MessageLookupByLibrary.simpleMessage( + "per aggiungerla agli album condivisi"), "joinDiscord": MessageLookupByLibrary.simpleMessage("Unisciti a Discord"), "keepPhotos": MessageLookupByLibrary.simpleMessage("Mantieni foto"), @@ -1046,8 +1206,11 @@ class MessageLookup extends MessageLookupByLibrary { "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( "Aiutaci con queste informazioni"), "language": MessageLookupByLibrary.simpleMessage("Lingua"), + "lastTimeWithThem": m45, "lastUpdated": MessageLookupByLibrary.simpleMessage("Ultimo aggiornamento"), + "lastYearsTrip": + MessageLookupByLibrary.simpleMessage("Viaggio dello scorso anno"), "leave": MessageLookupByLibrary.simpleMessage("Lascia"), "leaveAlbum": MessageLookupByLibrary.simpleMessage("Abbandona l\'album"), @@ -1059,22 +1222,24 @@ class MessageLookup extends MessageLookupByLibrary { "legacy": MessageLookupByLibrary.simpleMessage("Legacy"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("Account Legacy"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage( "Legacy consente ai contatti fidati di accedere al tuo account in tua assenza."), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( "I contatti fidati possono avviare il recupero dell\'account e, se non sono bloccati entro 30 giorni, reimpostare la password e accedere al tuo account."), "light": MessageLookupByLibrary.simpleMessage("Chiaro"), "lightTheme": MessageLookupByLibrary.simpleMessage("Chiaro"), + "link": MessageLookupByLibrary.simpleMessage("Link"), "linkCopiedToClipboard": MessageLookupByLibrary.simpleMessage("Link copiato negli appunti"), "linkDeviceLimit": MessageLookupByLibrary.simpleMessage("Limite dei dispositivi"), + "linkEmail": MessageLookupByLibrary.simpleMessage("Link Email"), "linkEmailToContactBannerCaption": MessageLookupByLibrary.simpleMessage( "per una condivisione più veloce"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Attivato"), "linkExpired": MessageLookupByLibrary.simpleMessage("Scaduto"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Scadenza del link"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("Il link è scaduto"), @@ -1082,7 +1247,8 @@ class MessageLookup extends MessageLookupByLibrary { "linkPerson": MessageLookupByLibrary.simpleMessage("Collega persona"), "linkPersonCaption": MessageLookupByLibrary.simpleMessage( "per una migliore esperienza di condivisione"), - "linkPersonToEmail": m47, + "linkPersonToEmail": m48, + "linkPersonToEmailConfirmation": m49, "livePhotos": MessageLookupByLibrary.simpleMessage("Live Photo"), "loadMessage1": MessageLookupByLibrary.simpleMessage( "Puoi condividere il tuo abbonamento con la tua famiglia"), @@ -1144,8 +1310,8 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Premi a lungo su un elemento per visualizzarlo a schermo intero"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), + "lookBackOnYourMemories": + MessageLookupByLibrary.simpleMessage("Rivivi i tuoi ricordi 🌄"), "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video disattivo"), "loopVideoOn": @@ -1175,9 +1341,15 @@ class MessageLookup extends MessageLookupByLibrary { "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), "me": MessageLookupByLibrary.simpleMessage("Io"), + "memories": MessageLookupByLibrary.simpleMessage("Ricordi"), + "memoriesWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Seleziona il tipo di ricordi che desideri vedere nella schermata principale."), + "memoryCount": m50, "merchandise": MessageLookupByLibrary.simpleMessage("Merchandise"), "mergeWithExisting": MessageLookupByLibrary.simpleMessage("Unisci con esistente"), + "mergedPhotos": + MessageLookupByLibrary.simpleMessage("Fotografie unite"), "mlConsent": MessageLookupByLibrary.simpleMessage( "Abilita l\'apprendimento automatico"), "mlConsentConfirmation": MessageLookupByLibrary.simpleMessage( @@ -1199,14 +1371,19 @@ class MessageLookup extends MessageLookupByLibrary { "moments": MessageLookupByLibrary.simpleMessage("Momenti"), "month": MessageLookupByLibrary.simpleMessage("mese"), "monthly": MessageLookupByLibrary.simpleMessage("Mensile"), + "moon": MessageLookupByLibrary.simpleMessage("Al chiaro di luna"), "moreDetails": MessageLookupByLibrary.simpleMessage("Più dettagli"), "mostRecent": MessageLookupByLibrary.simpleMessage("Più recenti"), "mostRelevant": MessageLookupByLibrary.simpleMessage("Più rilevanti"), + "mountains": MessageLookupByLibrary.simpleMessage("Oltre le colline"), + "moveItem": m51, + "moveSelectedPhotosToOneDate": MessageLookupByLibrary.simpleMessage( + "Sposta foto selezionate in una data specifica"), "moveToAlbum": MessageLookupByLibrary.simpleMessage("Sposta nell\'album"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Sposta in album nascosto"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("Spostato nel cestino"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1222,7 +1399,8 @@ class MessageLookup extends MessageLookupByLibrary { "newAlbum": MessageLookupByLibrary.simpleMessage("Nuovo album"), "newLocation": MessageLookupByLibrary.simpleMessage("Nuova posizione"), "newPerson": MessageLookupByLibrary.simpleMessage("Nuova persona"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), + "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" nuova 📸"), + "newRange": MessageLookupByLibrary.simpleMessage("Nuovo intervallo"), "newToEnte": MessageLookupByLibrary.simpleMessage("Prima volta con Ente"), "newest": MessageLookupByLibrary.simpleMessage("Più recenti"), @@ -1237,6 +1415,8 @@ class MessageLookup extends MessageLookupByLibrary { "Non hai file su questo dispositivo che possono essere eliminati"), "noDuplicates": MessageLookupByLibrary.simpleMessage("✨ Nessun doppione"), + "noEnteAccountExclamation": + MessageLookupByLibrary.simpleMessage("Nessun account Ente!"), "noExifData": MessageLookupByLibrary.simpleMessage("Nessun dato EXIF"), "noFacesFound": MessageLookupByLibrary.simpleMessage("Nessun volto trovato"), @@ -1260,10 +1440,12 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Nessun risultato"), "noResultsFound": MessageLookupByLibrary.simpleMessage("Nessun risultato trovato"), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage( "Nessun blocco di sistema trovato"), - "notPersonLabel": m53, + "notPersonLabel": m54, + "notThisPerson": + MessageLookupByLibrary.simpleMessage("Non è questa persona?"), "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( "Ancora nulla di condiviso con te"), "nothingToSeeHere": @@ -1273,10 +1455,14 @@ class MessageLookup extends MessageLookupByLibrary { "onDevice": MessageLookupByLibrary.simpleMessage("Sul dispositivo"), "onEnte": MessageLookupByLibrary.simpleMessage( "Su ente"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), + "onTheRoad": + MessageLookupByLibrary.simpleMessage("Un altro viaggio su strada"), + "onThisDay": MessageLookupByLibrary.simpleMessage("In questo giorno"), + "onThisDayMemories": + MessageLookupByLibrary.simpleMessage("Ricordi di questo giorno"), "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "Ricevi promemoria sui ricordi da questo giorno negli anni precedenti."), + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("Solo loro"), "oops": MessageLookupByLibrary.simpleMessage("Oops"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( @@ -1300,11 +1486,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("O unisci con esistente"), "orPickAnExistingOne": MessageLookupByLibrary.simpleMessage( "Oppure scegline una esistente"), + "orPickFromYourContacts": MessageLookupByLibrary.simpleMessage( + "o scegli tra i tuoi contatti"), "pair": MessageLookupByLibrary.simpleMessage("Abbina"), "pairWithPin": MessageLookupByLibrary.simpleMessage("Associa con PIN"), "pairingComplete": MessageLookupByLibrary.simpleMessage("Associazione completata"), "panorama": MessageLookupByLibrary.simpleMessage("Panorama"), + "partyWithThem": m56, "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage( "La verifica è ancora in corso"), "passkey": MessageLookupByLibrary.simpleMessage("Passkey"), @@ -1315,18 +1504,20 @@ class MessageLookup extends MessageLookupByLibrary { "Password modificata con successo"), "passwordLock": MessageLookupByLibrary.simpleMessage("Blocco con password"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "La sicurezza della password viene calcolata considerando la lunghezza della password, i caratteri usati e se la password appare o meno nelle prime 10.000 password più usate"), "passwordWarning": MessageLookupByLibrary.simpleMessage( "Noi non memorizziamo la tua password, quindi se te la dimentichi, non possiamo decriptare i tuoi dati"), + "pastYearsMemories": + MessageLookupByLibrary.simpleMessage("Ricordi degli ultimi anni"), "paymentDetails": MessageLookupByLibrary.simpleMessage("Dettagli di Pagamento"), "paymentFailed": MessageLookupByLibrary.simpleMessage("Pagamento non riuscito"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Purtroppo il tuo pagamento non è riuscito. Contatta l\'assistenza e ti aiuteremo!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("Elementi in sospeso"), "pendingSync": @@ -1334,30 +1525,44 @@ class MessageLookup extends MessageLookupByLibrary { "people": MessageLookupByLibrary.simpleMessage("Persone"), "peopleUsingYourCode": MessageLookupByLibrary.simpleMessage( "Persone che hanno usato il tuo codice"), + "peopleWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Seleziona le persone che desideri vedere nella schermata principale."), "permDeleteWarning": MessageLookupByLibrary.simpleMessage( "Tutti gli elementi nel cestino verranno eliminati definitivamente\n\nQuesta azione non può essere annullata"), "permanentlyDelete": MessageLookupByLibrary.simpleMessage("Elimina definitivamente"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage( "Eliminare definitivamente dal dispositivo?"), + "personIsAge": m59, "personName": MessageLookupByLibrary.simpleMessage("Nome della persona"), + "personTurningAge": m60, + "pets": MessageLookupByLibrary.simpleMessage("Compagni pelosetti"), "photoDescriptions": MessageLookupByLibrary.simpleMessage("Descrizioni delle foto"), "photoGridSize": MessageLookupByLibrary.simpleMessage("Dimensione griglia foto"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("foto"), + "photocountPhotos": m61, "photos": MessageLookupByLibrary.simpleMessage("Foto"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage( "Le foto aggiunte da te verranno rimosse dall\'album"), + "photosCount": m62, + "photosKeepRelativeTimeDifference": + MessageLookupByLibrary.simpleMessage( + "Le foto mantengono una differenza di tempo relativa"), "pickCenterPoint": MessageLookupByLibrary.simpleMessage( "Selezionare il punto centrale"), "pinAlbum": MessageLookupByLibrary.simpleMessage("Fissa l\'album"), "pinLock": MessageLookupByLibrary.simpleMessage("Blocco con PIN"), "playOnTv": MessageLookupByLibrary.simpleMessage("Riproduci album sulla TV"), - "playStoreFreeTrialValidTill": m62, + "playOriginal": + MessageLookupByLibrary.simpleMessage("Riproduci originale"), + "playStoreFreeTrialValidTill": m63, + "playStream": + MessageLookupByLibrary.simpleMessage("Riproduci lo streaming"), "playstoreSubscription": MessageLookupByLibrary.simpleMessage("Abbonamento su PlayStore"), "pleaseCheckYourInternetConnectionAndTryAgain": @@ -1369,14 +1574,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Riprova. Se il problema persiste, ti invitiamo a contattare l\'assistenza"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage("Concedi i permessi"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage( "Effettua nuovamente l\'accesso"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Si prega di selezionare i link rapidi da rimuovere"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Riprova"), "pleaseVerifyTheCodeYouHaveEntered": MessageLookupByLibrary.simpleMessage( @@ -1386,6 +1591,9 @@ class MessageLookup extends MessageLookupByLibrary { "Attendere, sto eliminando l\'album"), "pleaseWaitForSometimeBeforeRetrying": MessageLookupByLibrary.simpleMessage("Riprova tra qualche minuto"), + "pleaseWaitThisWillTakeAWhile": MessageLookupByLibrary.simpleMessage( + "Attendere, potrebbe volerci un po\' di tempo."), + "posingWithThem": m66, "preparingLogs": MessageLookupByLibrary.simpleMessage("Preparando i log..."), "preserveMore": MessageLookupByLibrary.simpleMessage("Salva più foto"), @@ -1393,6 +1601,7 @@ class MessageLookup extends MessageLookupByLibrary { "Tieni premuto per riprodurre il video"), "pressAndHoldToPlayVideoDetailed": MessageLookupByLibrary.simpleMessage( "Tieni premuto sull\'immagine per riprodurre il video"), + "previous": MessageLookupByLibrary.simpleMessage("Precedente"), "privacy": MessageLookupByLibrary.simpleMessage("Privacy"), "privacyPolicyTitle": MessageLookupByLibrary.simpleMessage("Privacy Policy"), @@ -1401,24 +1610,29 @@ class MessageLookup extends MessageLookupByLibrary { "privateSharing": MessageLookupByLibrary.simpleMessage("Condivisioni private"), "proceed": MessageLookupByLibrary.simpleMessage("Prosegui"), - "processingImport": m66, + "processed": MessageLookupByLibrary.simpleMessage("Processato"), + "processing": MessageLookupByLibrary.simpleMessage("In elaborazione"), + "processingImport": m67, "processingVideos": MessageLookupByLibrary.simpleMessage("Elaborando video"), "publicLinkCreated": MessageLookupByLibrary.simpleMessage("Link pubblico creato"), "publicLinkEnabled": MessageLookupByLibrary.simpleMessage("Link pubblico abilitato"), + "queued": MessageLookupByLibrary.simpleMessage("In coda"), "quickLinks": MessageLookupByLibrary.simpleMessage("Collegamenti rapidi"), "radius": MessageLookupByLibrary.simpleMessage("Raggio"), "raiseTicket": MessageLookupByLibrary.simpleMessage("Invia ticket"), "rateTheApp": MessageLookupByLibrary.simpleMessage("Valuta l\'app"), "rateUs": MessageLookupByLibrary.simpleMessage("Lascia una recensione"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "reassignMe": MessageLookupByLibrary.simpleMessage("Riassegna \"Io\""), - "reassignedToName": m68, + "reassignedToName": m69, "reassigningLoading": MessageLookupByLibrary.simpleMessage("Riassegnando..."), + "receiveRemindersOnBirthdays": MessageLookupByLibrary.simpleMessage( + "Ricevi promemoria quando è il compleanno di qualcuno. Toccare la notifica ti porterà alle foto della persona che compie gli anni."), "recover": MessageLookupByLibrary.simpleMessage("Recupera"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Recupera account"), @@ -1427,7 +1641,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Recupera l\'account"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage("Recupero avviato"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("Chiave di recupero"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( @@ -1442,12 +1656,12 @@ class MessageLookup extends MessageLookupByLibrary { "Chiave di recupero verificata"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "Se hai dimenticato la password, la tua chiave di ripristino è l\'unico modo per recuperare le tue foto. La puoi trovare in Impostazioni > Account.\n\nInserisci la tua chiave di recupero per verificare di averla salvata correttamente."), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage("Recupero riuscito!"), "recoveryWarning": MessageLookupByLibrary.simpleMessage( "Un contatto fidato sta tentando di accedere al tuo account"), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "Il dispositivo attuale non è abbastanza potente per verificare la tua password, ma la possiamo rigenerare in un modo che funzioni su tutti i dispositivi.\n\nEffettua il login utilizzando la tua chiave di recupero e rigenera la tua password (puoi utilizzare nuovamente la stessa se vuoi)."), "recreatePasswordTitle": @@ -1463,7 +1677,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Condividi questo codice con i tuoi amici"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Si iscrivono per un piano a pagamento"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("Invita un Amico"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "I referral code sono attualmente in pausa"), @@ -1492,7 +1706,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Elimina link"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Rimuovi partecipante"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Rimuovi etichetta persona"), "removePublicLink": @@ -1512,7 +1726,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("Rinomina file"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Rinnova abbonamento"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Segnala un bug"), "reportBug": MessageLookupByLibrary.simpleMessage("Segnala un bug"), "resendEmail": MessageLookupByLibrary.simpleMessage("Rinvia email"), @@ -1537,12 +1751,16 @@ class MessageLookup extends MessageLookupByLibrary { "reviewSuggestions": MessageLookupByLibrary.simpleMessage("Esamina i suggerimenti"), "right": MessageLookupByLibrary.simpleMessage("Destra"), + "roadtripWithThem": m76, "rotate": MessageLookupByLibrary.simpleMessage("Ruota"), "rotateLeft": MessageLookupByLibrary.simpleMessage("Ruota a sinistra"), "rotateRight": MessageLookupByLibrary.simpleMessage("Ruota a destra"), "safelyStored": MessageLookupByLibrary.simpleMessage("Salvati in sicurezza"), "save": MessageLookupByLibrary.simpleMessage("Salva"), + "saveChangesBeforeLeavingQuestion": + MessageLookupByLibrary.simpleMessage( + "Salvare le modifiche prima di uscire?"), "saveCollage": MessageLookupByLibrary.simpleMessage("Salva il collage"), "saveCopy": MessageLookupByLibrary.simpleMessage("Salva una copia"), "saveKey": MessageLookupByLibrary.simpleMessage("Salva chiave"), @@ -1589,30 +1807,47 @@ class MessageLookup extends MessageLookupByLibrary { "Invita persone e vedrai qui tutte le foto condivise da loro"), "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage( "Le persone saranno mostrate qui una volta che l\'elaborazione e la sincronizzazione saranno completate"), - "searchResultCount": m76, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("Sicurezza"), + "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage( + "Vedi link album pubblici nell\'app"), "selectALocation": MessageLookupByLibrary.simpleMessage("Seleziona un luogo"), "selectALocationFirst": MessageLookupByLibrary.simpleMessage("Scegli prima una posizione"), "selectAlbum": MessageLookupByLibrary.simpleMessage("Seleziona album"), "selectAll": MessageLookupByLibrary.simpleMessage("Seleziona tutto"), + "selectAllShort": MessageLookupByLibrary.simpleMessage("Tutte"), "selectCoverPhoto": MessageLookupByLibrary.simpleMessage("Seleziona foto di copertina"), + "selectDate": MessageLookupByLibrary.simpleMessage("Imposta data"), "selectFoldersForBackup": MessageLookupByLibrary.simpleMessage( "Seleziona cartelle per il backup"), "selectItemsToAdd": MessageLookupByLibrary.simpleMessage( "Seleziona gli elementi da aggiungere"), "selectLanguage": MessageLookupByLibrary.simpleMessage("Seleziona una lingua"), + "selectMailApp": + MessageLookupByLibrary.simpleMessage("Seleziona app email"), "selectMorePhotos": MessageLookupByLibrary.simpleMessage("Seleziona più foto"), + "selectOneDateAndTime": + MessageLookupByLibrary.simpleMessage("Seleziona data e orario"), + "selectOneDateAndTimeForAll": MessageLookupByLibrary.simpleMessage( + "Seleziona una data e un\'ora per tutti"), "selectPersonToLink": MessageLookupByLibrary.simpleMessage( "Seleziona persona da collegare"), "selectReason": MessageLookupByLibrary.simpleMessage("Seleziona un motivo"), + "selectStartOfRange": MessageLookupByLibrary.simpleMessage( + "Seleziona inizio dell\'intervallo"), + "selectTime": MessageLookupByLibrary.simpleMessage("Imposta ora"), + "selectYourFace": + MessageLookupByLibrary.simpleMessage("Seleziona il tuo volto"), "selectYourPlan": MessageLookupByLibrary.simpleMessage("Seleziona un piano"), + "selectedAlbums": m79, "selectedFilesAreNotOnEnte": MessageLookupByLibrary.simpleMessage( "I file selezionati non sono su Ente"), "selectedFoldersWillBeEncryptedAndBackedUp": @@ -1621,8 +1856,12 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage( "Gli elementi selezionati verranno eliminati da tutti gli album e spostati nel cestino."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, + "selectedItemsWillBeRemovedFromThisPerson": + MessageLookupByLibrary.simpleMessage( + "Gli elementi selezionati verranno rimossi da questa persona, ma non eliminati dalla tua libreria."), + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, + "selfiesWithThem": m82, "send": MessageLookupByLibrary.simpleMessage("Invia"), "sendEmail": MessageLookupByLibrary.simpleMessage("Invia email"), "sendInvite": MessageLookupByLibrary.simpleMessage("Invita"), @@ -1654,16 +1893,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Condividi un album"), "shareLink": MessageLookupByLibrary.simpleMessage("Condividi link"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Condividi solo con le persone che vuoi"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Scarica Ente in modo da poter facilmente condividere foto e video in qualità originale\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Condividi con utenti che non hanno un account Ente"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage( "Condividi il tuo primo album"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1674,13 +1913,15 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Nuove foto condivise"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "Ricevi notifiche quando qualcuno aggiunge una foto a un album condiviso, di cui fai parte"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Condivisi con me"), "sharedWithYou": MessageLookupByLibrary.simpleMessage("Condivise con te"), "sharing": MessageLookupByLibrary.simpleMessage("Condivisione in corso..."), + "shiftDatesAndTime": + MessageLookupByLibrary.simpleMessage("Sposta date e orari"), "showMemories": MessageLookupByLibrary.simpleMessage("Mostra ricordi"), "showPerson": MessageLookupByLibrary.simpleMessage("Mostra persona"), "signOutFromOtherDevices": MessageLookupByLibrary.simpleMessage( @@ -1691,12 +1932,14 @@ class MessageLookup extends MessageLookupByLibrary { "Esci dagli altri dispositivi"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Accetto i termini di servizio e la politica sulla privacy"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "Verrà eliminato da tutti gli album."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("Salta"), + "smartMemories": + MessageLookupByLibrary.simpleMessage("Ricordi intelligenti"), "social": MessageLookupByLibrary.simpleMessage("Social"), "someItemsAreInBothEnteAndYourDevice": MessageLookupByLibrary.simpleMessage( @@ -1713,6 +1956,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Qualcosa è andato storto, per favore riprova"), "sorry": MessageLookupByLibrary.simpleMessage("Siamo spiacenti"), + "sorryBackupFailedDesc": MessageLookupByLibrary.simpleMessage( + "Purtroppo non è stato possibile eseguire il backup del file in questo momento, riproveremo più tardi."), "sorryCouldNotAddToFavorites": MessageLookupByLibrary.simpleMessage( "Spiacenti, non è stato possibile aggiungere ai preferiti!"), "sorryCouldNotRemoveFromFavorites": MessageLookupByLibrary.simpleMessage( @@ -1724,7 +1969,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Siamo spiacenti, non possiamo generare le chiavi sicure su questo dispositivo.\n\nPer favore, accedi da un altro dispositivo."), "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), + "Spiacenti, abbiamo dovuto mettere in pausa i backup"), "sort": MessageLookupByLibrary.simpleMessage("Ordina"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Ordina per"), "sortNewestFirst": @@ -1733,6 +1978,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Prima le più vecchie"), "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ Operazione riuscita"), + "sportsWithThem": m91, + "spotlightOnThem": m92, + "spotlightOnYourself": + MessageLookupByLibrary.simpleMessage("Tu in primo piano"), "startAccountRecoveryTitle": MessageLookupByLibrary.simpleMessage("Avvia il recupero"), "startBackup": MessageLookupByLibrary.simpleMessage("Avvia backup"), @@ -1746,13 +1995,15 @@ class MessageLookup extends MessageLookupByLibrary { "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Famiglia"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Tu"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage( "Limite d\'archiviazione superato"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, + "streamDetails": + MessageLookupByLibrary.simpleMessage("Dettagli dello streaming"), "strongStrength": MessageLookupByLibrary.simpleMessage("Forte"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("Iscriviti"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "È necessario un abbonamento a pagamento attivo per abilitare la condivisione."), @@ -1768,8 +2019,9 @@ class MessageLookup extends MessageLookupByLibrary { "Rimossa dal nascondiglio con successo"), "suggestFeatures": MessageLookupByLibrary.simpleMessage("Suggerisci una funzionalità"), + "sunrise": MessageLookupByLibrary.simpleMessage("All\'orizzonte"), "support": MessageLookupByLibrary.simpleMessage("Assistenza"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("Sincronizzazione interrotta"), "syncing": MessageLookupByLibrary.simpleMessage( @@ -1782,7 +2034,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Tocca per sbloccare"), "tapToUpload": MessageLookupByLibrary.simpleMessage("Premi per caricare"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Sembra che qualcosa sia andato storto. Riprova tra un po\'. Se l\'errore persiste, contatta il nostro team di supporto."), "terminate": MessageLookupByLibrary.simpleMessage("Terminata"), @@ -1796,6 +2048,9 @@ class MessageLookup extends MessageLookupByLibrary { "Grazie per esserti iscritto!"), "theDownloadCouldNotBeCompleted": MessageLookupByLibrary.simpleMessage( "Il download non può essere completato"), + "theLinkYouAreTryingToAccessHasExpired": + MessageLookupByLibrary.simpleMessage( + "Il link a cui stai cercando di accedere è scaduto."), "theRecoveryKeyYouEnteredIsIncorrect": MessageLookupByLibrary.simpleMessage( "La chiave di recupero inserita non è corretta"), @@ -1803,7 +2058,7 @@ class MessageLookup extends MessageLookupByLibrary { "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage( "Questi file verranno eliminati dal tuo dispositivo."), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage( "Verranno eliminati da tutti gli album."), "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( @@ -1822,17 +2077,24 @@ class MessageLookup extends MessageLookupByLibrary { "Questa immagine non ha dati EXIF"), "thisIsMeExclamation": MessageLookupByLibrary.simpleMessage("Questo sono io!"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( "Questo è il tuo ID di verifica"), + "thisWeekThroughTheYears": + MessageLookupByLibrary.simpleMessage("Questa settimana negli anni"), + "thisWeekXYearsAgo": m101, "thisWillLogYouOutOfTheFollowingDevice": MessageLookupByLibrary.simpleMessage( "Verrai disconnesso dai seguenti dispositivi:"), "thisWillLogYouOutOfThisDevice": MessageLookupByLibrary.simpleMessage( "Verrai disconnesso dal tuo dispositivo!"), + "thisWillMakeTheDateAndTimeOfAllSelected": + MessageLookupByLibrary.simpleMessage( + "In questo modo la data e l\'ora di tutte le foto selezionate saranno uguali."), "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( "Questo rimuoverà i link pubblici di tutti i link rapidi selezionati."), + "throughTheYears": m102, "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": MessageLookupByLibrary.simpleMessage( "Per abilitare il blocco dell\'app, configura il codice di accesso del dispositivo o il blocco schermo nelle impostazioni di sistema."), @@ -1846,11 +2108,13 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("totale"), "totalSize": MessageLookupByLibrary.simpleMessage("Dimensioni totali"), "trash": MessageLookupByLibrary.simpleMessage("Cestino"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("Taglia"), + "tripInYear": m104, + "tripToLocation": m105, "trustedContacts": MessageLookupByLibrary.simpleMessage("Contatti fidati"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("Riprova"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "Attiva il backup per caricare automaticamente i file aggiunti a questa cartella del dispositivo su Ente."), @@ -1869,6 +2133,7 @@ class MessageLookup extends MessageLookupByLibrary { "Autenticazione a due fattori resettata con successo"), "twofactorSetup": MessageLookupByLibrary.simpleMessage( "Configura autenticazione a due fattori"), + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("Rimuovi dall\'archivio"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage( @@ -1896,10 +2161,10 @@ class MessageLookup extends MessageLookupByLibrary { "Aggiornamento della selezione delle cartelle..."), "upgrade": MessageLookupByLibrary.simpleMessage("Acquista altro spazio"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Caricamento dei file nell\'album..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage("Conservando 1 ricordo..."), "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( @@ -1918,7 +2183,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("Usa la foto selezionata"), "usedSpace": MessageLookupByLibrary.simpleMessage("Spazio utilizzato"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Verifica fallita, per favore prova di nuovo"), @@ -1926,7 +2191,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("ID di verifica"), "verify": MessageLookupByLibrary.simpleMessage("Verifica"), "verifyEmail": MessageLookupByLibrary.simpleMessage("Verifica email"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Verifica"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("Verifica passkey"), @@ -1938,6 +2203,8 @@ class MessageLookup extends MessageLookupByLibrary { "Verifica della chiave di recupero..."), "videoInfo": MessageLookupByLibrary.simpleMessage("Informazioni video"), "videoSmallCase": MessageLookupByLibrary.simpleMessage("video"), + "videoStreaming": + MessageLookupByLibrary.simpleMessage("Video in streaming"), "videos": MessageLookupByLibrary.simpleMessage("Video"), "viewActiveSessions": MessageLookupByLibrary.simpleMessage("Visualizza sessioni attive"), @@ -1951,9 +2218,11 @@ class MessageLookup extends MessageLookupByLibrary { "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( "Visualizza i file che stanno occupando la maggior parte dello spazio di archiviazione."), "viewLogs": MessageLookupByLibrary.simpleMessage("Visualizza i log"), + "viewPersonToUnlink": m112, "viewRecoveryKey": MessageLookupByLibrary.simpleMessage( "Visualizza chiave di recupero"), "viewer": MessageLookupByLibrary.simpleMessage("Sola lettura"), + "viewersSuccessfullyAdded": m113, "visitWebToManage": MessageLookupByLibrary.simpleMessage( "Visita web.ente.io per gestire il tuo abbonamento"), "waitingForVerification": @@ -1966,15 +2235,17 @@ class MessageLookup extends MessageLookupByLibrary { "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "Non puoi modificare foto e album che non possiedi"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Debole"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Bentornato/a!"), "whatsNew": MessageLookupByLibrary.simpleMessage("Novità"), "whyAddTrustContact": MessageLookupByLibrary.simpleMessage( "Un contatto fidato può aiutare a recuperare i tuoi dati."), + "widgets": MessageLookupByLibrary.simpleMessage("Widget"), + "wishThemAHappyBirthday": m115, "yearShort": MessageLookupByLibrary.simpleMessage("anno"), "yearly": MessageLookupByLibrary.simpleMessage("Annuale"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Si"), "yesCancel": MessageLookupByLibrary.simpleMessage("Sì, cancella"), "yesConvertToViewer": MessageLookupByLibrary.simpleMessage( @@ -1988,6 +2259,7 @@ class MessageLookup extends MessageLookupByLibrary { "yesResetPerson": MessageLookupByLibrary.simpleMessage("Sì, resetta persona"), "you": MessageLookupByLibrary.simpleMessage("Tu"), + "youAndThem": m117, "youAreOnAFamilyPlan": MessageLookupByLibrary.simpleMessage( "Sei un utente con piano famiglia!"), "youAreOnTheLatestVersion": MessageLookupByLibrary.simpleMessage( @@ -2006,7 +2278,7 @@ class MessageLookup extends MessageLookupByLibrary { "Non puoi condividere con te stesso"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( "Non hai nulla di archiviato."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage( "Il tuo account è stato eliminato"), "yourMap": MessageLookupByLibrary.simpleMessage("La tua mappa"), @@ -2027,6 +2299,9 @@ class MessageLookup extends MessageLookupByLibrary { "Il tuo abbonamento è stato modificato correttamente"), "yourVerificationCodeHasExpired": MessageLookupByLibrary.simpleMessage( "Il tuo codice di verifica è scaduto"), + "youveNoDuplicateFilesThatCanBeCleared": + MessageLookupByLibrary.simpleMessage( + "Non ci sono file duplicati che possono essere eliminati"), "youveNoFilesInThisAlbumThatCanBeDeleted": MessageLookupByLibrary.simpleMessage( "Non hai file in questo album che possono essere eliminati"), diff --git a/mobile/lib/generated/intl/messages_ja.dart b/mobile/lib/generated/intl/messages_ja.dart index 89896ac4f1..01062ecd62 100644 --- a/mobile/lib/generated/intl/messages_ja.dart +++ b/mobile/lib/generated/intl/messages_ja.dart @@ -73,205 +73,205 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: '${count} 個の項目を削除', other: '${count} 個の項目を削除')}"; - static String m22(currentlyDeleting, totalCount) => + static String m23(currentlyDeleting, totalCount) => "${currentlyDeleting} / ${totalCount} を削除中"; - static String m23(albumName) => "\"${albumName}\" にアクセスするための公開リンクが削除されます。"; + static String m24(albumName) => "\"${albumName}\" にアクセスするための公開リンクが削除されます。"; - static String m24(supportEmail) => + static String m25(supportEmail) => "あなたの登録したメールアドレスから${supportEmail} にメールを送ってください"; - static String m25(count, storageSaved) => - "お掃除しました ${Intl.plural(count, one: '${count} 個の重複ファイル', other: '${count} 個の重複ファイル')}, (${storageSaved}が開放されます!)"; + static String m26(count, storageSaved) => + "お掃除しました ${Intl.plural(count, other: '${count} 個の重複ファイル')}, (${storageSaved}が開放されます!)"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} 個のファイル、それぞれ${formattedSize}"; - static String m28(newEmail) => "メールアドレスが ${newEmail} に変更されました"; + static String m29(newEmail) => "メールアドレスが ${newEmail} に変更されました"; - static String m29(email) => "${email} は Ente アカウントを持っていません。"; + static String m30(email) => "${email} は Ente アカウントを持っていません。"; - static String m30(email) => + static String m31(email) => "${email} はEnteアカウントを持っていません。\n\n写真を共有するために「招待」を送信してください。"; - static String m31(name) => "${name}抱きしめて!"; + static String m32(name) => "${name}抱きしめて!"; - static String m32(text) => "${text} の写真が見つかりました"; + static String m33(text) => "${text} の写真が見つかりました"; - static String m33(name) => "${name}とご飯!"; - - static String m34(count, formattedNumber) => - "${Intl.plural(count, other: '${formattedNumber} 個のファイル')} が安全にバックアップされました"; + static String m34(name) => "${name}とご飯!"; static String m35(count, formattedNumber) => + "${Intl.plural(count, other: '${formattedNumber} 個のファイル')} が安全にバックアップされました"; + + static String m36(count, formattedNumber) => "${Intl.plural(count, other: '${formattedNumber} ファイル')} が安全にバックアップされました"; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "誰かが有料プランにサインアップしてコードを適用する度に ${storageAmountInGB} GB"; - static String m37(endDate) => "無料トライアルは${endDate} までです"; + static String m38(endDate) => "無料トライアルは${endDate} までです"; - static String m39(sizeInMBorGB) => "${sizeInMBorGB} を解放する"; + static String m40(sizeInMBorGB) => "${sizeInMBorGB} を解放する"; - static String m41(currentlyProcessing, totalCount) => + static String m42(currentlyProcessing, totalCount) => "${currentlyProcessing} / ${totalCount} を処理中"; - static String m42(name) => "${name}とハイキング!"; + static String m43(name) => "${name}とハイキング!"; - static String m43(count) => "${Intl.plural(count, other: '${count}個のアイテム')}"; + static String m44(count) => "${Intl.plural(count, other: '${count}個のアイテム')}"; - static String m44(name) => "前回の${name}との時間"; + static String m45(name) => "前回の${name}との時間"; - static String m45(email) => "${email} があなたを信頼する連絡先として招待しました"; + static String m46(email) => "${email} があなたを信頼する連絡先として招待しました"; - static String m46(expiryTime) => "リンクは ${expiryTime} に期限切れになります"; + static String m47(expiryTime) => "リンクは ${expiryTime} に期限切れになります"; - static String m47(email) => "この人物を ${email}に紐づけ"; + static String m48(email) => "この人物を ${email}に紐づけ"; - static String m48(personName, email) => "${personName} を ${email} に紐づけします"; + static String m49(personName, email) => "${personName} を ${email} に紐づけします"; - static String m51(albumName) => "${albumName} に移動しました"; + static String m52(albumName) => "${albumName} に移動しました"; - static String m52(personName) => "${personName} の候補はありません"; + static String m53(personName) => "${personName} の候補はありません"; - static String m53(name) => "${name} ではありませんか?"; + static String m54(name) => "${name} ではありませんか?"; - static String m54(familyAdminEmail) => + static String m55(familyAdminEmail) => "コードを変更するには、 ${familyAdminEmail} までご連絡ください。"; - static String m55(name) => "${name}とパーティー!"; + static String m56(name) => "${name}とパーティー!"; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "パスワードの長さ: ${passwordStrengthValue}"; - static String m57(providerName) => "請求された場合は、 ${providerName} のサポートに連絡してください"; + static String m58(providerName) => "請求された場合は、 ${providerName} のサポートに連絡してください"; - static String m58(name, age) => "${name}が${age}才!"; + static String m59(name, age) => "${name}が${age}才!"; - static String m59(name, age) => "${name}が${age}才になった!"; + static String m60(name, age) => "${name}が${age}才になった!"; - static String m60(count) => + static String m61(count) => "${Intl.plural(count, zero: '0枚の写真', one: '1枚の写真', other: '${count} 枚の写真')}"; - static String m62(endDate) => + static String m63(endDate) => "${endDate} まで無料トライアルが有効です。\nその後、有料プランを選択することができます。"; - static String m63(toEmail) => "${toEmail} にメールでご連絡ください"; + static String m64(toEmail) => "${toEmail} にメールでご連絡ください"; - static String m64(toEmail) => "ログを以下のアドレスに送信してください \n${toEmail}"; + static String m65(toEmail) => "ログを以下のアドレスに送信してください \n${toEmail}"; - static String m65(name) => "${name}と一緒にポーズ!"; + static String m66(name) => "${name}と一緒にポーズ!"; - static String m66(folderName) => "${folderName} を処理中..."; + static String m67(folderName) => "${folderName} を処理中..."; - static String m67(storeName) => "${storeName} で評価"; + static String m68(storeName) => "${storeName} で評価"; - static String m68(name) => "あなたを ${name} に紐づけました"; + static String m69(name) => "あなたを ${name} に紐づけました"; - static String m69(days, email) => + static String m70(days, email) => "${days} 日後にアカウントにアクセスできます。通知は ${email}に送信されます。"; - static String m70(email) => "${email}のアカウントを復元できるようになりました。新しいパスワードを設定してください。"; + static String m71(email) => "${email}のアカウントを復元できるようになりました。新しいパスワードを設定してください。"; - static String m71(email) => "${email} はあなたのアカウントを復元しようとしています。"; + static String m72(email) => "${email} はあなたのアカウントを復元しようとしています。"; - static String m72(storageInGB) => "3. お二人とも ${storageInGB} GB*を無料で手に入ります。"; + static String m73(storageInGB) => "3. お二人とも ${storageInGB} GB*を無料で手に入ります。"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} はこの共有アルバムから退出します\n\n${userEmail} が追加した写真もアルバムから削除されます"; - static String m74(endDate) => "サブスクリプションは ${endDate} に更新します"; + static String m75(endDate) => "サブスクリプションは ${endDate} に更新します"; - static String m75(name) => "${name}と車で旅行!"; + static String m76(name) => "${name}と車で旅行!"; - static String m76(count) => - "${Intl.plural(count, one: '${count} 個の結果', other: '${count} 個の結果')}"; + static String m77(count) => "${Intl.plural(count, other: '${count} 個の結果')}"; - static String m77(snapshotLength, searchLength) => + static String m78(snapshotLength, searchLength) => "セクションの長さの不一致: ${snapshotLength} != ${searchLength}"; - static String m78(count) => "${count} 個を選択"; + static String m80(count) => "${count} 個を選択"; - static String m79(count, yourCount) => "${count} 個選択中(${yourCount} あなた)"; + static String m81(count, yourCount) => "${count} 個選択中(${yourCount} あなた)"; - static String m80(name) => "${name}とセルフィー!"; + static String m82(name) => "${name}とセルフィー!"; - static String m81(verificationID) => "私の確認ID: ente.ioの ${verificationID}"; + static String m83(verificationID) => "私の確認ID: ente.ioの ${verificationID}"; - static String m82(verificationID) => + static String m84(verificationID) => "これがあなたのente.io確認用IDであることを確認できますか? ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "リフェラルコード: ${referralCode}\n\n設定→一般→リフェラルで使うことで${referralStorageInGB}が無料になります(あなたが有料プランに加入したあと)。\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: '誰かと共有しましょう', one: '1人と共有されています', other: '${numberOfPeople} 人と共有されています')}"; - static String m85(emailIDs) => "${emailIDs} と共有中"; - - static String m86(fileType) => "${fileType} はEnteから削除されます。"; - - static String m87(fileType) => "この ${fileType} はEnteとお使いのデバイスの両方にあります。"; + static String m87(emailIDs) => "${emailIDs} と共有中"; static String m88(fileType) => "${fileType} はEnteから削除されます。"; - static String m89(name) => "${name}とスポーツ!"; + static String m89(fileType) => "この ${fileType} はEnteとお使いのデバイスの両方にあります。"; - static String m90(name) => "${name}にスポットライト!"; + static String m90(fileType) => "${fileType} はEnteから削除されます。"; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m91(name) => "${name}とスポーツ!"; - static String m92( + static String m92(name) => "${name}にスポットライト!"; + + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; + + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} / ${totalAmount} ${totalStorageUnit} 使用"; - static String m93(id) => + static String m95(id) => "あなたの ${id} はすでに別のEnteアカウントにリンクされています。\nこのアカウントであなたの ${id} を使用したい場合は、サポートにお問い合わせください。"; - static String m94(endDate) => "サブスクリプションは ${endDate} でキャンセルされます"; + static String m96(endDate) => "サブスクリプションは ${endDate} でキャンセルされます"; - static String m95(completed, total) => "${completed}/${total} のメモリが保存されました"; + static String m97(completed, total) => "${completed}/${total} のメモリが保存されました"; - static String m96(ignoreReason) => + static String m98(ignoreReason) => "アップロードするにはタップしてください。 以下の理由のためアップロードは現在無視されています: ${ignoreReason}"; - static String m97(storageAmountInGB) => "紹介者も ${storageAmountInGB} GB を得ます"; + static String m99(storageAmountInGB) => "紹介者も ${storageAmountInGB} GB を得ます"; - static String m98(email) => "これは ${email} の確認用ID"; - - static String m99(count) => - "${Intl.plural(count, one: '${count} 1年前の今週', other: '${count}年前の今週')}"; - - static String m100(dateFormat) => "${dateFormat} から年"; + static String m100(email) => "これは ${email} の確認用ID"; static String m101(count) => + "${Intl.plural(count, one: '${count} 1年前の今週', other: '${count}年前の今週')}"; + + static String m102(dateFormat) => "${dateFormat} から年"; + + static String m103(count) => "${Intl.plural(count, zero: '', one: '1日', other: '${count} 日')}"; - static String m102(year) => "${year}年の旅行"; + static String m104(year) => "${year}年の旅行"; - static String m103(location) => "${location}への旅行"; + static String m105(location) => "${location}への旅行"; - static String m104(email) => "あなたは ${email}から信頼する連絡先になってもらうよう、お願いされています。"; + static String m106(email) => "あなたは ${email}から信頼する連絡先になってもらうよう、お願いされています。"; - static String m105(galleryType) => + static String m107(galleryType) => "このギャラリーのタイプ ${galleryType} は名前の変更には対応していません"; - static String m106(ignoreReason) => "以下の理由によりアップロードは無視されます: ${ignoreReason}"; + static String m108(ignoreReason) => "以下の理由によりアップロードは無視されます: ${ignoreReason}"; - static String m107(count) => "${count} メモリを保存しています..."; + static String m109(count) => "${count} メモリを保存しています..."; - static String m108(endDate) => "${endDate} まで"; + static String m110(endDate) => "${endDate} まで"; - static String m109(email) => "${email} を確認"; + static String m111(email) => "${email} を確認"; - static String m112(email) => "${email}にメールを送りました"; + static String m114(email) => "${email}にメールを送りました"; - static String m113(count) => - "${Intl.plural(count, one: '${count} 年前', other: '${count} 年前')}"; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; - static String m114(name) => "あなたと${name}"; + static String m116(count) => "${Intl.plural(count, other: '${count} 年前')}"; - static String m115(storageSaved) => "${storageSaved} を解放しました"; + static String m117(name) => "あなたと${name}"; + + static String m118(storageSaved) => "${storageSaved} を解放しました"; final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { @@ -461,6 +461,24 @@ class MessageLookup extends MessageLookupByLibrary { "birthday": MessageLookupByLibrary.simpleMessage("誕生日"), "blackFridaySale": MessageLookupByLibrary.simpleMessage("ブラックフライデーセール"), "blog": MessageLookupByLibrary.simpleMessage("ブログ"), + "cLDesc1": MessageLookupByLibrary.simpleMessage( + "動画ストリーミングベータ版と再開可能なアップロード・ダウンロードの作業により、ファイルアップロード制限を10GBに増加しました。これはデスクトップとモバイルアプリの両方で利用可能です。"), + "cLDesc2": MessageLookupByLibrary.simpleMessage( + "バックグラウンドアップロードがAndroidデバイスに加えてiOSでもサポートされるようになりました。最新の写真や動画をバックアップするためにアプリを開く必要がありません。"), + "cLDesc3": MessageLookupByLibrary.simpleMessage( + "自動再生、次のメモリーへのスワイプなど、メモリー体験に大幅な改善を加えました。"), + "cLDesc4": MessageLookupByLibrary.simpleMessage( + "多くの内部改善とともに、検出されたすべての顔を確認し、類似した顔にフィードバックを提供し、1枚の写真から顔を追加/削除することがはるかに簡単になりました。"), + "cLDesc5": MessageLookupByLibrary.simpleMessage( + "Enteに保存したすべての誕生日について、その人のベスト写真のコレクションとともに、オプトアウト通知を受け取るようになります。"), + "cLDesc6": MessageLookupByLibrary.simpleMessage( + "アプリを閉じる前にアップロード/ダウンロードの完了を待つ必要がなくなりました。すべてのアップロードとダウンロードは途中で一時停止し、中断したところから再開できるようになりました。"), + "cLTitle1": MessageLookupByLibrary.simpleMessage("大きな動画ファイルのアップロード"), + "cLTitle2": MessageLookupByLibrary.simpleMessage("バックグラウンドアップロード"), + "cLTitle3": MessageLookupByLibrary.simpleMessage("メモリーの自動再生"), + "cLTitle4": MessageLookupByLibrary.simpleMessage("顔認識の改善"), + "cLTitle5": MessageLookupByLibrary.simpleMessage("誕生日通知"), + "cLTitle6": MessageLookupByLibrary.simpleMessage("再開可能なアップロードとダウンロード"), "cachedData": MessageLookupByLibrary.simpleMessage("キャッシュデータ"), "calculating": MessageLookupByLibrary.simpleMessage("計算中..."), "canNotOpenBody": MessageLookupByLibrary.simpleMessage( @@ -522,8 +540,6 @@ class MessageLookup extends MessageLookupByLibrary { "click": MessageLookupByLibrary.simpleMessage("• クリック"), "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage("• 三点ドットをクリックしてください"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "close": MessageLookupByLibrary.simpleMessage("閉じる"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage("時間ごとにまとめる"), "clubByFileName": MessageLookupByLibrary.simpleMessage("ファイル名ごとにまとめる"), @@ -643,7 +659,7 @@ class MessageLookup extends MessageLookupByLibrary { "deleteItemCount": m21, "deleteLocation": MessageLookupByLibrary.simpleMessage("位置情報を削除"), "deletePhotos": MessageLookupByLibrary.simpleMessage("写真を削除"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage("いちばん必要な機能がない"), "deleteReason2": MessageLookupByLibrary.simpleMessage("アプリや特定の機能が想定通りに動かない"), @@ -675,7 +691,7 @@ class MessageLookup extends MessageLookupByLibrary { "ビューアーはスクリーンショットを撮ったり、外部ツールを使用して写真のコピーを保存したりすることができます"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("ご注意ください"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage("2段階認証を無効にする"), "disablingTwofactorAuthentication": MessageLookupByLibrary.simpleMessage("2要素認証を無効にしています..."), @@ -711,9 +727,9 @@ class MessageLookup extends MessageLookupByLibrary { "download": MessageLookupByLibrary.simpleMessage("ダウンロード"), "downloadFailed": MessageLookupByLibrary.simpleMessage("ダウンロード失敗"), "downloading": MessageLookupByLibrary.simpleMessage("ダウンロード中…"), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("編集"), "editLocation": MessageLookupByLibrary.simpleMessage("位置情報を編集"), "editLocationTagTitle": MessageLookupByLibrary.simpleMessage("位置情報を編集"), @@ -726,15 +742,15 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("Eメール"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage("このメールアドレスはすでに登録されています。"), - "emailChangedTo": m28, - "emailDoesNotHaveEnteAccount": m29, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailDoesNotHaveEnteAccount": m30, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage("このメールアドレスはまだ登録されていません。"), "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("メール確認"), "emailYourLogs": MessageLookupByLibrary.simpleMessage("ログをメールで送信"), - "embracingThem": m31, + "embracingThem": m32, "emergencyContacts": MessageLookupByLibrary.simpleMessage("緊急連絡先"), "empty": MessageLookupByLibrary.simpleMessage("空"), "emptyTrash": MessageLookupByLibrary.simpleMessage("ゴミ箱を空にしますか?"), @@ -801,7 +817,7 @@ class MessageLookup extends MessageLookupByLibrary { "exportYourData": MessageLookupByLibrary.simpleMessage("データをエクスポート"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage("追加の写真が見つかりました"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage("顔がまだ集まっていません。後で戻ってきてください"), "faceRecognition": MessageLookupByLibrary.simpleMessage("顔認識"), @@ -834,7 +850,7 @@ class MessageLookup extends MessageLookupByLibrary { "faq": MessageLookupByLibrary.simpleMessage("よくある質問"), "faqs": MessageLookupByLibrary.simpleMessage("よくある質問"), "favorite": MessageLookupByLibrary.simpleMessage("お気に入り"), - "feastingWithThem": m33, + "feastingWithThem": m34, "feedback": MessageLookupByLibrary.simpleMessage("フィードバック"), "file": MessageLookupByLibrary.simpleMessage("ファイル"), "fileFailedToSaveToGallery": @@ -846,8 +862,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("ファイルをギャラリーに保存しました"), "fileTypes": MessageLookupByLibrary.simpleMessage("ファイルの種類"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("ファイルの種類と名前"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("削除されたファイル"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage("写真をダウンロードしました"), @@ -859,12 +875,12 @@ class MessageLookup extends MessageLookupByLibrary { "forgotPassword": MessageLookupByLibrary.simpleMessage("パスワードを忘れた"), "foundFaces": MessageLookupByLibrary.simpleMessage("見つかった顔"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("空き容量を受け取る"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("無料のストレージが利用可能です"), "freeTrial": MessageLookupByLibrary.simpleMessage("無料トライアル"), - "freeTrialValidTill": m37, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("デバイスの空き領域を解放する"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( @@ -876,7 +892,7 @@ class MessageLookup extends MessageLookupByLibrary { "general": MessageLookupByLibrary.simpleMessage("設定"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage("暗号化鍵を生成しています"), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("設定に移動"), "googlePlayId": MessageLookupByLibrary.simpleMessage("Google Play ID"), "grantFullAccessPrompt": MessageLookupByLibrary.simpleMessage( @@ -903,7 +919,7 @@ class MessageLookup extends MessageLookupByLibrary { "hideSharedItemsFromHomeGallery": MessageLookupByLibrary.simpleMessage("ホームギャラリーから共有された写真等を非表示"), "hiding": MessageLookupByLibrary.simpleMessage("非表示にしています"), - "hikingWithThem": m42, + "hikingWithThem": m43, "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("OSM Franceでホスト"), "howItWorks": MessageLookupByLibrary.simpleMessage("仕組みを知る"), @@ -954,7 +970,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "問題が発生したようです。しばらくしてから再試行してください。エラーが解決しない場合は、サポートチームにお問い合わせください。"), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage("完全に削除されるまでの日数が項目に表示されます"), "itemsWillBeRemovedFromAlbum": @@ -973,7 +989,7 @@ class MessageLookup extends MessageLookupByLibrary { "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage("よければ、情報をお寄せください"), "language": MessageLookupByLibrary.simpleMessage("言語"), - "lastTimeWithThem": m44, + "lastTimeWithThem": m45, "lastUpdated": MessageLookupByLibrary.simpleMessage("更新された順"), "lastYearsTrip": MessageLookupByLibrary.simpleMessage("昨年の旅行"), "leave": MessageLookupByLibrary.simpleMessage("離脱"), @@ -984,7 +1000,7 @@ class MessageLookup extends MessageLookupByLibrary { "left": MessageLookupByLibrary.simpleMessage("左"), "legacy": MessageLookupByLibrary.simpleMessage("レガシー"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("レガシーアカウント"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage( "レガシーでは、信頼できる連絡先が不在時(あなたが亡くなった時など)にアカウントにアクセスできます。"), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( @@ -1000,15 +1016,15 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("共有を高速化するために"), "linkEnabled": MessageLookupByLibrary.simpleMessage("有効"), "linkExpired": MessageLookupByLibrary.simpleMessage("期限切れ"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("リンクの期限切れ"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("リンクは期限切れです"), "linkNeverExpires": MessageLookupByLibrary.simpleMessage("なし"), "linkPerson": MessageLookupByLibrary.simpleMessage("人を紐づけ"), "linkPersonCaption": MessageLookupByLibrary.simpleMessage("良い経験を分かち合うために"), - "linkPersonToEmail": m47, - "linkPersonToEmailConfirmation": m48, + "linkPersonToEmail": m48, + "linkPersonToEmailConfirmation": m49, "livePhotos": MessageLookupByLibrary.simpleMessage("ライブフォト"), "loadMessage1": MessageLookupByLibrary.simpleMessage("サブスクリプションを家族と共有できます"), @@ -1062,8 +1078,6 @@ class MessageLookup extends MessageLookupByLibrary { "表示されているEメールアドレスを長押しして、暗号化を確認します。"), "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage("アイテムを長押しして全画面表示する"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "loopVideoOff": MessageLookupByLibrary.simpleMessage("ビデオのループをオフ"), "loopVideoOn": MessageLookupByLibrary.simpleMessage("ビデオのループをオン"), "lostDevice": MessageLookupByLibrary.simpleMessage("デバイスを紛失しましたか?"), @@ -1118,7 +1132,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("選択した写真を1つの日付に移動"), "moveToAlbum": MessageLookupByLibrary.simpleMessage("アルバムに移動"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("隠しアルバムに移動"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("ごみ箱へ移動"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage("アルバムにファイルを移動中"), @@ -1132,7 +1146,6 @@ class MessageLookup extends MessageLookupByLibrary { "newAlbum": MessageLookupByLibrary.simpleMessage("新しいアルバム"), "newLocation": MessageLookupByLibrary.simpleMessage("新しいロケーション"), "newPerson": MessageLookupByLibrary.simpleMessage("新しい人物"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "newRange": MessageLookupByLibrary.simpleMessage("範囲を追加"), "newToEnte": MessageLookupByLibrary.simpleMessage("Enteを初めて使用する"), "newest": MessageLookupByLibrary.simpleMessage("新しい順"), @@ -1166,10 +1179,10 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("該当なし"), "noResultsFound": MessageLookupByLibrary.simpleMessage("一致する結果が見つかりませんでした"), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage("システムロックが見つかりませんでした"), - "notPersonLabel": m53, + "notPersonLabel": m54, "notThisPerson": MessageLookupByLibrary.simpleMessage("この人ではありませんか?"), "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage("あなたに共有されたものはありません"), @@ -1181,10 +1194,7 @@ class MessageLookup extends MessageLookupByLibrary { "onEnte": MessageLookupByLibrary.simpleMessage( "Enteが保管"), "onTheRoad": MessageLookupByLibrary.simpleMessage("再び道で"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("この人のみ"), "oops": MessageLookupByLibrary.simpleMessage("Oops"), "oopsCouldNotSaveEdits": @@ -1212,7 +1222,7 @@ class MessageLookup extends MessageLookupByLibrary { "pairWithPin": MessageLookupByLibrary.simpleMessage("PINを使ってペアリングする"), "pairingComplete": MessageLookupByLibrary.simpleMessage("ペアリング完了"), "panorama": MessageLookupByLibrary.simpleMessage("パノラマ"), - "partyWithThem": m55, + "partyWithThem": m56, "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage("検証はまだ保留中です"), "passkey": MessageLookupByLibrary.simpleMessage("パスキー"), @@ -1221,7 +1231,7 @@ class MessageLookup extends MessageLookupByLibrary { "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage("パスワードの変更に成功しました"), "passwordLock": MessageLookupByLibrary.simpleMessage("パスワード保護"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "パスワードの長さ、使用される文字の種類を考慮してパスワードの強度は計算されます。"), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -1230,7 +1240,7 @@ class MessageLookup extends MessageLookupByLibrary { "paymentFailed": MessageLookupByLibrary.simpleMessage("支払いに失敗しました"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "残念ながらお支払いに失敗しました。サポートにお問い合わせください。お手伝いします!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("処理待ちの項目"), "pendingSync": MessageLookupByLibrary.simpleMessage("同期を保留中"), "people": MessageLookupByLibrary.simpleMessage("人物"), @@ -1241,14 +1251,14 @@ class MessageLookup extends MessageLookupByLibrary { "permanentlyDelete": MessageLookupByLibrary.simpleMessage("完全に削除"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage("デバイスから完全に削除しますか?"), - "personIsAge": m58, + "personIsAge": m59, "personName": MessageLookupByLibrary.simpleMessage("人名名"), - "personTurningAge": m59, + "personTurningAge": m60, "pets": MessageLookupByLibrary.simpleMessage("毛むくじゃらな仲間たち"), "photoDescriptions": MessageLookupByLibrary.simpleMessage("写真の説明"), "photoGridSize": MessageLookupByLibrary.simpleMessage("写真のグリッドサイズ"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("写真"), - "photocountPhotos": m60, + "photocountPhotos": m61, "photos": MessageLookupByLibrary.simpleMessage("写真"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage("あなたの追加した写真はこのアルバムから削除されます"), @@ -1259,7 +1269,7 @@ class MessageLookup extends MessageLookupByLibrary { "pinLock": MessageLookupByLibrary.simpleMessage("PINロック"), "playOnTv": MessageLookupByLibrary.simpleMessage("TVでアルバムを再生"), "playOriginal": MessageLookupByLibrary.simpleMessage("元動画を再生"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playStream": MessageLookupByLibrary.simpleMessage("再生"), "playstoreSubscription": MessageLookupByLibrary.simpleMessage("PlayStoreサブスクリプション"), @@ -1270,13 +1280,13 @@ class MessageLookup extends MessageLookupByLibrary { "Support@ente.ioにお問い合わせください、お手伝いいたします。"), "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage("問題が解決しない場合はサポートにお問い合わせください"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage("権限を付与してください"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("もう一度試してください"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage("削除するクイックリンクを選択してください"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("もう一度試してください"), "pleaseVerifyTheCodeYouHaveEntered": MessageLookupByLibrary.simpleMessage("入力したコードを確認してください"), @@ -1287,7 +1297,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("再試行する前にしばらくお待ちください"), "pleaseWaitThisWillTakeAWhile": MessageLookupByLibrary.simpleMessage("しばらくお待ちください。時間がかかります。"), - "posingWithThem": m65, + "posingWithThem": m66, "preparingLogs": MessageLookupByLibrary.simpleMessage("ログを準備中..."), "preserveMore": MessageLookupByLibrary.simpleMessage("もっと保存する"), "pressAndHoldToPlayVideo": @@ -1303,7 +1313,7 @@ class MessageLookup extends MessageLookupByLibrary { "proceed": MessageLookupByLibrary.simpleMessage("続行"), "processed": MessageLookupByLibrary.simpleMessage("処理完了"), "processing": MessageLookupByLibrary.simpleMessage("処理中"), - "processingImport": m66, + "processingImport": m67, "processingVideos": MessageLookupByLibrary.simpleMessage("動画を処理中"), "publicLinkCreated": MessageLookupByLibrary.simpleMessage("公開リンクが作成されました"), @@ -1315,9 +1325,9 @@ class MessageLookup extends MessageLookupByLibrary { "raiseTicket": MessageLookupByLibrary.simpleMessage("サポートを受ける"), "rateTheApp": MessageLookupByLibrary.simpleMessage("アプリを評価"), "rateUs": MessageLookupByLibrary.simpleMessage("評価して下さい"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "reassignMe": MessageLookupByLibrary.simpleMessage("\"自分\" を再割り当て"), - "reassignedToName": m68, + "reassignedToName": m69, "reassigningLoading": MessageLookupByLibrary.simpleMessage("再割り当て中..."), "recover": MessageLookupByLibrary.simpleMessage("復元"), "recoverAccount": MessageLookupByLibrary.simpleMessage("アカウントを復元"), @@ -1325,7 +1335,7 @@ class MessageLookup extends MessageLookupByLibrary { "recoveryAccount": MessageLookupByLibrary.simpleMessage("アカウントを復元"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage("リカバリが開始されました"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("リカバリーキー"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage("リカバリーキーはクリップボードにコピーされました"), @@ -1339,12 +1349,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("リカバリキーが確認されました"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "パスワードを忘れた場合、リカバリーキーは写真を復元するための唯一の方法になります。なお、設定 > アカウント でリカバリーキーを確認することができます。\n \n\nここにリカバリーキーを入力して、正しく保存できていることを確認してください。"), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage("復元に成功しました!"), "recoveryWarning": MessageLookupByLibrary.simpleMessage( "信頼する連絡先の持ち主があなたのアカウントにアクセスしようとしています"), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "このデバイスではパスワードを確認する能力が足りません。\n\n恐れ入りますが、リカバリーキーを入力してパスワードを再生成する必要があります。"), "recreatePasswordTitle": @@ -1358,7 +1368,7 @@ class MessageLookup extends MessageLookupByLibrary { "referralStep1": MessageLookupByLibrary.simpleMessage("1. このコードを友達に贈りましょう"), "referralStep2": MessageLookupByLibrary.simpleMessage("2. 友達が有料プランに登録"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("リフェラル"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage("リフェラルは現在一時停止しています"), @@ -1383,7 +1393,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeInvite": MessageLookupByLibrary.simpleMessage("招待を削除"), "removeLink": MessageLookupByLibrary.simpleMessage("リンクを削除"), "removeParticipant": MessageLookupByLibrary.simpleMessage("参加者を削除"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage("人名を削除"), "removePublicLink": MessageLookupByLibrary.simpleMessage("公開リンクを削除"), "removePublicLinks": MessageLookupByLibrary.simpleMessage("公開リンクを削除"), @@ -1400,7 +1410,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("ファイル名を変更"), "renewSubscription": MessageLookupByLibrary.simpleMessage("サブスクリプションの更新"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("バグを報告"), "reportBug": MessageLookupByLibrary.simpleMessage("バグを報告"), "resendEmail": MessageLookupByLibrary.simpleMessage("メールを再送信"), @@ -1420,7 +1430,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("重複だと思うファイルを確認して削除してください"), "reviewSuggestions": MessageLookupByLibrary.simpleMessage("提案を確認"), "right": MessageLookupByLibrary.simpleMessage("右"), - "roadtripWithThem": m75, + "roadtripWithThem": m76, "rotate": MessageLookupByLibrary.simpleMessage("回転"), "rotateLeft": MessageLookupByLibrary.simpleMessage("左に回転"), "rotateRight": MessageLookupByLibrary.simpleMessage("右に回転"), @@ -1467,8 +1477,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("友達を招待すると、共有される写真はここから閲覧できます"), "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage("処理と同期が完了すると、ここに人々が表示されます"), - "searchResultCount": m76, - "searchSectionsLengthMismatch": m77, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("セキュリティ"), "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage("アプリ内で公開アルバムのリンクを見る"), @@ -1508,9 +1518,9 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeRemovedFromThisPerson": MessageLookupByLibrary.simpleMessage( "選択したアイテムはこの人としての登録が解除されますが、ライブラリからは削除されません。"), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, - "selfiesWithThem": m80, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, + "selfiesWithThem": m82, "send": MessageLookupByLibrary.simpleMessage("送信"), "sendEmail": MessageLookupByLibrary.simpleMessage("メールを送信する"), "sendInvite": MessageLookupByLibrary.simpleMessage("招待を送る"), @@ -1534,16 +1544,16 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("アルバムを開いて右上のシェアボタンをタップ"), "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("アルバムを共有"), "shareLink": MessageLookupByLibrary.simpleMessage("リンクの共有"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage("選んだ人と共有します"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Enteをダウンロードして、写真や動画の共有を簡単に!\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage("Enteを使っていない人に共有"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage("アルバムの共有をしてみましょう"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1554,7 +1564,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("新しい共有写真"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage("誰かが写真を共有アルバムに追加した時に通知を受け取る"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("あなたと共有されたアルバム"), "sharedWithYou": MessageLookupByLibrary.simpleMessage("あなたと共有されています"), "sharing": MessageLookupByLibrary.simpleMessage("共有中..."), @@ -1569,11 +1579,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("他のデバイスからサインアウトする"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "利用規約プライバシーポリシーに同意します"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage("全てのアルバムから削除されます。"), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("スキップ"), "social": MessageLookupByLibrary.simpleMessage("SNS"), "someItemsAreInBothEnteAndYourDevice": @@ -1599,15 +1609,13 @@ class MessageLookup extends MessageLookupByLibrary { "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "このデバイスでは安全な鍵を生成することができませんでした。\n\n他のデバイスからサインアップを試みてください。"), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "sort": MessageLookupByLibrary.simpleMessage("並び替え"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("並び替え"), "sortNewestFirst": MessageLookupByLibrary.simpleMessage("新しい順"), "sortOldestFirst": MessageLookupByLibrary.simpleMessage("古い順"), "sparkleSuccess": MessageLookupByLibrary.simpleMessage("成功✨"), - "sportsWithThem": m89, - "spotlightOnThem": m90, + "sportsWithThem": m91, + "spotlightOnThem": m92, "spotlightOnYourself": MessageLookupByLibrary.simpleMessage("あなた自身にスポットライト!"), "startAccountRecoveryTitle": @@ -1619,14 +1627,14 @@ class MessageLookup extends MessageLookupByLibrary { "storage": MessageLookupByLibrary.simpleMessage("ストレージ"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("ファミリー"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("あなた"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage("ストレージの上限を超えました"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "streamDetails": MessageLookupByLibrary.simpleMessage("動画の詳細"), "strongStrength": MessageLookupByLibrary.simpleMessage("強いパスワード"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("サブスクライブ"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "共有を有効にするには、有料サブスクリプションが必要です。"), @@ -1641,7 +1649,7 @@ class MessageLookup extends MessageLookupByLibrary { "suggestFeatures": MessageLookupByLibrary.simpleMessage("機能を提案"), "sunrise": MessageLookupByLibrary.simpleMessage("水平線"), "support": MessageLookupByLibrary.simpleMessage("サポート"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("同期が停止しました"), "syncing": MessageLookupByLibrary.simpleMessage("同期中..."), "systemTheme": MessageLookupByLibrary.simpleMessage("システム"), @@ -1649,7 +1657,7 @@ class MessageLookup extends MessageLookupByLibrary { "tapToEnterCode": MessageLookupByLibrary.simpleMessage("タップしてコードを入力"), "tapToUnlock": MessageLookupByLibrary.simpleMessage("タップして解除"), "tapToUpload": MessageLookupByLibrary.simpleMessage("タップしてアップロード"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "問題が発生したようです。しばらくしてから再試行してください。エラーが解決しない場合は、サポートチームにお問い合わせください。"), "terminate": MessageLookupByLibrary.simpleMessage("終了させる"), @@ -1668,7 +1676,7 @@ class MessageLookup extends MessageLookupByLibrary { "theme": MessageLookupByLibrary.simpleMessage("テーマ"), "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage("これらの項目はデバイスから削除されます。"), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage("全てのアルバムから削除されます。"), "thisActionCannotBeUndone": @@ -1685,12 +1693,12 @@ class MessageLookup extends MessageLookupByLibrary { "thisImageHasNoExifData": MessageLookupByLibrary.simpleMessage("この画像にEXIFデータはありません"), "thisIsMeExclamation": MessageLookupByLibrary.simpleMessage("これは私です"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage("これはあなたの認証IDです"), "thisWeekThroughTheYears": MessageLookupByLibrary.simpleMessage("毎年のこの週"), - "thisWeekXYearsAgo": m99, + "thisWeekXYearsAgo": m101, "thisWillLogYouOutOfTheFollowingDevice": MessageLookupByLibrary.simpleMessage("以下のデバイスからログアウトします:"), "thisWillLogYouOutOfThisDevice": @@ -1700,7 +1708,7 @@ class MessageLookup extends MessageLookupByLibrary { "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( "選択したすべてのクイックリンクの公開リンクを削除します。"), - "throughTheYears": m100, + "throughTheYears": m102, "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": MessageLookupByLibrary.simpleMessage( "アプリのロックを有効にするには、システム設定でデバイスのパスコードまたは画面ロックを設定してください。"), @@ -1714,12 +1722,12 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("合計"), "totalSize": MessageLookupByLibrary.simpleMessage("合計サイズ"), "trash": MessageLookupByLibrary.simpleMessage("ゴミ箱"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("トリミング"), - "tripInYear": m102, - "tripToLocation": m103, + "tripInYear": m104, + "tripToLocation": m105, "trustedContacts": MessageLookupByLibrary.simpleMessage("信頼する連絡先"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("もう一度試してください"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "バックアップをオンにすると、このデバイスフォルダに追加されたファイルは自動的にEnteにアップロードされます。"), @@ -1734,7 +1742,7 @@ class MessageLookup extends MessageLookupByLibrary { "twofactorAuthenticationSuccessfullyReset": MessageLookupByLibrary.simpleMessage("2段階認証をリセットしました"), "twofactorSetup": MessageLookupByLibrary.simpleMessage("2段階認証のセットアップ"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("アーカイブ解除"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("アルバムのアーカイブ解除"), "unarchiving": MessageLookupByLibrary.simpleMessage("アーカイブを解除中..."), @@ -1754,10 +1762,10 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage("フォルダの選択を更新しています..."), "upgrade": MessageLookupByLibrary.simpleMessage("アップグレード"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage("アルバムにファイルをアップロード中"), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage("1メモリを保存しています..."), "upto50OffUntil4thDec": @@ -1773,13 +1781,13 @@ class MessageLookup extends MessageLookupByLibrary { "useRecoveryKey": MessageLookupByLibrary.simpleMessage("リカバリーキーを使用"), "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("選択した写真を使用"), "usedSpace": MessageLookupByLibrary.simpleMessage("使用済み領域"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage("確認に失敗しました、再試行してください"), "verificationId": MessageLookupByLibrary.simpleMessage("確認用ID"), "verify": MessageLookupByLibrary.simpleMessage("確認"), "verifyEmail": MessageLookupByLibrary.simpleMessage("Eメールの確認"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("確認"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("パスキーを確認"), "verifyPassword": MessageLookupByLibrary.simpleMessage("パスワードの確認"), @@ -1812,15 +1820,16 @@ class MessageLookup extends MessageLookupByLibrary { "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "あなたが所有していない写真やアルバムの編集はサポートされていません"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("弱いパスワード"), "welcomeBack": MessageLookupByLibrary.simpleMessage("おかえりなさい!"), "whatsNew": MessageLookupByLibrary.simpleMessage("最新情報"), "whyAddTrustContact": MessageLookupByLibrary.simpleMessage("信頼する連絡先は、データの復旧が必要な際に役立ちます。"), + "wishThemAHappyBirthday": m115, "yearShort": MessageLookupByLibrary.simpleMessage("年"), "yearly": MessageLookupByLibrary.simpleMessage("年額"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("はい"), "yesCancel": MessageLookupByLibrary.simpleMessage("キャンセル"), "yesConvertToViewer": @@ -1833,7 +1842,7 @@ class MessageLookup extends MessageLookupByLibrary { "yesRenew": MessageLookupByLibrary.simpleMessage("はい、更新する"), "yesResetPerson": MessageLookupByLibrary.simpleMessage("リセット"), "you": MessageLookupByLibrary.simpleMessage("あなた"), - "youAndThem": m114, + "youAndThem": m117, "youAreOnAFamilyPlan": MessageLookupByLibrary.simpleMessage("ファミリープランに入会しています!"), "youAreOnTheLatestVersion": @@ -1850,7 +1859,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("自分自身と共有することはできません"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage("アーカイブした項目はありません"), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("アカウントは削除されました"), "yourMap": MessageLookupByLibrary.simpleMessage("あなたの地図"), diff --git a/mobile/lib/generated/intl/messages_km.dart b/mobile/lib/generated/intl/messages_km.dart index 7def70d59c..6271e8d455 100644 --- a/mobile/lib/generated/intl/messages_km.dart +++ b/mobile/lib/generated/intl/messages_km.dart @@ -20,17 +20,9 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'km'; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => { - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups") - }; + static Map _notInlinedMessages(_) => + {"wishThemAHappyBirthday": m115}; } diff --git a/mobile/lib/generated/intl/messages_ko.dart b/mobile/lib/generated/intl/messages_ko.dart index 9e92894916..6f8a7f5a0c 100644 --- a/mobile/lib/generated/intl/messages_ko.dart +++ b/mobile/lib/generated/intl/messages_ko.dart @@ -20,6 +20,8 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'ko'; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { "accountWelcomeBack": @@ -27,8 +29,6 @@ class MessageLookup extends MessageLookupByLibrary { "askDeleteReason": MessageLookupByLibrary.simpleMessage("계정을 삭제하는 가장 큰 이유가 무엇인가요?"), "cancel": MessageLookupByLibrary.simpleMessage("닫기"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage("계정 삭제 확인"), "deleteAccount": MessageLookupByLibrary.simpleMessage("계정 삭제"), @@ -42,15 +42,8 @@ class MessageLookup extends MessageLookupByLibrary { "feedback": MessageLookupByLibrary.simpleMessage("피드백"), "invalidEmailAddress": MessageLookupByLibrary.simpleMessage("잘못된 이메일 주소"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "verify": MessageLookupByLibrary.simpleMessage("인증"), + "wishThemAHappyBirthday": m115, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("계정이 삭제되었습니다.") }; diff --git a/mobile/lib/generated/intl/messages_ku.dart b/mobile/lib/generated/intl/messages_ku.dart new file mode 100644 index 0000000000..90ea2aeea1 --- /dev/null +++ b/mobile/lib/generated/intl/messages_ku.dart @@ -0,0 +1,28 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a ku locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'ku'; + + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => + {"wishThemAHappyBirthday": m115}; +} diff --git a/mobile/lib/generated/intl/messages_lt.dart b/mobile/lib/generated/intl/messages_lt.dart index cfb1c23b2d..6f493e38c5 100644 --- a/mobile/lib/generated/intl/messages_lt.dart +++ b/mobile/lib/generated/intl/messages_lt.dart @@ -45,6 +45,9 @@ class MessageLookup extends MessageLookupByLibrary { static String m9(versionValue) => "Versija: ${versionValue}"; + static String m10(freeAmount, storageUnit) => + "${freeAmount} ${storageUnit} laisva"; + static String m11(name) => "Gražūs vaizdai su ${name}"; static String m12(paymentProvider) => @@ -67,7 +70,7 @@ class MessageLookup extends MessageLookupByLibrary { "${Intl.plural(count, zero: 'Pridėta 0 bendradarbių', one: 'Pridėtas 1 bendradarbis', other: 'Pridėta ${count} bendradarbių')}"; static String m17(email, numOfDays) => - "Ketinate pridėti ${email} kaip patikimą kontaktą. Jie galės atkurti jūsų paskyrą, jei jūsų nebus ${numOfDays} dienų."; + "Ketinate įtraukti ${email} kaip patikimą kontaktą. Jie galės atkurti jūsų paskyrą, jei jūsų nebus ${numOfDays} dienų."; static String m18(familyAdminEmail) => "Susisiekite su ${familyAdminEmail}, kad sutvarkytumėte savo prenumeratą."; @@ -80,198 +83,250 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'Ištrinti ${count} elementą', other: 'Ištrinti ${count} elementų')}"; - static String m22(currentlyDeleting, totalCount) => + static String m22(count) => + "Taip pat ištrinti nuotraukas (ir vaizdo įrašus), esančias šiuose ${count} albumuose, iš visų kitų albumų, kuriuose jos yra dalis?"; + + static String m23(currentlyDeleting, totalCount) => "Ištrinama ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "Tai pašalins viešą nuorodą, skirtą pasiekti „${albumName}“."; - static String m24(supportEmail) => + static String m25(supportEmail) => "Iš savo registruoto el. pašto adreso atsiųskite el. laišką adresu ${supportEmail}"; - static String m25(count, storageSaved) => + static String m26(count, storageSaved) => "Išvalėte ${Intl.plural(count, one: '${count} dubliuojantį failą', other: '${count} dubliuojančių failų')}, išsaugodami (${storageSaved})"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} failai (-ų), kiekvienas ${formattedSize}"; - static String m28(newEmail) => "El. paštas pakeistas į ${newEmail}"; + static String m28(name) => "Šis el. paštas jau susietas su ${name}."; - static String m29(email) => "${email} neturi „Ente“ paskyros."; + static String m29(newEmail) => "El. paštas pakeistas į ${newEmail}"; - static String m30(email) => + static String m30(email) => "${email} neturi „Ente“ paskyros."; + + static String m31(email) => "${email} neturi „Ente“ paskyros.\n\nSiųskite jiems kvietimą bendrinti nuotraukas."; - static String m32(text) => "Rastos papildomos nuotraukos, skirtos ${text}"; + static String m32(name) => "Apkabinat ${name}"; + + static String m33(text) => "Rastos papildomos nuotraukos, skirtos ${text}"; + + static String m34(name) => "Vaišiavimas su ${name}"; static String m35(count, formattedNumber) => - "${Intl.plural(count, one: '${formattedNumber} failas šiame albume saugiai sukurta atsarginė kopija', few: '${formattedNumber} failai šiame albume saugiai sukurtos atsarginės kopijos', many: '${formattedNumber} failo šiame albume saugiai sukurtos atsargines kopijos', other: '${formattedNumber} failų šiame albume saugiai sukurta atsarginė kopija')}."; + "${Intl.plural(count, one: '${formattedNumber} failas šiame įrenginyje saugiai sukurta atsarginė kopija', other: '${formattedNumber} failų šiame įrenginyje saugiai sukurta atsarginių kopijų')}."; - static String m36(storageAmountInGB) => + static String m36(count, formattedNumber) => + "${Intl.plural(count, one: '${formattedNumber} failas šiame albume saugiai sukurta atsarginė kopija', other: '${formattedNumber} failų šiame albume saugiai sukurta atsarginė kopija')}."; + + static String m37(storageAmountInGB) => "${storageAmountInGB} GB kiekvieną kartą, kai kas nors užsiregistruoja mokamam planui ir pritaiko jūsų kodą."; - static String m37(endDate) => + static String m38(endDate) => "Nemokamas bandomasis laikotarpis galioja iki ${endDate}"; - static String m38(count) => + static String m39(count) => "Vis dar galite pasiekti ${Intl.plural(count, one: 'jį', other: 'jų')} platformoje „Ente“, kol turite aktyvų prenumeratą."; - static String m39(sizeInMBorGB) => "Atlaisvinti ${sizeInMBorGB}"; + static String m40(sizeInMBorGB) => "Atlaisvinti ${sizeInMBorGB}"; - static String m40(count, formattedSize) => + static String m41(count, formattedSize) => "${Intl.plural(count, one: 'Jį galima ištrinti iš įrenginio, kad atlaisvintų ${formattedSize}', other: 'Jų galima ištrinti iš įrenginio, kad atlaisvintų ${formattedSize}')}"; - static String m41(currentlyProcessing, totalCount) => + static String m42(currentlyProcessing, totalCount) => "Apdorojama ${currentlyProcessing} / ${totalCount}"; - static String m43(count) => + static String m43(name) => "Žygiavimas su ${name}"; + + static String m44(count) => "${Intl.plural(count, one: '${count} elementas', other: '${count} elementų')}"; - static String m45(email) => "${email} pakvietė jus būti patikimu kontaktu"; + static String m45(name) => "Paskutinį kartą su ${name}"; - static String m46(expiryTime) => "Nuoroda nebegalios ${expiryTime}"; + static String m46(email) => "${email} pakvietė jus būti patikimu kontaktu"; - static String m48(personName, email) => + static String m47(expiryTime) => "Nuoroda nebegalios ${expiryTime}"; + + static String m48(email) => "Susieti asmenį su ${email}"; + + static String m49(personName, email) => "Tai susies ${personName} su ${email}."; - static String m49(count, formattedCount) => + static String m50(count, formattedCount) => "${Intl.plural(count, zero: 'nėra prisiminimų', one: '${formattedCount} prisiminimas', other: '${formattedCount} prisiminimų')}"; - static String m50(count) => + static String m51(count) => "${Intl.plural(count, one: 'Perkelti elementą', other: 'Perkelti elementų')}"; - static String m51(albumName) => "Sėkmingai perkelta į „${albumName}“"; + static String m52(albumName) => "Sėkmingai perkelta į „${albumName}“"; - static String m52(personName) => "Nėra pasiūlymų asmeniui ${personName}."; + static String m53(personName) => "Nėra pasiūlymų asmeniui ${personName}."; - static String m53(name) => "Ne ${name}?"; + static String m54(name) => "Ne ${name}?"; - static String m54(familyAdminEmail) => + static String m55(familyAdminEmail) => "Susisiekite su ${familyAdminEmail}, kad pakeistumėte savo kodą."; - static String m56(passwordStrengthValue) => + static String m56(name) => "Vakarėlis su ${name}"; + + static String m57(passwordStrengthValue) => "Slaptažodžio stiprumas: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "Kreipkitės į ${providerName} palaikymo komandą, jei jums buvo nuskaičiuota."; - static String m60(count) => + static String m59(name, age) => "${name} yra ${age} m.!"; + + static String m60(name, age) => "${name} netrukus sulauks ${age} m."; + + static String m61(count) => "${Intl.plural(count, zero: 'Nėra nuotraukų', one: '1 nuotrauka', other: '${count} nuotraukų')}"; - static String m62(endDate) => + static String m62(count) => + "${Intl.plural(count, zero: '0 nuotraukų', one: '1 nuotrauka', other: '${count} nuotraukų')}"; + + static String m63(endDate) => "Nemokama bandomoji versija galioja iki ${endDate}.\nVėliau galėsite pasirinkti mokamą planą."; - static String m64(toEmail) => "Siųskite žurnalus adresu\n${toEmail}"; + static String m64(toEmail) => "Siųskite el. laišką mums adresu ${toEmail}."; - static String m66(folderName) => "Apdorojama ${folderName}..."; + static String m65(toEmail) => "Siųskite žurnalus adresu\n${toEmail}"; - static String m67(storeName) => "Vertinti mus parduotuvėje „${storeName}“"; + static String m66(name) => "Pozavimas su ${name}"; - static String m68(name) => "Perskirstė jus į ${name}"; + static String m67(folderName) => "Apdorojama ${folderName}..."; - static String m69(days, email) => + static String m68(storeName) => "Vertinti mus parduotuvėje „${storeName}“"; + + static String m69(name) => "Perskirstė jus į ${name}"; + + static String m70(days, email) => "Paskyrą galėsite pasiekti po ${days} dienų. Pranešimas bus išsiųstas į ${email}."; - static String m70(email) => + static String m71(email) => "Dabar galite atkurti ${email} paskyrą nustatydami naują slaptažodį."; - static String m71(email) => "${email} bando atkurti jūsų paskyrą."; + static String m72(email) => "${email} bando atkurti jūsų paskyrą."; - static String m72(storageInGB) => + static String m73(storageInGB) => "3. Abu gaunate ${storageInGB} GB* nemokamai"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} bus pašalintas iš šio bendrinamo albumo.\n\nVisos jų pridėtos nuotraukos taip pat bus pašalintos iš albumo."; - static String m74(endDate) => "Prenumerata pratęsiama ${endDate}"; + static String m75(endDate) => "Prenumerata pratęsiama ${endDate}"; - static String m76(count) => + static String m76(name) => "Kelionė su ${name}"; + + static String m77(count) => "${Intl.plural(count, one: 'Rastas ${count} rezultatas', other: 'Rasta ${count} rezultatų')}"; - static String m77(snapshotLength, searchLength) => + static String m78(snapshotLength, searchLength) => "Sekcijų ilgio neatitikimas: ${snapshotLength} != ${searchLength}"; - static String m78(count) => "${count} pasirinkta"; + static String m79(count) => "${count} pasirinkta"; - static String m79(count, yourCount) => + static String m80(count) => "${count} pasirinkta"; + + static String m81(count, yourCount) => "${count} pasirinkta (${yourCount} jūsų)"; - static String m81(verificationID) => + static String m82(name) => "Asmenukės su ${name}"; + + static String m83(verificationID) => "Štai mano patvirtinimo ID: ${verificationID}, skirta ente.io."; - static String m82(verificationID) => + static String m84(verificationID) => "Ei, ar galite patvirtinti, kad tai yra jūsų ente.io patvirtinimo ID: ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "„Ente“ rekomendacijos kodas: ${referralCode} \n\nTaikykite jį per Nustatymai → Bendrieji → Rekomendacijos, kad gautumėte ${referralStorageInGB} GB nemokamai po to, kai užsiregistruosite mokamam planui.\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Bendrinti su konkrečiais asmenimis', one: 'Bendrinta su 1 asmeniu', other: 'Bendrinta su ${numberOfPeople} asmenimis')}"; - static String m85(emailIDs) => "Bendrinta su ${emailIDs}"; + static String m87(emailIDs) => "Bendrinta su ${emailIDs}"; - static String m86(fileType) => + static String m88(fileType) => "Šis ${fileType} bus ištrintas iš jūsų įrenginio."; - static String m87(fileType) => + static String m89(fileType) => "Šis ${fileType} yra ir saugykloje „Ente“ bei įrenginyje."; - static String m88(fileType) => "Šis ${fileType} bus ištrintas iš „Ente“."; + static String m90(fileType) => "Šis ${fileType} bus ištrintas iš „Ente“."; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m91(name) => "Sportai su ${name}"; - static String m93(id) => + static String m92(name) => "Dėmesys ${name}"; + + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; + + static String m94( + usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => + "${usedAmount} ${usedStorageUnit} iš ${totalAmount} ${totalStorageUnit} naudojama"; + + static String m95(id) => "Jūsų ${id} jau susietas su kita „Ente“ paskyra.\nJei norite naudoti savo ${id} su šia paskyra, susisiekite su mūsų palaikymo komanda."; - static String m94(endDate) => "Jūsų prenumerata bus atsisakyta ${endDate}"; + static String m96(endDate) => "Jūsų prenumerata bus atsisakyta ${endDate}"; - static String m95(completed, total) => + static String m97(completed, total) => "${completed} / ${total} išsaugomi prisiminimai"; - static String m96(ignoreReason) => + static String m98(ignoreReason) => "Palieskite, kad įkeltumėte. Įkėlimas šiuo metu ignoruojamas dėl ${ignoreReason}."; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "Jie taip pat gauna ${storageAmountInGB} GB"; - static String m98(email) => "Tai – ${email} patvirtinimo ID"; - - static String m99(count) => - "${Intl.plural(count, one: 'Šią savaitę, prieš ${count} metus', other: 'Šią savaitę, prieš ${count} metų')}"; - - static String m100(dateFormat) => "${dateFormat} per metus"; + static String m100(email) => "Tai – ${email} patvirtinimo ID"; static String m101(count) => + "${Intl.plural(count, one: 'Šią savaitę, prieš ${count} metus', other: 'Šią savaitę, prieš ${count} metų')}"; + + static String m102(dateFormat) => "${dateFormat} per metus"; + + static String m103(count) => "${Intl.plural(count, zero: 'Netrukus', one: '1 diena', other: '${count} dienų')}"; - static String m102(year) => "Kelionė per ${year}"; + static String m104(year) => "Kelionė per ${year}"; - static String m103(location) => "Kelionė į ${location}"; + static String m105(location) => "Kelionė į ${location}"; - static String m104(email) => + static String m106(email) => "Buvote pakviesti tapti ${email} palikimo kontaktu."; - static String m105(galleryType) => + static String m107(galleryType) => "Galerijos tipas ${galleryType} nepalaikomas pervadinimui."; - static String m106(ignoreReason) => + static String m108(ignoreReason) => "Įkėlimas ignoruojamas dėl ${ignoreReason}."; - static String m107(count) => "Išsaugomi ${count} prisiminimai..."; + static String m109(count) => "Išsaugomi ${count} prisiminimai..."; - static String m108(endDate) => "Galioja iki ${endDate}"; + static String m110(endDate) => "Galioja iki ${endDate}"; - static String m109(email) => "Patvirtinti ${email}"; + static String m111(email) => "Patvirtinti ${email}"; - static String m112(email) => - "Išsiuntėme laišką adresu ${email}"; + static String m112(name) => "Peržiūrėkite ${name}, kad atsietumėte"; static String m113(count) => + "${Intl.plural(count, zero: 'Įtraukta 0 žiūrėtojų', one: 'Įtrauktas 1 žiūrėtojas', other: 'Įtraukta ${count} žiūrėtojų')}"; + + static String m114(email) => + "Išsiuntėme laišką adresu ${email}"; + + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + + static String m116(count) => "${Intl.plural(count, one: 'prieš ${count} metus', other: 'prieš ${count} metų')}"; - static String m114(name) => "Jūs ir ${name}"; + static String m117(name) => "Jūs ir ${name}"; - static String m115(storageSaved) => "Sėkmingai atlaisvinote ${storageSaved}!"; + static String m118(storageSaved) => "Sėkmingai atlaisvinote ${storageSaved}!"; final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { @@ -288,19 +343,28 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Sveiki sugrįžę!"), "ackPasswordLostWarning": MessageLookupByLibrary.simpleMessage( "Suprantu, kad jei prarasiu slaptažodį, galiu prarasti savo duomenis, kadangi mano duomenys yra visapusiškai užšifruoti"), + "actionNotSupportedOnFavouritesAlbum": + MessageLookupByLibrary.simpleMessage( + "Veiksmas nepalaikomas Mėgstamų albume."), "activeSessions": MessageLookupByLibrary.simpleMessage("Aktyvūs seansai"), "add": MessageLookupByLibrary.simpleMessage("Pridėti"), "addAName": MessageLookupByLibrary.simpleMessage("Pridėti vardą"), "addANewEmail": - MessageLookupByLibrary.simpleMessage("Pridėti naują el. paštą"), + MessageLookupByLibrary.simpleMessage("Įtraukite naują el. paštą"), + "addAlbumWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Pridėkite albumo valdiklį prie savo pradžios ekrano ir grįžkite čia, kad tinkintumėte."), "addCollaborator": MessageLookupByLibrary.simpleMessage("Pridėti bendradarbį"), "addCollaborators": m1, "addFiles": MessageLookupByLibrary.simpleMessage("Pridėti failus"), + "addFromDevice": + MessageLookupByLibrary.simpleMessage("Pridėti iš įrenginio"), "addItem": m2, "addLocation": MessageLookupByLibrary.simpleMessage("Pridėti vietovę"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Pridėti"), + "addMemoriesWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Pridėkite prisiminimų valdiklį prie savo pradžios ekrano ir grįžkite čia, kad tinkintumėte."), "addMore": MessageLookupByLibrary.simpleMessage("Pridėti daugiau"), "addName": MessageLookupByLibrary.simpleMessage("Pridėti vardą"), "addNameOrMerge": @@ -312,12 +376,23 @@ class MessageLookup extends MessageLookupByLibrary { "Išsami informacija apie priedus"), "addOnValidTill": m3, "addOns": MessageLookupByLibrary.simpleMessage("Priedai"), + "addParticipants": + MessageLookupByLibrary.simpleMessage("Įtraukti dalyvių"), + "addPeopleWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Pridėkite asmenų valdiklį prie savo pradžios ekrano ir grįžkite čia, kad tinkintumėte."), + "addPhotos": MessageLookupByLibrary.simpleMessage("Įtraukti nuotraukų"), + "addSelected": + MessageLookupByLibrary.simpleMessage("Pridėti pasirinktus"), "addToAlbum": MessageLookupByLibrary.simpleMessage("Pridėti į albumą"), "addToEnte": MessageLookupByLibrary.simpleMessage("Pridėti į „Ente“"), + "addToHiddenAlbum": + MessageLookupByLibrary.simpleMessage("Įtraukti į paslėptą albumą"), "addTrustedContact": MessageLookupByLibrary.simpleMessage("Pridėti patikimą kontaktą"), "addViewer": MessageLookupByLibrary.simpleMessage("Pridėti žiūrėtoją"), "addViewers": m4, + "addYourPhotosNow": MessageLookupByLibrary.simpleMessage( + "Įtraukite savo nuotraukas dabar"), "addedAs": MessageLookupByLibrary.simpleMessage("Pridėta kaip"), "addedBy": m5, "addedSuccessfullyTo": m6, @@ -339,6 +414,8 @@ class MessageLookup extends MessageLookupByLibrary { "albumUpdated": MessageLookupByLibrary.simpleMessage("Atnaujintas albumas"), "albums": MessageLookupByLibrary.simpleMessage("Albumai"), + "albumsWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Pasirinkite albumus, kuriuos norite matyti savo pradžios ekrane."), "allClear": MessageLookupByLibrary.simpleMessage("✨ Viskas išvalyta"), "allMemoriesPreserved": MessageLookupByLibrary.simpleMessage("Išsaugoti visi prisiminimai"), @@ -363,8 +440,12 @@ class MessageLookup extends MessageLookupByLibrary { "Leisti prieigą prie nuotraukų"), "androidBiometricHint": MessageLookupByLibrary.simpleMessage("Patvirtinkite tapatybę"), + "androidBiometricNotRecognized": MessageLookupByLibrary.simpleMessage( + "Neatpažinta. Bandykite dar kartą."), "androidBiometricRequiredTitle": MessageLookupByLibrary.simpleMessage("Privaloma biometrija"), + "androidBiometricSuccess": + MessageLookupByLibrary.simpleMessage("Sėkmė"), "androidCancelButton": MessageLookupByLibrary.simpleMessage("Atšaukti"), "androidDeviceCredentialsRequiredTitle": MessageLookupByLibrary.simpleMessage( @@ -454,6 +535,8 @@ class MessageLookup extends MessageLookupByLibrary { "Tapatybės nustatymas sėkmingas."), "autoCastDialogBody": MessageLookupByLibrary.simpleMessage( "Čia matysite pasiekiamus perdavimo įrenginius."), + "autoCastiOSPermission": MessageLookupByLibrary.simpleMessage( + "Įsitikinkite, kad programai „Ente“ nuotraukos yra įjungti vietinio tinklo leidimai, nustatymuose."), "autoLock": MessageLookupByLibrary.simpleMessage("Automatinis užraktas"), "autoLockFeatureDescription": MessageLookupByLibrary.simpleMessage( @@ -465,6 +548,7 @@ class MessageLookup extends MessageLookupByLibrary { "autoPairDesc": MessageLookupByLibrary.simpleMessage( "Automatinis susiejimas veikia tik su įrenginiais, kurie palaiko „Chromecast“."), "available": MessageLookupByLibrary.simpleMessage("Prieinama"), + "availableStorageSpace": m10, "backedUpFolders": MessageLookupByLibrary.simpleMessage( "Sukurtos atsarginės aplankų kopijos"), "backgroundWithThem": m11, @@ -522,7 +606,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Nepavyko perduoti albumo"), "castInstruction": MessageLookupByLibrary.simpleMessage( "Aplankykite cast.ente.io įrenginyje, kurį norite susieti.\n\nĮveskite toliau esantį kodą, kad paleistumėte albumą televizoriuje."), - "centerPoint": MessageLookupByLibrary.simpleMessage("Vidurio taškas"), + "centerPoint": MessageLookupByLibrary.simpleMessage("Centro taškas"), "change": MessageLookupByLibrary.simpleMessage("Keisti"), "changeEmail": MessageLookupByLibrary.simpleMessage("Keisti el. paštą"), "changeLocationOfSelectedItems": MessageLookupByLibrary.simpleMessage( @@ -556,10 +640,11 @@ class MessageLookup extends MessageLookupByLibrary { "clearCaches": MessageLookupByLibrary.simpleMessage("Valyti podėlius"), "clearIndexes": MessageLookupByLibrary.simpleMessage("Valyti indeksavimus"), + "click": MessageLookupByLibrary.simpleMessage("• Spauskite"), "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage( "• Spustelėkite ant perpildymo meniu"), "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), + "Spustelėkite, kad įdiegtumėte geriausią mūsų versiją iki šiol"), "close": MessageLookupByLibrary.simpleMessage("Uždaryti"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage( "Grupuoti pagal užfiksavimo laiką"), @@ -620,6 +705,7 @@ class MessageLookup extends MessageLookupByLibrary { "Susisiekti su palaikymo komanda"), "contactToManageSubscription": m19, "contacts": MessageLookupByLibrary.simpleMessage("Kontaktai"), + "contents": MessageLookupByLibrary.simpleMessage("Turinys"), "continueLabel": MessageLookupByLibrary.simpleMessage("Tęsti"), "continueOnFreeTrial": MessageLookupByLibrary.simpleMessage( "Tęsti nemokame bandomajame laikotarpyje"), @@ -638,6 +724,8 @@ class MessageLookup extends MessageLookupByLibrary { "couldNotUpdateSubscription": MessageLookupByLibrary.simpleMessage( "Nepavyko atnaujinti prenumeratos"), "count": MessageLookupByLibrary.simpleMessage("Skaičių"), + "crashReporting": + MessageLookupByLibrary.simpleMessage("Pranešti apie strigčius"), "create": MessageLookupByLibrary.simpleMessage("Kurti"), "createAccount": MessageLookupByLibrary.simpleMessage("Kurti paskyrą"), "createAlbumActionHint": MessageLookupByLibrary.simpleMessage( @@ -704,9 +792,10 @@ class MessageLookup extends MessageLookupByLibrary { "deleteItemCount": m21, "deleteLocation": MessageLookupByLibrary.simpleMessage("Ištrinti vietovę"), + "deleteMultipleAlbumDialog": m22, "deletePhotos": MessageLookupByLibrary.simpleMessage("Ištrinti nuotraukas"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Trūksta pagrindinės funkcijos, kurios man reikia"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -746,7 +835,7 @@ class MessageLookup extends MessageLookupByLibrary { "Žiūrėtojai vis tiek gali daryti ekrano kopijas arba išsaugoti nuotraukų kopijas naudojant išorinius įrankius"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Atkreipkite dėmesį"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Išjungti dvigubą tapatybės nustatymą"), "disablingTwofactorAuthentication": @@ -773,10 +862,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Lankymo kortelės"), "discover_wallpapers": MessageLookupByLibrary.simpleMessage("Ekrano fonai"), + "dismiss": MessageLookupByLibrary.simpleMessage("Atmesti"), "distanceInKMUnit": MessageLookupByLibrary.simpleMessage("km"), "doNotSignOut": MessageLookupByLibrary.simpleMessage("Neatsijungti"), "doThisLater": MessageLookupByLibrary.simpleMessage("Daryti tai vėliau"), + "doYouWantToDiscardTheEditsYouHaveMade": + MessageLookupByLibrary.simpleMessage( + "Ar norite atmesti atliktus pakeitimus?"), "done": MessageLookupByLibrary.simpleMessage("Atlikta"), "dontSave": MessageLookupByLibrary.simpleMessage("Neišsaugoti"), "doubleYourStorage": @@ -785,16 +878,19 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("Atsisiuntimas nepavyko."), "downloading": MessageLookupByLibrary.simpleMessage("Atsisiunčiama..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("Redaguoti"), + "editEmailAlreadyLinked": m28, "editLocation": MessageLookupByLibrary.simpleMessage("Redaguoti vietovę"), "editLocationTagTitle": MessageLookupByLibrary.simpleMessage("Redaguoti vietovę"), "editPerson": MessageLookupByLibrary.simpleMessage("Redaguoti asmenį"), "editTime": MessageLookupByLibrary.simpleMessage("Redaguoti laiką"), + "editsSaved": + MessageLookupByLibrary.simpleMessage("Redagavimai išsaugoti"), "editsToLocationWillOnlyBeSeenWithinEnte": MessageLookupByLibrary.simpleMessage( "Vietovės pakeitimai bus matomi tik per „Ente“"), @@ -802,15 +898,16 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("El. paštas"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage( "El. paštas jau užregistruotas."), - "emailChangedTo": m28, - "emailDoesNotHaveEnteAccount": m29, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailDoesNotHaveEnteAccount": m30, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage("El. paštas neregistruotas."), "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("El. pašto patvirtinimas"), "emailYourLogs": MessageLookupByLibrary.simpleMessage( "Atsiųskite žurnalus el. laišku"), + "embracingThem": m32, "emergencyContacts": MessageLookupByLibrary.simpleMessage("Skubios pagalbos kontaktai"), "empty": MessageLookupByLibrary.simpleMessage("Ištuštinti"), @@ -853,6 +950,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Gimtadienis (neprivaloma)"), "enterEmail": MessageLookupByLibrary.simpleMessage("Įveskite el. paštą"), + "enterFileName": + MessageLookupByLibrary.simpleMessage("Įveskite failo pavadinimą"), "enterName": MessageLookupByLibrary.simpleMessage("Įveskite vardą"), "enterNewPasswordToEncrypt": MessageLookupByLibrary.simpleMessage( "Įveskite naują slaptažodį, kurį galime naudoti jūsų duomenims šifruoti"), @@ -872,6 +971,8 @@ class MessageLookup extends MessageLookupByLibrary { "Įveskite tinkamą el. pašto adresą."), "enterYourEmailAddress": MessageLookupByLibrary.simpleMessage( "Įveskite savo el. pašto adresą"), + "enterYourNewEmailAddress": MessageLookupByLibrary.simpleMessage( + "Įveskite savo naują el. pašto adresą"), "enterYourPassword": MessageLookupByLibrary.simpleMessage("Įveskite savo slaptažodį"), "enterYourRecoveryKey": @@ -889,7 +990,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Eksportuoti duomenis"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage( "Rastos papildomos nuotraukos"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage( "Veidas dar nesugrupuotas. Grįžkite vėliau."), "faceRecognition": @@ -900,6 +1001,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Nepavyko pritaikyti kodo."), "failedToCancel": MessageLookupByLibrary.simpleMessage("Nepavyko atsisakyti"), + "failedToDownloadVideo": MessageLookupByLibrary.simpleMessage( + "Nepavyko atsisiųsti vaizdo įrašo."), "failedToFetchActiveSessions": MessageLookupByLibrary.simpleMessage( "Nepavyko gauti aktyvių seansų."), "failedToFetchOriginalForEdit": MessageLookupByLibrary.simpleMessage( @@ -924,6 +1027,7 @@ class MessageLookup extends MessageLookupByLibrary { "faq": MessageLookupByLibrary.simpleMessage("DUK"), "faqs": MessageLookupByLibrary.simpleMessage("DUK"), "favorite": MessageLookupByLibrary.simpleMessage("Pamėgti"), + "feastingWithThem": m34, "feedback": MessageLookupByLibrary.simpleMessage("Atsiliepimai"), "file": MessageLookupByLibrary.simpleMessage("Failas"), "fileFailedToSaveToGallery": MessageLookupByLibrary.simpleMessage( @@ -935,13 +1039,18 @@ class MessageLookup extends MessageLookupByLibrary { "fileSavedToGallery": MessageLookupByLibrary.simpleMessage( "Failas išsaugotas į galeriją"), "fileTypes": MessageLookupByLibrary.simpleMessage("Failų tipai"), - "filesBackedUpInAlbum": m35, + "fileTypesAndNames": + MessageLookupByLibrary.simpleMessage("Failų tipai ir pavadinimai"), + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, + "filesDeleted": MessageLookupByLibrary.simpleMessage("Failai ištrinti"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage("Failai išsaugoti į galeriją"), "findPeopleByName": MessageLookupByLibrary.simpleMessage( "Greitai suraskite žmones pagal vardą"), "findThemQuickly": MessageLookupByLibrary.simpleMessage("Raskite juos greitai"), + "flip": MessageLookupByLibrary.simpleMessage("Apversti"), "food": MessageLookupByLibrary.simpleMessage("Kulinarinis malonumas"), "forYourMemories": MessageLookupByLibrary.simpleMessage("jūsų prisiminimams"), @@ -950,28 +1059,28 @@ class MessageLookup extends MessageLookupByLibrary { "foundFaces": MessageLookupByLibrary.simpleMessage("Rasti veidai"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("Gauta nemokama saugykla"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("Naudojama nemokama saugykla"), "freeTrial": MessageLookupByLibrary.simpleMessage( "Nemokamas bandomasis laikotarpis"), - "freeTrialValidTill": m37, - "freeUpAccessPostDelete": m38, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAccessPostDelete": m39, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("Atlaisvinti įrenginio vietą"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Sutaupykite vietos savo įrenginyje išvalydami failus, kurių atsarginės kopijos jau buvo sukurtos."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Atlaisvinti vietos"), - "freeUpSpaceSaving": m40, + "freeUpSpaceSaving": m41, "gallery": MessageLookupByLibrary.simpleMessage("Galerija"), "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Galerijoje rodoma iki 1000 prisiminimų"), "general": MessageLookupByLibrary.simpleMessage("Bendrieji"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Generuojami šifravimo raktai..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("Eiti į nustatymus"), "googlePlayId": @@ -981,6 +1090,8 @@ class MessageLookup extends MessageLookupByLibrary { "grantPermission": MessageLookupByLibrary.simpleMessage("Suteikti leidimą"), "greenery": MessageLookupByLibrary.simpleMessage("Žaliasis gyvenimas"), + "groupNearbyPhotos": MessageLookupByLibrary.simpleMessage( + "Grupuoti netoliese nuotraukas"), "guestView": MessageLookupByLibrary.simpleMessage("Svečio peržiūra"), "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( "Kad įjungtumėte svečio peržiūrą, sistemos nustatymuose nustatykite įrenginio prieigos kodą arba ekrano užraktą."), @@ -999,6 +1110,9 @@ class MessageLookup extends MessageLookupByLibrary { "hideSharedItemsFromHomeGallery": MessageLookupByLibrary.simpleMessage( "Slėpti bendrinamus elementus iš pagrindinės galerijos"), "hiding": MessageLookupByLibrary.simpleMessage("Slepiama..."), + "hikingWithThem": m43, + "hostedAtOsmFrance": + MessageLookupByLibrary.simpleMessage("Talpinama OSM Prancūzijoje"), "howItWorks": MessageLookupByLibrary.simpleMessage("Kaip tai veikia"), "howToViewShareeVerificationID": MessageLookupByLibrary.simpleMessage( "Paprašykite jų ilgai paspausti savo el. pašto adresą nustatymų ekrane ir patvirtinti, kad abiejų įrenginių ID sutampa."), @@ -1050,10 +1164,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Kviesti į „Ente“"), "inviteYourFriends": MessageLookupByLibrary.simpleMessage("Kviesti savo draugus"), + "inviteYourFriendsToEnte": MessageLookupByLibrary.simpleMessage( + "Pakvieskite savo draugus į „Ente“"), "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Atrodo, kad kažkas nutiko ne taip. Bandykite pakartotinai po kurio laiko. Jei klaida tęsiasi, susisiekite su mūsų palaikymo komanda."), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Elementai rodo likusių dienų skaičių iki visiško ištrynimo."), @@ -1076,6 +1192,7 @@ class MessageLookup extends MessageLookupByLibrary { "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( "Maloniai padėkite mums su šia informacija."), "language": MessageLookupByLibrary.simpleMessage("Kalba"), + "lastTimeWithThem": m45, "lastUpdated": MessageLookupByLibrary.simpleMessage("Paskutinį kartą atnaujintą"), "lastYearsTrip": @@ -1089,7 +1206,7 @@ class MessageLookup extends MessageLookupByLibrary { "legacy": MessageLookupByLibrary.simpleMessage("Palikimas"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("Palikimo paskyros"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage( "Palikimas leidžia patikimiems kontaktams pasiekti jūsų paskyrą jums nesant."), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( @@ -1102,9 +1219,11 @@ class MessageLookup extends MessageLookupByLibrary { "linkDeviceLimit": MessageLookupByLibrary.simpleMessage("Įrenginių riba"), "linkEmail": MessageLookupByLibrary.simpleMessage("Susieti el. paštą"), + "linkEmailToContactBannerCaption": + MessageLookupByLibrary.simpleMessage("spartesniam bendrinimui"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Įjungta"), "linkExpired": MessageLookupByLibrary.simpleMessage("Nebegalioja"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Nuorodos galiojimo laikas"), "linkHasExpired": @@ -1112,8 +1231,9 @@ class MessageLookup extends MessageLookupByLibrary { "linkNeverExpires": MessageLookupByLibrary.simpleMessage("Niekada"), "linkPerson": MessageLookupByLibrary.simpleMessage("Susiekite asmenį,"), "linkPersonCaption": MessageLookupByLibrary.simpleMessage( - "kad geriau bendrintumėte patirtį"), - "linkPersonToEmailConfirmation": m48, + "geresniam bendrinimo patirčiai"), + "linkPersonToEmail": m48, + "linkPersonToEmailConfirmation": m49, "livePhotos": MessageLookupByLibrary.simpleMessage("Gyvos nuotraukos"), "loadMessage1": MessageLookupByLibrary.simpleMessage( "Galite bendrinti savo prenumeratą su šeima."), @@ -1137,6 +1257,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Įkeliami EXIF duomenys..."), "loadingGallery": MessageLookupByLibrary.simpleMessage("Įkeliama galerija..."), + "loadingMessage": MessageLookupByLibrary.simpleMessage( + "Įkeliamos jūsų nuotraukos..."), "loadingModel": MessageLookupByLibrary.simpleMessage("Atsisiunčiami modeliai..."), "loadingYourPhotos": @@ -1175,7 +1297,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Ilgai paspauskite elementą, kad peržiūrėtumėte per visą ekraną"), "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), + "Pažvelkite atgal į savo prisiminimus 🌄"), "loopVideoOff": MessageLookupByLibrary.simpleMessage( "Išjungtas vaizdo įrašo ciklas"), "loopVideoOn": MessageLookupByLibrary.simpleMessage( @@ -1204,7 +1326,10 @@ class MessageLookup extends MessageLookupByLibrary { "mastodon": MessageLookupByLibrary.simpleMessage("„Mastodon“"), "matrix": MessageLookupByLibrary.simpleMessage("„Matrix“"), "me": MessageLookupByLibrary.simpleMessage("Aš"), - "memoryCount": m49, + "memories": MessageLookupByLibrary.simpleMessage("Prisiminimai"), + "memoriesWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Pasirinkite, kokius prisiminimus norite matyti savo pradžios ekrane."), + "memoryCount": m50, "merchandise": MessageLookupByLibrary.simpleMessage("Atributika"), "mergeWithExisting": MessageLookupByLibrary.simpleMessage("Sujungti su esamais"), @@ -1225,6 +1350,9 @@ class MessageLookup extends MessageLookupByLibrary { "mobileWebDesktop": MessageLookupByLibrary.simpleMessage( "Mobiliuosiuose, internete ir darbalaukyje"), "moderateStrength": MessageLookupByLibrary.simpleMessage("Vidutinė"), + "modifyYourQueryOrTrySearchingFor": + MessageLookupByLibrary.simpleMessage( + "Modifikuokite užklausą arba bandykite ieškoti"), "moments": MessageLookupByLibrary.simpleMessage("Akimirkos"), "month": MessageLookupByLibrary.simpleMessage("mėnesis"), "monthly": MessageLookupByLibrary.simpleMessage("Mėnesinis"), @@ -1234,12 +1362,14 @@ class MessageLookup extends MessageLookupByLibrary { "mostRecent": MessageLookupByLibrary.simpleMessage("Naujausią"), "mostRelevant": MessageLookupByLibrary.simpleMessage("Aktualiausią"), "mountains": MessageLookupByLibrary.simpleMessage("Per kalvas"), - "moveItem": m50, + "moveItem": m51, "moveSelectedPhotosToOneDate": MessageLookupByLibrary.simpleMessage( "Perkelti pasirinktas nuotraukas į vieną datą"), "moveToAlbum": MessageLookupByLibrary.simpleMessage("Perkelti į albumą"), - "movedSuccessfullyTo": m51, + "moveToHiddenAlbum": + MessageLookupByLibrary.simpleMessage("Perkelti į paslėptą albumą"), + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("Perkelta į šiukšlinę"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1255,13 +1385,15 @@ class MessageLookup extends MessageLookupByLibrary { "newAlbum": MessageLookupByLibrary.simpleMessage("Naujas albumas"), "newLocation": MessageLookupByLibrary.simpleMessage("Nauja vietovė"), "newPerson": MessageLookupByLibrary.simpleMessage("Naujas asmuo"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), + "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" naujas 📸"), "newRange": MessageLookupByLibrary.simpleMessage("Naujas intervalas"), "newToEnte": MessageLookupByLibrary.simpleMessage("Naujas platformoje „Ente“"), "newest": MessageLookupByLibrary.simpleMessage("Naujausią"), "next": MessageLookupByLibrary.simpleMessage("Toliau"), "no": MessageLookupByLibrary.simpleMessage("Ne"), + "noAlbumsSharedByYouYet": MessageLookupByLibrary.simpleMessage( + "Dar nėra albumų, kuriais bendrinotės."), "noDeviceFound": MessageLookupByLibrary.simpleMessage("Įrenginys nerastas"), "noDeviceLimit": MessageLookupByLibrary.simpleMessage("Jokio"), @@ -1282,6 +1414,8 @@ class MessageLookup extends MessageLookupByLibrary { "noPhotosAreBeingBackedUpRightNow": MessageLookupByLibrary.simpleMessage( "Šiuo metu nekuriamos atsarginės nuotraukų kopijos"), + "noPhotosFoundHere": + MessageLookupByLibrary.simpleMessage("Nuotraukų čia nerasta"), "noQuickLinksSelected": MessageLookupByLibrary.simpleMessage( "Nėra pasirinktų sparčiųjų nuorodų"), "noRecoveryKey": @@ -1291,10 +1425,10 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Rezultatų nėra."), "noResultsFound": MessageLookupByLibrary.simpleMessage("Rezultatų nerasta."), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage("Nerastas sistemos užraktas"), - "notPersonLabel": m53, + "notPersonLabel": m54, "notThisPerson": MessageLookupByLibrary.simpleMessage("Ne šis asmuo?"), "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( "Kol kas su jumis niekuo nesibendrinama."), @@ -1306,12 +1440,16 @@ class MessageLookup extends MessageLookupByLibrary { "onEnte": MessageLookupByLibrary.simpleMessage( "Saugykloje ente"), "onTheRoad": MessageLookupByLibrary.simpleMessage("Vėl kelyje"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), + "onThisDay": MessageLookupByLibrary.simpleMessage("Šią dieną"), + "onThisDayMemories": + MessageLookupByLibrary.simpleMessage("Šios dienos prisiminimai"), "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "Gaukite priminimus apie praėjusių metų šios dienos prisiminimus."), + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("Tik jiems"), "oops": MessageLookupByLibrary.simpleMessage("Ups"), + "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( + "Ups, nepavyko išsaugoti redagavimų."), "oopsSomethingWentWrong": MessageLookupByLibrary.simpleMessage("Ups, kažkas nutiko ne taip"), "openAlbumInBrowser": @@ -1323,6 +1461,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Atverti nustatymus"), "openTheItem": MessageLookupByLibrary.simpleMessage("• Atverkite elementą."), + "openstreetmapContributors": MessageLookupByLibrary.simpleMessage( + "„OpenStreetMap“ bendradarbiai"), "optionalAsShortAsYouLike": MessageLookupByLibrary.simpleMessage( "Nebūtina, trumpai, kaip jums patinka..."), "orMergeWithExistingPerson": @@ -1336,6 +1476,7 @@ class MessageLookup extends MessageLookupByLibrary { "pairingComplete": MessageLookupByLibrary.simpleMessage("Susiejimas baigtas"), "panorama": MessageLookupByLibrary.simpleMessage("Panorama"), + "partyWithThem": m56, "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage( "Vis dar laukiama patvirtinimo"), "passkey": MessageLookupByLibrary.simpleMessage("Slaptaraktis"), @@ -1346,18 +1487,20 @@ class MessageLookup extends MessageLookupByLibrary { "Slaptažodis sėkmingai pakeistas"), "passwordLock": MessageLookupByLibrary.simpleMessage("Slaptažodžio užraktas"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "Slaptažodžio stiprumas apskaičiuojamas atsižvelgiant į slaptažodžio ilgį, naudotus simbolius ir į tai, ar slaptažodis patenka į 10 000 dažniausiai naudojamų slaptažodžių."), "passwordWarning": MessageLookupByLibrary.simpleMessage( "Šio slaptažodžio nesaugome, todėl jei jį pamiršite, negalėsime iššifruoti jūsų duomenų"), + "pastYearsMemories": + MessageLookupByLibrary.simpleMessage("Praėjusių metų prisiminimai"), "paymentDetails": MessageLookupByLibrary.simpleMessage("Mokėjimo duomenys"), "paymentFailed": MessageLookupByLibrary.simpleMessage("Mokėjimas nepavyko"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Deja, jūsų mokėjimas nepavyko. Susisiekite su palaikymo komanda ir mes jums padėsime!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("Laukiami elementai"), "pendingSync": @@ -1365,29 +1508,41 @@ class MessageLookup extends MessageLookupByLibrary { "people": MessageLookupByLibrary.simpleMessage("Asmenys"), "peopleUsingYourCode": MessageLookupByLibrary.simpleMessage( "Asmenys, naudojantys jūsų kodą"), + "peopleWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Pasirinkite asmenis, kuriuos norite matyti savo pradžios ekrane."), + "permDeleteWarning": MessageLookupByLibrary.simpleMessage( + "Visi elementai šiukšlinėje bus negrįžtamai ištrinti.\n\nŠio veiksmo negalima anuliuoti."), "permanentlyDelete": MessageLookupByLibrary.simpleMessage("Ištrinti negrįžtamai"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage( "Ištrinti negrįžtamai iš įrenginio?"), + "personIsAge": m59, "personName": MessageLookupByLibrary.simpleMessage("Asmens vardas"), + "personTurningAge": m60, + "pets": MessageLookupByLibrary.simpleMessage("Furio draugai"), + "photoDescriptions": + MessageLookupByLibrary.simpleMessage("Nuotraukų aprašai"), "photoGridSize": MessageLookupByLibrary.simpleMessage("Nuotraukų tinklelio dydis"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("nuotrauka"), - "photocountPhotos": m60, + "photocountPhotos": m61, "photos": MessageLookupByLibrary.simpleMessage("Nuotraukos"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage( "Jūsų pridėtos nuotraukos bus pašalintos iš albumo"), + "photosCount": m62, "photosKeepRelativeTimeDifference": MessageLookupByLibrary.simpleMessage( "Nuotraukos išlaiko santykinį laiko skirtumą"), + "pickCenterPoint": + MessageLookupByLibrary.simpleMessage("Pasirinkite centro tašką"), "pinAlbum": MessageLookupByLibrary.simpleMessage("Prisegti albumą"), "pinLock": MessageLookupByLibrary.simpleMessage("PIN užrakinimas"), "playOnTv": MessageLookupByLibrary.simpleMessage( "Paleisti albumą televizoriuje"), "playOriginal": MessageLookupByLibrary.simpleMessage("Leisti originalą"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playStream": MessageLookupByLibrary.simpleMessage("Leisti srautinį perdavimą"), "playstoreSubscription": @@ -1398,13 +1553,17 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportAndWeWillBeHappyToHelp": MessageLookupByLibrary.simpleMessage( "Susisiekite adresu support@ente.io ir mes mielai padėsime!"), + "pleaseContactSupportIfTheProblemPersists": + MessageLookupByLibrary.simpleMessage( + "Jei problema išlieka, susisiekite su pagalbos komanda."), + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage("Suteikite leidimus."), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Prisijunkite iš naujo."), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Pasirinkite sparčiąsias nuorodas, kad pašalintumėte"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Bandykite dar kartą."), "pleaseVerifyTheCodeYouHaveEntered": @@ -1417,6 +1576,7 @@ class MessageLookup extends MessageLookupByLibrary { "Palaukite kurį laiką prieš bandydami pakartotinai"), "pleaseWaitThisWillTakeAWhile": MessageLookupByLibrary.simpleMessage( "Palaukite, tai šiek tiek užtruks."), + "posingWithThem": m66, "preparingLogs": MessageLookupByLibrary.simpleMessage("Ruošiami žurnalai..."), "preserveMore": @@ -1436,7 +1596,7 @@ class MessageLookup extends MessageLookupByLibrary { "proceed": MessageLookupByLibrary.simpleMessage("Tęsti"), "processed": MessageLookupByLibrary.simpleMessage("Apdorota"), "processing": MessageLookupByLibrary.simpleMessage("Apdorojama"), - "processingImport": m66, + "processingImport": m67, "processingVideos": MessageLookupByLibrary.simpleMessage("Apdorojami vaizdo įrašai"), "publicLinkCreated": @@ -1444,11 +1604,16 @@ class MessageLookup extends MessageLookupByLibrary { "publicLinkEnabled": MessageLookupByLibrary.simpleMessage("Įjungta viešoji nuoroda"), "queued": MessageLookupByLibrary.simpleMessage("Įtraukta eilėje"), + "quickLinks": MessageLookupByLibrary.simpleMessage("Sparčios nuorodos"), + "radius": MessageLookupByLibrary.simpleMessage("Spindulys"), "raiseTicket": MessageLookupByLibrary.simpleMessage("Sukurti paraišką"), "rateTheApp": MessageLookupByLibrary.simpleMessage("Vertinti programą"), "rateUs": MessageLookupByLibrary.simpleMessage("Vertinti mus"), - "rateUsOnStore": m67, - "reassignedToName": m68, + "rateUsOnStore": m68, + "reassignMe": MessageLookupByLibrary.simpleMessage("Perskirstyti „Aš“"), + "reassignedToName": m69, + "reassigningLoading": + MessageLookupByLibrary.simpleMessage("Perskirstoma..."), "recover": MessageLookupByLibrary.simpleMessage("Atkurti"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Atkurti paskyrą"), @@ -1457,7 +1622,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Atkurti paskyrą"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage("Pradėtas atkūrimas"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("Atkūrimo raktas"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( "Nukopijuotas atkūrimo raktas į iškarpinę"), @@ -1471,12 +1636,12 @@ class MessageLookup extends MessageLookupByLibrary { "Patvirtintas atkūrimo raktas"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "Atkūrimo raktas – vienintelis būdas atkurti nuotraukas, jei pamiršote slaptažodį. Atkūrimo raktą galite rasti Nustatymose > Paskyra.\n\nĮveskite savo atkūrimo raktą čia, kad patvirtintumėte, ar teisingai jį išsaugojote."), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage("Atkūrimas sėkmingas."), "recoveryWarning": MessageLookupByLibrary.simpleMessage( "Patikimas kontaktas bando pasiekti jūsų paskyrą."), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "Dabartinis įrenginys nėra pakankamai galingas, kad patvirtintų jūsų slaptažodį, bet mes galime iš naujo sugeneruoti taip, kad jis veiktų su visais įrenginiais.\n\nPrisijunkite naudojant atkūrimo raktą ir sugeneruokite iš naujo slaptažodį (jei norite, galite vėl naudoti tą patį)."), "recreatePasswordTitle": @@ -1492,7 +1657,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Duokite šį kodą savo draugams"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Jie užsiregistruoja mokamą planą"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("Rekomendacijos"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Šiuo metu rekomendacijos yra pristabdytos"), @@ -1524,7 +1689,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Šalinti nuorodą"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Šalinti dalyvį"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Šalinti asmens žymą"), "removePublicLink": @@ -1545,7 +1710,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("Pervadinti failą"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Pratęsti prenumeratą"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Pranešti apie riktą"), "reportBug": @@ -1556,6 +1721,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Atkurti ignoruojamus failus"), "resetPasswordTitle": MessageLookupByLibrary.simpleMessage( "Nustatyti slaptažodį iš naujo"), + "resetPerson": MessageLookupByLibrary.simpleMessage("Šalinti"), "resetToDefault": MessageLookupByLibrary.simpleMessage( "Atkurti numatytąsias reikšmes"), "restore": MessageLookupByLibrary.simpleMessage("Atkurti"), @@ -1563,24 +1729,33 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Atkurti į albumą"), "restoringFiles": MessageLookupByLibrary.simpleMessage("Atkuriami failai..."), + "resumableUploads": + MessageLookupByLibrary.simpleMessage("Tęstiniai įkėlimai"), "retry": MessageLookupByLibrary.simpleMessage("Kartoti"), + "review": MessageLookupByLibrary.simpleMessage("Peržiūrėti"), "reviewDeduplicateItems": MessageLookupByLibrary.simpleMessage( "Peržiūrėkite ir ištrinkite elementus, kurie, jūsų manymu, yra dublikatai."), "reviewSuggestions": MessageLookupByLibrary.simpleMessage("Peržiūrėti pasiūlymus"), "right": MessageLookupByLibrary.simpleMessage("Dešinė"), + "roadtripWithThem": m76, "rotate": MessageLookupByLibrary.simpleMessage("Sukti"), + "rotateLeft": MessageLookupByLibrary.simpleMessage("Sukti į kairę"), + "rotateRight": MessageLookupByLibrary.simpleMessage("Sukti į dešinę"), "safelyStored": MessageLookupByLibrary.simpleMessage("Saugiai saugoma"), + "save": MessageLookupByLibrary.simpleMessage("Išsaugoti"), "saveChangesBeforeLeavingQuestion": MessageLookupByLibrary.simpleMessage( "Išsaugoti pakeitimus prieš išeinant?"), "saveCollage": MessageLookupByLibrary.simpleMessage("Išsaugoti koliažą"), + "saveCopy": MessageLookupByLibrary.simpleMessage("Išsaugoti kopiją"), "saveKey": MessageLookupByLibrary.simpleMessage("Išsaugoti raktą"), "savePerson": MessageLookupByLibrary.simpleMessage("Išsaugoti asmenį"), "saveYourRecoveryKeyIfYouHaventAlready": MessageLookupByLibrary.simpleMessage( "Išsaugokite atkūrimo raktą, jei dar to nepadarėte"), + "saving": MessageLookupByLibrary.simpleMessage("Išsaugoma..."), "savingEdits": MessageLookupByLibrary.simpleMessage("Išsaugomi redagavimai..."), "scanCode": MessageLookupByLibrary.simpleMessage("Skenuoti kodą"), @@ -1588,14 +1763,26 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Skenuokite šį QR kodą\nsu autentifikatoriaus programa"), "search": MessageLookupByLibrary.simpleMessage("Ieškokite"), + "searchAlbumsEmptySection": + MessageLookupByLibrary.simpleMessage("Albumai"), "searchByAlbumNameHint": MessageLookupByLibrary.simpleMessage("Albumo pavadinimas"), "searchByExamples": MessageLookupByLibrary.simpleMessage( "• Albumų pavadinimai (pvz., „Fotoaparatas“)\n• Failų tipai (pvz., „Vaizdo įrašai“, „.gif“)\n• Metai ir mėnesiai (pvz., „2022“, „sausis“)\n• Šventės (pvz., „Kalėdos“)\n• Nuotraukų aprašymai (pvz., „#džiaugsmas“)"), "searchCaptionEmptySection": MessageLookupByLibrary.simpleMessage( "Pridėkite aprašymus, pavyzdžiui, „#kelionė“, į nuotraukos informaciją, kad greičiau jas čia rastumėte."), + "searchDatesEmptySection": MessageLookupByLibrary.simpleMessage( + "Ieškokite pagal datą, mėnesį arba metus"), "searchDiscoverEmptySection": MessageLookupByLibrary.simpleMessage( "Vaizdai bus rodomi čia, kai bus užbaigtas apdorojimas ir sinchronizavimas."), + "searchFaceEmptySection": MessageLookupByLibrary.simpleMessage( + "Asmenys bus rodomi čia, kai bus užbaigtas indeksavimas."), + "searchFileTypesAndNamesEmptySection": + MessageLookupByLibrary.simpleMessage("Failų tipai ir pavadinimai"), + "searchHint1": + MessageLookupByLibrary.simpleMessage("Sparti paieška įrenginyje"), + "searchHint2": + MessageLookupByLibrary.simpleMessage("Nuotraukų datos ir aprašai"), "searchHint3": MessageLookupByLibrary.simpleMessage( "Albumai, failų pavadinimai ir tipai"), "searchHint4": MessageLookupByLibrary.simpleMessage("Vietovė"), @@ -1607,8 +1794,8 @@ class MessageLookup extends MessageLookupByLibrary { "Pakvieskite asmenis ir čia matysite visas jų bendrinamas nuotraukas."), "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage( "Asmenys bus rodomi čia, kai bus užbaigtas apdorojimas ir sinchronizavimas."), - "searchResultCount": m76, - "searchSectionsLengthMismatch": m77, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("Saugumas"), "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage( "Žiūrėti viešų albumų nuorodas programoje"), @@ -1625,6 +1812,8 @@ class MessageLookup extends MessageLookupByLibrary { "selectDate": MessageLookupByLibrary.simpleMessage("Pasirinkti datą"), "selectFoldersForBackup": MessageLookupByLibrary.simpleMessage( "Pasirinkite aplankus atsarginėms kopijoms kurti"), + "selectItemsToAdd": MessageLookupByLibrary.simpleMessage( + "Pasirinkite elementus įtraukti"), "selectLanguage": MessageLookupByLibrary.simpleMessage("Pasirinkite kalbą"), "selectMailApp": @@ -1635,23 +1824,32 @@ class MessageLookup extends MessageLookupByLibrary { "Pasirinkti vieną datą ir laiką"), "selectOneDateAndTimeForAll": MessageLookupByLibrary.simpleMessage( "Pasirinkti vieną datą ir laiką viskam"), + "selectPersonToLink": MessageLookupByLibrary.simpleMessage( + "Pasirinkite asmenį, kurį susieti."), "selectReason": MessageLookupByLibrary.simpleMessage("Pasirinkite priežastį"), "selectStartOfRange": MessageLookupByLibrary.simpleMessage( "Pasirinkti intervalo pradžią"), "selectTime": MessageLookupByLibrary.simpleMessage("Pasirinkti laiką"), + "selectYourFace": + MessageLookupByLibrary.simpleMessage("Pasirinkite savo veidą"), "selectYourPlan": MessageLookupByLibrary.simpleMessage("Pasirinkite planą"), + "selectedAlbums": m79, "selectedFilesAreNotOnEnte": MessageLookupByLibrary.simpleMessage( "Pasirinkti failai nėra platformoje „Ente“"), "selectedFoldersWillBeEncryptedAndBackedUp": MessageLookupByLibrary.simpleMessage( "Pasirinkti aplankai bus užšifruoti ir sukurtos atsarginės kopijos."), + "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": + MessageLookupByLibrary.simpleMessage( + "Pasirinkti elementai bus ištrinti iš visų albumų ir perkelti į šiukšlinę."), "selectedItemsWillBeRemovedFromThisPerson": MessageLookupByLibrary.simpleMessage( "Pasirinkti elementai bus pašalinti iš šio asmens, bet nebus ištrinti iš jūsų bibliotekos."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, + "selfiesWithThem": m82, "send": MessageLookupByLibrary.simpleMessage("Siųsti"), "sendEmail": MessageLookupByLibrary.simpleMessage("Siųsti el. laišką"), "sendInvite": MessageLookupByLibrary.simpleMessage("Siųsti kvietimą"), @@ -1673,6 +1871,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Nustatykite naują PIN"), "setPasswordTitle": MessageLookupByLibrary.simpleMessage("Nustatyti slaptažodį"), + "setRadius": MessageLookupByLibrary.simpleMessage("Nustatyti spindulį"), "setupComplete": MessageLookupByLibrary.simpleMessage("Sąranka baigta"), "share": MessageLookupByLibrary.simpleMessage("Bendrinti"), "shareALink": @@ -1682,16 +1881,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Bendrinti albumą dabar"), "shareLink": MessageLookupByLibrary.simpleMessage("Bendrinti nuorodą"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Bendrinkite tik su tais asmenimis, su kuriais norite"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Atsisiųskite „Ente“, kad galėtume lengvai bendrinti originalios kokybės nuotraukas ir vaizdo įrašus.\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Bendrinkite su ne „Ente“ naudotojais."), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage( "Bendrinkite savo pirmąjį albumą"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1702,8 +1901,8 @@ class MessageLookup extends MessageLookupByLibrary { "sharedPhotoNotifications": MessageLookupByLibrary.simpleMessage( "Naujos bendrintos nuotraukos"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( - "Gaukite pranešimus, kai kas nors prideda nuotrauką į bendrinamą albumą, kuriame dalyvaujate."), - "sharedWith": m85, + "Gaukite pranešimus, kai kas nors įtraukia nuotrauką į bendrinamą albumą, kuriame dalyvaujate."), + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Bendrinta su manimi"), "sharedWithYou": @@ -1714,17 +1913,25 @@ class MessageLookup extends MessageLookupByLibrary { "showMemories": MessageLookupByLibrary.simpleMessage("Rodyti prisiminimus"), "showPerson": MessageLookupByLibrary.simpleMessage("Rodyti asmenį"), + "signOutFromOtherDevices": MessageLookupByLibrary.simpleMessage( + "Atsijungti iš kitų įrenginių"), "signOutOtherBody": MessageLookupByLibrary.simpleMessage( "Jei manote, kad kas nors gali žinoti jūsų slaptažodį, galite priverstinai atsijungti iš visų kitų įrenginių, naudojančių jūsų paskyrą."), + "signOutOtherDevices": + MessageLookupByLibrary.simpleMessage("Atsijungti kitus įrenginius"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Sutinku su paslaugų sąlygomis ir privatumo politika"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "Jis bus ištrintas iš visų albumų."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("Praleisti"), + "smartMemories": + MessageLookupByLibrary.simpleMessage("Išmanieji prisiminimai"), "social": MessageLookupByLibrary.simpleMessage("Socialinės"), + "someItemsAreInBothEnteAndYourDevice": MessageLookupByLibrary.simpleMessage( + "Kai kurie elementai yra ir platformoje „Ente“ bei jūsų įrenginyje."), "someOfTheFilesYouAreTryingToDeleteAre": MessageLookupByLibrary.simpleMessage( "Kai kurie failai, kuriuos bandote ištrinti, yra pasiekiami tik jūsų įrenginyje ir jų negalima atkurti, jei jie buvo ištrinti."), @@ -1744,11 +1951,14 @@ class MessageLookup extends MessageLookupByLibrary { "sorryCouldNotRemoveFromFavorites": MessageLookupByLibrary.simpleMessage( "Atsiprašome, nepavyko pašalinti iš mėgstamų."), + "sorryTheCodeYouveEnteredIsIncorrect": + MessageLookupByLibrary.simpleMessage( + "Atsiprašome, įvestas kodas yra neteisingas."), "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "Atsiprašome, šiame įrenginyje nepavyko sugeneruoti saugių raktų.\n\nRegistruokitės iš kito įrenginio."), "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), + "Atsiprašome, turėjome pristabdyti jūsų atsarginių kopijų kūrimą."), "sort": MessageLookupByLibrary.simpleMessage("Rikiuoti"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Rikiuoti pagal"), "sortNewestFirst": @@ -1756,6 +1966,10 @@ class MessageLookup extends MessageLookupByLibrary { "sortOldestFirst": MessageLookupByLibrary.simpleMessage("Seniausią pirmiausiai"), "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ Sėkmė"), + "sportsWithThem": m91, + "spotlightOnThem": m92, + "spotlightOnYourself": + MessageLookupByLibrary.simpleMessage("Dėmesys į save"), "startAccountRecoveryTitle": MessageLookupByLibrary.simpleMessage("Pradėti atkūrimą"), "startBackup": MessageLookupByLibrary.simpleMessage( @@ -1766,15 +1980,17 @@ class MessageLookup extends MessageLookupByLibrary { "stopCastingTitle": MessageLookupByLibrary.simpleMessage("Stabdyti perdavimą"), "storage": MessageLookupByLibrary.simpleMessage("Saugykla"), + "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Šeima"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Jūs"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage("Viršyta saugyklos riba."), + "storageUsageInfo": m94, "streamDetails": MessageLookupByLibrary.simpleMessage( "Srautinio perdavimo išsami informacija"), "strongStrength": MessageLookupByLibrary.simpleMessage("Stipri"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("Prenumeruoti"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "Kad įjungtumėte bendrinimą, reikia aktyvios mokamos prenumeratos."), @@ -1782,13 +1998,17 @@ class MessageLookup extends MessageLookupByLibrary { "success": MessageLookupByLibrary.simpleMessage("Sėkmė"), "successfullyArchived": MessageLookupByLibrary.simpleMessage("Sėkmingai suarchyvuota"), + "successfullyHid": + MessageLookupByLibrary.simpleMessage("Sėkmingai paslėptas"), "successfullyUnarchived": MessageLookupByLibrary.simpleMessage("Sėkmingai išarchyvuota"), + "successfullyUnhid": + MessageLookupByLibrary.simpleMessage("Sėkmingai atslėptas"), "suggestFeatures": MessageLookupByLibrary.simpleMessage("Siūlyti funkcijas"), "sunrise": MessageLookupByLibrary.simpleMessage("Akiratyje"), "support": MessageLookupByLibrary.simpleMessage("Pagalba"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage( "Sinchronizavimas sustabdytas"), "syncing": MessageLookupByLibrary.simpleMessage("Sinchronizuojama..."), @@ -1801,7 +2021,7 @@ class MessageLookup extends MessageLookupByLibrary { "Palieskite, kad atrakintumėte"), "tapToUpload": MessageLookupByLibrary.simpleMessage("Palieskite, kad įkeltumėte"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Atrodo, kad kažkas nutiko ne taip. Bandykite dar kartą po kurio laiko. Jei klaida tęsiasi, susisiekite su mūsų palaikymo komanda."), "terminate": MessageLookupByLibrary.simpleMessage("Baigti"), @@ -1821,7 +2041,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Įvestas atkūrimo raktas yra neteisingas."), "theme": MessageLookupByLibrary.simpleMessage("Tema"), - "theyAlsoGetXGb": m97, + "theseItemsWillBeDeletedFromYourDevice": + MessageLookupByLibrary.simpleMessage( + "Šie elementai bus ištrinti iš jūsų įrenginio."), + "theyAlsoGetXGb": m99, + "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage( + "Jie bus ištrinti iš visų albumų."), + "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( + "Šio veiksmo negalima anuliuoti."), "thisAlbumAlreadyHDACollaborativeLink": MessageLookupByLibrary.simpleMessage( "Šis albumas jau turi bendradarbiavimo nuorodą."), @@ -1834,12 +2061,12 @@ class MessageLookup extends MessageLookupByLibrary { "thisImageHasNoExifData": MessageLookupByLibrary.simpleMessage( "Šis vaizdas neturi Exif duomenų"), "thisIsMeExclamation": MessageLookupByLibrary.simpleMessage("Tai aš!"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage("Tai – jūsų patvirtinimo ID"), "thisWeekThroughTheYears": MessageLookupByLibrary.simpleMessage("Ši savaitė per metus"), - "thisWeekXYearsAgo": m99, + "thisWeekXYearsAgo": m101, "thisWillLogYouOutOfTheFollowingDevice": MessageLookupByLibrary.simpleMessage( "Tai jus atjungs nuo toliau nurodyto įrenginio:"), @@ -1851,7 +2078,7 @@ class MessageLookup extends MessageLookupByLibrary { "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( "Tai pašalins visų pasirinktų sparčiųjų nuorodų viešąsias nuorodas."), - "throughTheYears": m100, + "throughTheYears": m102, "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": MessageLookupByLibrary.simpleMessage( "Kad įjungtumėte programos užraktą, sistemos nustatymuose nustatykite įrenginio prieigos kodą arba ekrano užraktą."), @@ -1866,13 +2093,13 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("iš viso"), "totalSize": MessageLookupByLibrary.simpleMessage("Bendrą dydį"), "trash": MessageLookupByLibrary.simpleMessage("Šiukšlinė"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("Trumpinti"), - "tripInYear": m102, - "tripToLocation": m103, + "tripInYear": m104, + "tripToLocation": m105, "trustedContacts": MessageLookupByLibrary.simpleMessage("Patikimi kontaktai"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("Bandyti dar kartą"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "Įjunkite atsarginės kopijos kūrimą, kad automatiškai įkeltumėte į šį įrenginio aplanką įtrauktus failus į „Ente“."), @@ -1881,6 +2108,9 @@ class MessageLookup extends MessageLookupByLibrary { "2 mėnesiai nemokamai metiniuose planuose"), "twofactor": MessageLookupByLibrary.simpleMessage( "Dvigubas tapatybės nustatymas"), + "twofactorAuthenticationHasBeenDisabled": + MessageLookupByLibrary.simpleMessage( + "Dvigubas tapatybės nustatymas išjungtas."), "twofactorAuthenticationPageTitle": MessageLookupByLibrary.simpleMessage( "Dvigubas tapatybės nustatymas"), @@ -1889,7 +2119,7 @@ class MessageLookup extends MessageLookupByLibrary { "Dvigubas tapatybės nustatymas sėkmingai iš naujo nustatytas."), "twofactorSetup": MessageLookupByLibrary.simpleMessage( "Dvigubo tapatybės nustatymo sąranka"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("Išarchyvuoti"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("Išarchyvuoti albumą"), @@ -1902,6 +2132,7 @@ class MessageLookup extends MessageLookupByLibrary { "unhide": MessageLookupByLibrary.simpleMessage("Rodyti"), "unhideToAlbum": MessageLookupByLibrary.simpleMessage("Rodyti į albumą"), + "unhiding": MessageLookupByLibrary.simpleMessage("Rodoma..."), "unhidingFilesToAlbum": MessageLookupByLibrary.simpleMessage("Rodomi failai į albumą"), "unlock": MessageLookupByLibrary.simpleMessage("Atrakinti"), @@ -1913,10 +2144,10 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage( "Atnaujinamas aplankų pasirinkimas..."), "upgrade": MessageLookupByLibrary.simpleMessage("Keisti planą"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage("Įkeliami failai į albumą..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage("Išsaugomas prisiminimas..."), "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( @@ -1931,8 +2162,10 @@ class MessageLookup extends MessageLookupByLibrary { "Naudokite viešas nuorodas asmenimis, kurie nėra sistemoje „Ente“"), "useRecoveryKey": MessageLookupByLibrary.simpleMessage("Naudoti atkūrimo raktą"), + "useSelectedPhoto": MessageLookupByLibrary.simpleMessage( + "Naudoti pasirinktą nuotrauką"), "usedSpace": MessageLookupByLibrary.simpleMessage("Naudojama vieta"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Patvirtinimas nepavyko. Bandykite dar kartą."), @@ -1941,7 +2174,7 @@ class MessageLookup extends MessageLookupByLibrary { "verify": MessageLookupByLibrary.simpleMessage("Patvirtinti"), "verifyEmail": MessageLookupByLibrary.simpleMessage("Patvirtinti el. paštą"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Patvirtinti"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("Patvirtinti slaptaraktį"), @@ -1953,6 +2186,8 @@ class MessageLookup extends MessageLookupByLibrary { "videoInfo": MessageLookupByLibrary.simpleMessage("Vaizdo įrašo informacija"), "videoSmallCase": MessageLookupByLibrary.simpleMessage("vaizdo įrašas"), + "videoStreaming": + MessageLookupByLibrary.simpleMessage("Srautiniai vaizdo įrašai"), "videos": MessageLookupByLibrary.simpleMessage("Vaizdo įrašai"), "viewActiveSessions": MessageLookupByLibrary.simpleMessage("Peržiūrėti aktyvius seansus"), @@ -1965,9 +2200,11 @@ class MessageLookup extends MessageLookupByLibrary { "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( "Peržiūrėkite failus, kurie užima daugiausiai saugyklos vietos."), "viewLogs": MessageLookupByLibrary.simpleMessage("Peržiūrėti žurnalus"), + "viewPersonToUnlink": m112, "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("Peržiūrėti atkūrimo raktą"), "viewer": MessageLookupByLibrary.simpleMessage("Žiūrėtojas"), + "viewersSuccessfullyAdded": m113, "visitWebToManage": MessageLookupByLibrary.simpleMessage( "Aplankykite web.ente.io, kad tvarkytumėte savo prenumeratą"), "waitingForVerification": @@ -1980,27 +2217,31 @@ class MessageLookup extends MessageLookupByLibrary { "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "Nepalaikome nuotraukų ir albumų redagavimo, kurių dar neturite."), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Silpna"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Sveiki sugrįžę!"), "whatsNew": MessageLookupByLibrary.simpleMessage("Kas naujo"), "whyAddTrustContact": MessageLookupByLibrary.simpleMessage( "Patikimas kontaktas gali padėti atkurti jūsų duomenis."), + "widgets": MessageLookupByLibrary.simpleMessage("Valdikliai"), + "wishThemAHappyBirthday": m115, "yearShort": MessageLookupByLibrary.simpleMessage("m."), "yearly": MessageLookupByLibrary.simpleMessage("Metinis"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Taip"), "yesCancel": MessageLookupByLibrary.simpleMessage("Taip, atsisakyti"), "yesConvertToViewer": MessageLookupByLibrary.simpleMessage("Taip, keisti į žiūrėtoją"), "yesDelete": MessageLookupByLibrary.simpleMessage("Taip, ištrinti"), + "yesDiscardChanges": + MessageLookupByLibrary.simpleMessage("Taip, atmesti pakeitimus"), "yesLogout": MessageLookupByLibrary.simpleMessage("Taip, atsijungti"), "yesRemove": MessageLookupByLibrary.simpleMessage("Taip, šalinti"), "yesRenew": MessageLookupByLibrary.simpleMessage("Taip, pratęsti"), "yesResetPerson": MessageLookupByLibrary.simpleMessage( "Taip, nustatyti asmenį iš naujo"), "you": MessageLookupByLibrary.simpleMessage("Jūs"), - "youAndThem": m114, + "youAndThem": m117, "youAreOnAFamilyPlan": MessageLookupByLibrary.simpleMessage("Esate šeimos plane!"), "youAreOnTheLatestVersion": @@ -2019,7 +2260,7 @@ class MessageLookup extends MessageLookupByLibrary { "Negalite bendrinti su savimi."), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( "Neturite jokių archyvuotų elementų."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("Jūsų paskyra ištrinta"), "yourMap": MessageLookupByLibrary.simpleMessage("Jūsų žemėlapis"), @@ -2045,6 +2286,8 @@ class MessageLookup extends MessageLookupByLibrary { "Neturite dubliuotų failų, kuriuos būtų galima išvalyti."), "youveNoFilesInThisAlbumThatCanBeDeleted": MessageLookupByLibrary.simpleMessage( - "Neturite šiame albume failų, kuriuos būtų galima ištrinti.") + "Neturite šiame albume failų, kuriuos būtų galima ištrinti."), + "zoomOutToSeePhotos": MessageLookupByLibrary.simpleMessage( + "Padidinkite mastelį, kad matytumėte nuotraukas") }; } diff --git a/mobile/lib/generated/intl/messages_lv.dart b/mobile/lib/generated/intl/messages_lv.dart index 01cf6553da..b91248b291 100644 --- a/mobile/lib/generated/intl/messages_lv.dart +++ b/mobile/lib/generated/intl/messages_lv.dart @@ -20,17 +20,9 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'lv'; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => { - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups") - }; + static Map _notInlinedMessages(_) => + {"wishThemAHappyBirthday": m115}; } diff --git a/mobile/lib/generated/intl/messages_ml.dart b/mobile/lib/generated/intl/messages_ml.dart index bf62178aab..77bb5a5388 100644 --- a/mobile/lib/generated/intl/messages_ml.dart +++ b/mobile/lib/generated/intl/messages_ml.dart @@ -20,6 +20,8 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'ml'; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { "accountWelcomeBack": @@ -32,8 +34,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("കണക്കുകൂട്ടുന്നു..."), "cancel": MessageLookupByLibrary.simpleMessage("റദ്ദാക്കുക"), "changeEmail": MessageLookupByLibrary.simpleMessage("ഇമെയിൽ മാറ്റുക"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "close": MessageLookupByLibrary.simpleMessage("അടക്കുക"), "confirm": MessageLookupByLibrary.simpleMessage("നിജപ്പെടുത്തുക"), "confirmPassword": @@ -81,22 +81,16 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("വിവരങ്ങൾ തന്നു സഹായിക്കുക"), "lightTheme": MessageLookupByLibrary.simpleMessage("തെളിഞ"), "linkExpired": MessageLookupByLibrary.simpleMessage("കാലഹരണപ്പെട്ടു"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "mastodon": MessageLookupByLibrary.simpleMessage("മാസ്റ്റഡോൺ"), "matrix": MessageLookupByLibrary.simpleMessage("മേട്രിക്സ്"), "moderateStrength": MessageLookupByLibrary.simpleMessage("ഇടത്തരം"), "monthly": MessageLookupByLibrary.simpleMessage("പ്രതിമാസം"), "name": MessageLookupByLibrary.simpleMessage("പേര്"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "no": MessageLookupByLibrary.simpleMessage("വേണ്ട"), "noDeviceLimit": MessageLookupByLibrary.simpleMessage("ഒന്നുമില്ല"), "nothingToSeeHere": MessageLookupByLibrary.simpleMessage("ഇവിടൊന്നും കാണ്മാനില്ല! 👀"), "ok": MessageLookupByLibrary.simpleMessage("ശരി"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), "oops": MessageLookupByLibrary.simpleMessage("അയ്യോ"), "password": MessageLookupByLibrary.simpleMessage("സങ്കേതക്കുറി"), "pleaseTryAgain": @@ -126,8 +120,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "എന്തോ കുഴപ്പം സംഭവിച്ചു, ദയവായി വീണ്ടും ശ്രമിക്കുക"), "sorry": MessageLookupByLibrary.simpleMessage("ക്ഷമിക്കുക"), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("ഇപ്രകാരം അടുക്കുക"), "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ സഫലം"), @@ -146,6 +138,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("സങ്കേതക്കുറി ദൃഢീകരിക്കുക"), "weakStrength": MessageLookupByLibrary.simpleMessage("ദുർബലം"), "welcomeBack": MessageLookupByLibrary.simpleMessage("വീണ്ടും സ്വാഗതം!"), + "wishThemAHappyBirthday": m115, "yearly": MessageLookupByLibrary.simpleMessage("പ്രതിവർഷം") }; } diff --git a/mobile/lib/generated/intl/messages_nl.dart b/mobile/lib/generated/intl/messages_nl.dart index 9ec25a6a40..0772f32b0f 100644 --- a/mobile/lib/generated/intl/messages_nl.dart +++ b/mobile/lib/generated/intl/messages_nl.dart @@ -22,9 +22,18 @@ class MessageLookup extends MessageLookupByLibrary { static String m0(title) => "${title} (Ik)"; + static String m1(count) => + "${Intl.plural(count, zero: 'Samenwerker toevoegen', one: 'Samenwerker toevoegen', other: 'Samenwerkers toevoegen')}"; + + static String m2(count) => + "${Intl.plural(count, one: 'Bestand toevoegen', other: 'Bestanden toevoegen')}"; + static String m3(storageAmount, endDate) => "Jouw ${storageAmount} add-on is geldig tot ${endDate}"; + static String m4(count) => + "${Intl.plural(count, zero: 'Kijker toevoegen', one: 'Kijker toevoegen', other: 'Kijkers toevoegen')}"; + static String m5(emailOrName) => "Toegevoegd door ${emailOrName}"; static String m6(albumName) => "Succesvol toegevoegd aan ${albumName}"; @@ -75,223 +84,252 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'Verwijder ${count} bestand', other: 'Verwijder ${count} bestanden')}"; - static String m22(currentlyDeleting, totalCount) => + static String m22(count) => + "Verwijder de foto\'s (en video\'s) van deze ${count} albums ook uit alle andere albums waar deze deel van uitmaken?"; + + static String m23(currentlyDeleting, totalCount) => "Verwijderen van ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "Dit verwijdert de openbare link voor toegang tot \"${albumName}\"."; - static String m24(supportEmail) => + static String m25(supportEmail) => "Stuur een e-mail naar ${supportEmail} vanaf het door jou geregistreerde e-mailadres"; - static String m25(count, storageSaved) => + static String m26(count, storageSaved) => "Je hebt ${Intl.plural(count, one: '${count} dubbel bestand', other: '${count} dubbele bestanden')} opgeruimd, totaal (${storageSaved}!)"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} bestanden, elk ${formattedSize}"; - static String m28(newEmail) => "E-mailadres gewijzigd naar ${newEmail}"; + static String m28(name) => "Dit e-mailadres is al aan ${name} gekoppeld."; - static String m29(email) => "${email} heeft geen Ente account."; + static String m29(newEmail) => "E-mailadres gewijzigd naar ${newEmail}"; - static String m30(email) => + static String m30(email) => "${email} heeft geen Ente account."; + + static String m31(email) => "${email} heeft geen Ente account.\n\nStuur ze een uitnodiging om foto\'s te delen."; - static String m31(name) => "${name} omarmen"; + static String m32(name) => "${name} omarmen"; - static String m32(text) => "Extra foto\'s gevonden voor ${text}"; + static String m33(text) => "Extra foto\'s gevonden voor ${text}"; - static String m33(name) => "Feestmaal met ${name}"; - - static String m34(count, formattedNumber) => - "${Intl.plural(count, one: '1 bestand', other: '${formattedNumber} bestanden')} in dit album zijn veilig geback-upt"; + static String m34(name) => "Feestmaal met ${name}"; static String m35(count, formattedNumber) => + "${Intl.plural(count, one: '1 bestand', other: '${formattedNumber} bestanden')} in dit album zijn veilig geback-upt"; + + static String m36(count, formattedNumber) => "${Intl.plural(count, one: '1 bestand', other: '${formattedNumber} bestanden')} in dit album is veilig geback-upt"; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "${storageAmountInGB} GB telkens als iemand zich aanmeldt voor een betaald abonnement en je code toepast"; - static String m37(endDate) => "Gratis proefversie geldig tot ${endDate}"; + static String m38(endDate) => "Gratis proefversie geldig tot ${endDate}"; - static String m39(sizeInMBorGB) => "Maak ${sizeInMBorGB} vrij"; + static String m39(count) => + "Je hebt nog steeds toegang tot ${Intl.plural(count, one: 'het', other: 'ze')} op Ente zolang je een actief abonnement hebt"; - static String m41(currentlyProcessing, totalCount) => + static String m40(sizeInMBorGB) => "Maak ${sizeInMBorGB} vrij"; + + static String m41(count, formattedSize) => + "${Intl.plural(count, one: 'Het kan verwijderd worden van het apparaat om ${formattedSize} vrij te maken', other: 'Ze kunnen verwijderd worden van het apparaat om ${formattedSize} vrij te maken')}"; + + static String m42(currentlyProcessing, totalCount) => "Verwerken van ${currentlyProcessing} / ${totalCount}"; - static String m42(name) => "Wandelen met ${name}"; + static String m43(name) => "Wandelen met ${name}"; - static String m43(count) => + static String m44(count) => "${Intl.plural(count, one: '${count} item', other: '${count} items')}"; - static String m44(name) => "Laatste keer met ${name}"; + static String m45(name) => "Laatste keer met ${name}"; - static String m45(email) => + static String m46(email) => "${email} heeft je uitgenodigd om een vertrouwd contact te zijn"; - static String m46(expiryTime) => "Link vervalt op ${expiryTime}"; + static String m47(expiryTime) => "Link vervalt op ${expiryTime}"; - static String m47(email) => "Link persoon aan ${email}"; + static String m48(email) => "Link persoon aan ${email}"; - static String m48(personName, email) => + static String m49(personName, email) => "Dit linkt ${personName} aan ${email}"; - static String m51(albumName) => "Succesvol verplaatst naar ${albumName}"; + static String m50(count, formattedCount) => + "${Intl.plural(count, zero: 'geen herinneringen', one: '${formattedCount} herinnering', other: '${formattedCount} herinneringen')}"; - static String m52(personName) => "Geen suggesties voor ${personName}"; + static String m51(count) => + "${Intl.plural(count, one: 'Bestand verplaatsen', other: 'Bestanden verplaatsen')}"; - static String m53(name) => "Niet ${name}?"; + static String m52(albumName) => "Succesvol verplaatst naar ${albumName}"; - static String m54(familyAdminEmail) => + static String m53(personName) => "Geen suggesties voor ${personName}"; + + static String m54(name) => "Niet ${name}?"; + + static String m55(familyAdminEmail) => "Neem contact op met ${familyAdminEmail} om uw code te wijzigen."; - static String m55(name) => "Feest met ${name}"; + static String m56(name) => "Feest met ${name}"; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Wachtwoord sterkte: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "Praat met ${providerName} klantenservice als u in rekening bent gebracht"; - static String m58(name, age) => "${name} is ${age}!"; + static String m59(name, age) => "${name} is ${age}!"; - static String m59(name, age) => "${name} wordt binnenkort ${age}"; + static String m60(name, age) => "${name} wordt binnenkort ${age}"; - static String m60(count) => + static String m61(count) => "${Intl.plural(count, zero: 'Geen foto\'s', one: '1 foto', other: '${count} foto\'s')}"; - static String m62(endDate) => + static String m62(count) => + "${Intl.plural(count, zero: '0 foto\'s', one: '1 foto', other: '${count} foto\'s')}"; + + static String m63(endDate) => "Gratis proefperiode geldig tot ${endDate}.\nU kunt naderhand een betaald abonnement kiezen."; - static String m63(toEmail) => "Stuur ons een e-mail op ${toEmail}"; + static String m64(toEmail) => "Stuur ons een e-mail op ${toEmail}"; - static String m64(toEmail) => + static String m65(toEmail) => "Verstuur de logboeken alstublieft naar ${toEmail}"; - static String m65(name) => "Poseren met ${name}"; + static String m66(name) => "Poseren met ${name}"; - static String m66(folderName) => "Verwerken van ${folderName}..."; + static String m67(folderName) => "Verwerken van ${folderName}..."; - static String m67(storeName) => "Beoordeel ons op ${storeName}"; + static String m68(storeName) => "Beoordeel ons op ${storeName}"; - static String m68(name) => "Toegewezen aan ${name}"; + static String m69(name) => "Toegewezen aan ${name}"; - static String m69(days, email) => + static String m70(days, email) => "U krijgt toegang tot het account na ${days} dagen. Een melding zal worden verzonden naar ${email}."; - static String m70(email) => + static String m71(email) => "U kunt nu het account van ${email} herstellen door een nieuw wachtwoord in te stellen."; - static String m71(email) => "${email} probeert je account te herstellen."; + static String m72(email) => "${email} probeert je account te herstellen."; - static String m72(storageInGB) => + static String m73(storageInGB) => "Jullie krijgen allebei ${storageInGB} GB* gratis"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} zal worden verwijderd uit dit gedeelde album\n\nAlle door hen toegevoegde foto\'s worden ook uit het album verwijderd"; - static String m74(endDate) => "Wordt verlengd op ${endDate}"; + static String m75(endDate) => "Wordt verlengd op ${endDate}"; - static String m75(name) => "Roadtrip met ${name}"; + static String m76(name) => "Roadtrip met ${name}"; - static String m76(count) => + static String m77(count) => "${Intl.plural(count, one: '${count} resultaat gevonden', other: '${count} resultaten gevonden')}"; - static String m77(snapshotLength, searchLength) => + static String m78(snapshotLength, searchLength) => "Lengte van secties komt niet overeen: ${snapshotLength} != ${searchLength}"; - static String m78(count) => "${count} geselecteerd"; + static String m79(count) => "${count} geselecteerd"; - static String m79(count, yourCount) => + static String m80(count) => "${count} geselecteerd"; + + static String m81(count, yourCount) => "${count} geselecteerd (${yourCount} van jou)"; - static String m80(name) => "Selfies met ${name}"; + static String m82(name) => "Selfies met ${name}"; - static String m81(verificationID) => + static String m83(verificationID) => "Hier is mijn verificatie-ID: ${verificationID} voor ente.io."; - static String m82(verificationID) => + static String m84(verificationID) => "Hey, kunt u bevestigen dat dit uw ente.io verificatie-ID is: ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Ente verwijzingscode: ${referralCode} \n\nPas het toe bij Instellingen → Algemeen → Verwijzingen om ${referralStorageInGB} GB gratis te krijgen nadat je je hebt aangemeld voor een betaald abonnement\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Deel met specifieke mensen', one: 'Gedeeld met 1 persoon', other: 'Gedeeld met ${numberOfPeople} mensen')}"; - static String m85(emailIDs) => "Gedeeld met ${emailIDs}"; - - static String m86(fileType) => - "Deze ${fileType} zal worden verwijderd van jouw apparaat."; - - static String m87(fileType) => - "Deze ${fileType} staat zowel in Ente als op jouw apparaat."; + static String m87(emailIDs) => "Gedeeld met ${emailIDs}"; static String m88(fileType) => + "Deze ${fileType} zal worden verwijderd van jouw apparaat."; + + static String m89(fileType) => + "Deze ${fileType} staat zowel in Ente als op jouw apparaat."; + + static String m90(fileType) => "Deze ${fileType} zal worden verwijderd uit Ente."; - static String m89(name) => "Sporten met ${name}"; + static String m91(name) => "Sporten met ${name}"; - static String m90(name) => "Spotlicht op ${name}"; + static String m92(name) => "Spotlicht op ${name}"; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} van ${totalAmount} ${totalStorageUnit} gebruikt"; - static String m93(id) => + static String m95(id) => "Jouw ${id} is al aan een ander Ente account gekoppeld.\nAls je jouw ${id} wilt gebruiken met dit account, neem dan contact op met onze klantenservice"; - static String m94(endDate) => "Uw abonnement loopt af op ${endDate}"; + static String m96(endDate) => "Uw abonnement loopt af op ${endDate}"; - static String m95(completed, total) => + static String m97(completed, total) => "${completed}/${total} herinneringen bewaard"; - static String m96(ignoreReason) => + static String m98(ignoreReason) => "Tik om te uploaden, upload wordt momenteel genegeerd vanwege ${ignoreReason}"; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "Zij krijgen ook ${storageAmountInGB} GB"; - static String m98(email) => "Dit is de verificatie-ID van ${email}"; - - static String m99(count) => - "${Intl.plural(count, one: 'Deze week, ${count} jaar geleden', other: 'Deze week, ${count} jaren geleden')}"; - - static String m100(dateFormat) => "${dateFormat} door de jaren"; + static String m100(email) => "Dit is de verificatie-ID van ${email}"; static String m101(count) => + "${Intl.plural(count, one: 'Deze week, ${count} jaar geleden', other: 'Deze week, ${count} jaren geleden')}"; + + static String m102(dateFormat) => "${dateFormat} door de jaren"; + + static String m103(count) => "${Intl.plural(count, zero: 'Binnenkort', one: '1 dag', other: '${count} dagen')}"; - static String m102(year) => "Reis in ${year}"; + static String m104(year) => "Reis in ${year}"; - static String m103(location) => "Reis naar ${location}"; + static String m105(location) => "Reis naar ${location}"; - static String m104(email) => + static String m106(email) => "Je bent uitgenodigd om een legacy contact van ${email} te zijn."; - static String m105(galleryType) => + static String m107(galleryType) => "Galerijtype ${galleryType} wordt niet ondersteund voor hernoemen"; - static String m106(ignoreReason) => + static String m108(ignoreReason) => "Upload wordt genegeerd omdat ${ignoreReason}"; - static String m107(count) => "${count} herinneringen veiligstellen..."; + static String m109(count) => "${count} herinneringen veiligstellen..."; - static String m108(endDate) => "Geldig tot ${endDate}"; + static String m110(endDate) => "Geldig tot ${endDate}"; - static String m109(email) => "Verifieer ${email}"; + static String m111(email) => "Verifieer ${email}"; - static String m112(email) => - "We hebben een e-mail gestuurd naar ${email}"; + static String m112(name) => "Bekijk ${name} om te ontkoppelen"; static String m113(count) => - "${Intl.plural(count, one: '${count} jaar geleden', other: '${count} jaar geleden')}"; + "${Intl.plural(count, zero: '0 kijkers toegevoegd', one: '1 kijker toegevoegd', other: '${count} kijkers toegevoegd')}"; - static String m114(name) => "Jij en ${name}"; + static String m114(email) => + "We hebben een e-mail gestuurd naar ${email}"; - static String m115(storageSaved) => + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + + static String m116(count) => + "${Intl.plural(count, other: '${count} jaar geleden')}"; + + static String m117(name) => "Jij en ${name}"; + + static String m118(storageSaved) => "Je hebt ${storageSaved} succesvol vrijgemaakt!"; final messages = _notInlinedMessages(_notInlinedMessages); @@ -309,20 +347,29 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Welkom terug!"), "ackPasswordLostWarning": MessageLookupByLibrary.simpleMessage( "Ik begrijp dat als ik mijn wachtwoord verlies, ik mijn gegevens kan verliezen omdat mijn gegevens end-to-end versleuteld zijn."), + "actionNotSupportedOnFavouritesAlbum": + MessageLookupByLibrary.simpleMessage( + "Actie niet ondersteund op Favorieten album"), "activeSessions": MessageLookupByLibrary.simpleMessage("Actieve sessies"), "add": MessageLookupByLibrary.simpleMessage("Toevoegen"), "addAName": MessageLookupByLibrary.simpleMessage("Een naam toevoegen"), "addANewEmail": MessageLookupByLibrary.simpleMessage("Nieuw e-mailadres toevoegen"), + "addAlbumWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Voeg een widget toe aan je beginscherm en kom hier terug om aan te passen."), "addCollaborator": MessageLookupByLibrary.simpleMessage("Samenwerker toevoegen"), + "addCollaborators": m1, "addFiles": MessageLookupByLibrary.simpleMessage("Bestanden toevoegen"), "addFromDevice": MessageLookupByLibrary.simpleMessage("Toevoegen vanaf apparaat"), + "addItem": m2, "addLocation": MessageLookupByLibrary.simpleMessage("Locatie toevoegen"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Toevoegen"), + "addMemoriesWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Voeg een widget toe aan je beginscherm en kom hier terug om aan te passen."), "addMore": MessageLookupByLibrary.simpleMessage("Meer toevoegen"), "addName": MessageLookupByLibrary.simpleMessage("Naam toevoegen"), "addNameOrMerge": MessageLookupByLibrary.simpleMessage( @@ -334,6 +381,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Details van add-ons"), "addOnValidTill": m3, "addOns": MessageLookupByLibrary.simpleMessage("Add-ons"), + "addParticipants": + MessageLookupByLibrary.simpleMessage("Voeg deelnemers toe"), + "addPeopleWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Voeg een widget toe aan je beginscherm en kom hier terug om aan te passen."), "addPhotos": MessageLookupByLibrary.simpleMessage("Foto\'s toevoegen"), "addSelected": MessageLookupByLibrary.simpleMessage("Voeg geselecteerde toe"), @@ -345,6 +396,7 @@ class MessageLookup extends MessageLookupByLibrary { "addTrustedContact": MessageLookupByLibrary.simpleMessage("Vertrouwd contact toevoegen"), "addViewer": MessageLookupByLibrary.simpleMessage("Voeg kijker toe"), + "addViewers": m4, "addYourPhotosNow": MessageLookupByLibrary.simpleMessage("Voeg nu je foto\'s toe"), "addedAs": MessageLookupByLibrary.simpleMessage("Toegevoegd als"), @@ -366,6 +418,8 @@ class MessageLookup extends MessageLookupByLibrary { "albumUpdated": MessageLookupByLibrary.simpleMessage("Album bijgewerkt"), "albums": MessageLookupByLibrary.simpleMessage("Albums"), + "albumsWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Selecteer de albums die je wilt zien op je beginscherm."), "allClear": MessageLookupByLibrary.simpleMessage("✨ Alles in orde"), "allMemoriesPreserved": MessageLookupByLibrary.simpleMessage("Alle herinneringen bewaard"), @@ -588,7 +642,7 @@ class MessageLookup extends MessageLookupByLibrary { "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage("• Klik op het menu"), "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), + "Klik om onze beste versie tot nu toe te installeren"), "close": MessageLookupByLibrary.simpleMessage("Sluiten"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage("Samenvoegen op tijd"), @@ -689,6 +743,8 @@ class MessageLookup extends MessageLookupByLibrary { "criticalUpdateAvailable": MessageLookupByLibrary.simpleMessage( "Belangrijke update beschikbaar"), "crop": MessageLookupByLibrary.simpleMessage("Bijsnijden"), + "curatedMemories": + MessageLookupByLibrary.simpleMessage("Samengestelde herinneringen"), "currentUsageIs": MessageLookupByLibrary.simpleMessage("Huidig gebruik is "), "currentlyRunning": @@ -735,9 +791,10 @@ class MessageLookup extends MessageLookupByLibrary { "deleteItemCount": m21, "deleteLocation": MessageLookupByLibrary.simpleMessage("Verwijder locatie"), + "deleteMultipleAlbumDialog": m22, "deletePhotos": MessageLookupByLibrary.simpleMessage("Foto\'s verwijderen"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Ik mis een belangrijke functie"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -778,7 +835,7 @@ class MessageLookup extends MessageLookupByLibrary { "Kijkers kunnen nog steeds screenshots maken of een kopie van je foto\'s opslaan met behulp van externe tools"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Let op"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Tweestapsverificatie uitschakelen"), "disablingTwofactorAuthentication": @@ -821,10 +878,11 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("Download mislukt"), "downloading": MessageLookupByLibrary.simpleMessage("Downloaden..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("Bewerken"), + "editEmailAlreadyLinked": m28, "editLocation": MessageLookupByLibrary.simpleMessage("Locatie bewerken"), "editLocationTagTitle": @@ -840,16 +898,16 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("E-mail"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage("E-mail is al geregistreerd."), - "emailChangedTo": m28, - "emailDoesNotHaveEnteAccount": m29, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailDoesNotHaveEnteAccount": m30, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage("E-mail niet geregistreerd."), "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("E-mailverificatie"), "emailYourLogs": MessageLookupByLibrary.simpleMessage("E-mail uw logboeken"), - "embracingThem": m31, + "embracingThem": m32, "emergencyContacts": MessageLookupByLibrary.simpleMessage("Noodcontacten"), "empty": MessageLookupByLibrary.simpleMessage("Leeg"), @@ -913,6 +971,8 @@ class MessageLookup extends MessageLookupByLibrary { "Voer een geldig e-mailadres in."), "enterYourEmailAddress": MessageLookupByLibrary.simpleMessage("Voer je e-mailadres in"), + "enterYourNewEmailAddress": MessageLookupByLibrary.simpleMessage( + "Voer uw nieuwe e-mailadres in"), "enterYourPassword": MessageLookupByLibrary.simpleMessage("Voer je wachtwoord in"), "enterYourRecoveryKey": @@ -930,7 +990,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Exporteer je gegevens"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage("Extra foto\'s gevonden"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage( "Gezicht nog niet geclusterd, kom later terug"), "faceRecognition": @@ -970,7 +1030,7 @@ class MessageLookup extends MessageLookupByLibrary { "faqs": MessageLookupByLibrary.simpleMessage("Veelgestelde vragen"), "favorite": MessageLookupByLibrary.simpleMessage("Toevoegen aan favorieten"), - "feastingWithThem": m33, + "feastingWithThem": m34, "feedback": MessageLookupByLibrary.simpleMessage("Feedback"), "file": MessageLookupByLibrary.simpleMessage("Bestand"), "fileFailedToSaveToGallery": MessageLookupByLibrary.simpleMessage( @@ -984,8 +1044,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Bestandstype"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Bestandstypen en namen"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("Bestanden verwijderd"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage( @@ -1003,24 +1063,26 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Gezichten gevonden"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("Gratis opslag geclaimd"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("Gratis opslag bruikbaar"), "freeTrial": MessageLookupByLibrary.simpleMessage("Gratis proefversie"), - "freeTrialValidTill": m37, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAccessPostDelete": m39, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("Apparaatruimte vrijmaken"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Bespaar ruimte op je apparaat door bestanden die al geback-upt zijn te wissen."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Ruimte vrijmaken"), + "freeUpSpaceSaving": m41, "gallery": MessageLookupByLibrary.simpleMessage("Galerij"), "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Tot 1000 herinneringen getoond in de galerij"), "general": MessageLookupByLibrary.simpleMessage("Algemeen"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Encryptiesleutels genereren..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("Ga naar instellingen"), "googlePlayId": MessageLookupByLibrary.simpleMessage("Google Play ID"), @@ -1049,7 +1111,7 @@ class MessageLookup extends MessageLookupByLibrary { "hideSharedItemsFromHomeGallery": MessageLookupByLibrary.simpleMessage( "Verberg gedeelde bestanden uit de galerij"), "hiding": MessageLookupByLibrary.simpleMessage("Verbergen..."), - "hikingWithThem": m42, + "hikingWithThem": m43, "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("Gehost bij OSM France"), "howItWorks": MessageLookupByLibrary.simpleMessage("Hoe het werkt"), @@ -1106,7 +1168,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Het lijkt erop dat er iets fout is gegaan. Probeer het later opnieuw. Als de fout zich blijft voordoen, neem dan contact op met ons supportteam."), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Bestanden tonen het aantal resterende dagen voordat ze permanent worden verwijderd"), @@ -1127,7 +1189,7 @@ class MessageLookup extends MessageLookupByLibrary { "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( "Help ons alsjeblieft met deze informatie"), "language": MessageLookupByLibrary.simpleMessage("Taal"), - "lastTimeWithThem": m44, + "lastTimeWithThem": m45, "lastUpdated": MessageLookupByLibrary.simpleMessage("Laatst gewijzigd"), "lastYearsTrip": MessageLookupByLibrary.simpleMessage("Reis van vorig jaar"), @@ -1141,7 +1203,7 @@ class MessageLookup extends MessageLookupByLibrary { "legacy": MessageLookupByLibrary.simpleMessage("Legacy"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("Legacy accounts"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage( "Legacy geeft vertrouwde contacten toegang tot je account bij afwezigheid."), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( @@ -1158,7 +1220,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("voor sneller delen"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Ingeschakeld"), "linkExpired": MessageLookupByLibrary.simpleMessage("Verlopen"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Vervaldatum"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("Link is vervallen"), @@ -1166,11 +1228,13 @@ class MessageLookup extends MessageLookupByLibrary { "linkPerson": MessageLookupByLibrary.simpleMessage("Link persoon"), "linkPersonCaption": MessageLookupByLibrary.simpleMessage( "voor een betere ervaring met delen"), - "linkPersonToEmail": m47, - "linkPersonToEmailConfirmation": m48, + "linkPersonToEmail": m48, + "linkPersonToEmailConfirmation": m49, "livePhotos": MessageLookupByLibrary.simpleMessage("Live foto"), "loadMessage1": MessageLookupByLibrary.simpleMessage( "U kunt uw abonnement met uw familie delen"), + "loadMessage2": MessageLookupByLibrary.simpleMessage( + "We hebben tot nu toe meer dan 200 miljoen herinneringen bewaard"), "loadMessage3": MessageLookupByLibrary.simpleMessage( "We bewaren 3 kopieën van uw bestanden, één in een ondergrondse kernbunker"), "loadMessage4": MessageLookupByLibrary.simpleMessage( @@ -1226,7 +1290,7 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Houd een bestand lang ingedrukt om te bekijken op volledig scherm"), "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), + "Kijk terug op je herinneringen 🌄"), "loopVideoOff": MessageLookupByLibrary.simpleMessage("Video in lus afspelen uit"), "loopVideoOn": @@ -1257,6 +1321,10 @@ class MessageLookup extends MessageLookupByLibrary { "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), "me": MessageLookupByLibrary.simpleMessage("Ik"), + "memories": MessageLookupByLibrary.simpleMessage("Herinneringen"), + "memoriesWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Selecteer het soort herinneringen dat je wilt zien op je beginscherm."), + "memoryCount": m50, "merchandise": MessageLookupByLibrary.simpleMessage("Merchandise"), "mergeWithExisting": MessageLookupByLibrary.simpleMessage("Samenvoegen met bestaand"), @@ -1288,13 +1356,14 @@ class MessageLookup extends MessageLookupByLibrary { "mostRecent": MessageLookupByLibrary.simpleMessage("Meest recent"), "mostRelevant": MessageLookupByLibrary.simpleMessage("Meest relevant"), "mountains": MessageLookupByLibrary.simpleMessage("Over de heuvels"), + "moveItem": m51, "moveSelectedPhotosToOneDate": MessageLookupByLibrary.simpleMessage( "Verplaats de geselecteerde foto\'s naar één datum"), "moveToAlbum": MessageLookupByLibrary.simpleMessage("Verplaats naar album"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage( "Verplaatsen naar verborgen album"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("Naar prullenbak verplaatst"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1309,7 +1378,7 @@ class MessageLookup extends MessageLookupByLibrary { "newAlbum": MessageLookupByLibrary.simpleMessage("Nieuw album"), "newLocation": MessageLookupByLibrary.simpleMessage("Nieuwe locatie"), "newPerson": MessageLookupByLibrary.simpleMessage("Nieuw persoon"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), + "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" nieuwe 📸"), "newRange": MessageLookupByLibrary.simpleMessage("Nieuwe reeks"), "newToEnte": MessageLookupByLibrary.simpleMessage("Nieuw bij Ente"), "newest": MessageLookupByLibrary.simpleMessage("Nieuwste"), @@ -1350,10 +1419,10 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Geen resultaten"), "noResultsFound": MessageLookupByLibrary.simpleMessage("Geen resultaten gevonden"), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage( "Geen systeemvergrendeling gevonden"), - "notPersonLabel": m53, + "notPersonLabel": m54, "notThisPerson": MessageLookupByLibrary.simpleMessage("Niet dezelfde persoon?"), "nothingSharedWithYouYet": @@ -1366,10 +1435,12 @@ class MessageLookup extends MessageLookupByLibrary { "onEnte": MessageLookupByLibrary.simpleMessage( "Op ente"), "onTheRoad": MessageLookupByLibrary.simpleMessage("Onderweg"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), + "onThisDay": MessageLookupByLibrary.simpleMessage("Op deze dag"), + "onThisDayMemories": + MessageLookupByLibrary.simpleMessage("Op deze dag herinneringen"), "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "Ontvang meldingen over herinneringen op deze dag door de jaren heen."), + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("Alleen hen"), "oops": MessageLookupByLibrary.simpleMessage("Oeps"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( @@ -1399,7 +1470,7 @@ class MessageLookup extends MessageLookupByLibrary { "pairingComplete": MessageLookupByLibrary.simpleMessage("Koppeling voltooid"), "panorama": MessageLookupByLibrary.simpleMessage("Panorama"), - "partyWithThem": m55, + "partyWithThem": m56, "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage( "Verificatie is nog in behandeling"), "passkey": MessageLookupByLibrary.simpleMessage("Passkey"), @@ -1409,18 +1480,20 @@ class MessageLookup extends MessageLookupByLibrary { "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage( "Wachtwoord succesvol aangepast"), "passwordLock": MessageLookupByLibrary.simpleMessage("Wachtwoord slot"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "De wachtwoordsterkte wordt berekend aan de hand van de lengte van het wachtwoord, de gebruikte tekens en of het wachtwoord al dan niet in de top 10.000 van meest gebruikte wachtwoorden staat"), "passwordWarning": MessageLookupByLibrary.simpleMessage( "Wij slaan dit wachtwoord niet op, dus als je het vergeet, kunnen we je gegevens niet ontsleutelen"), + "pastYearsMemories": + MessageLookupByLibrary.simpleMessage("Afgelopen jaren"), "paymentDetails": MessageLookupByLibrary.simpleMessage("Betaalgegevens"), "paymentFailed": MessageLookupByLibrary.simpleMessage("Betaling mislukt"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Helaas is je betaling mislukt. Neem contact op met support zodat we je kunnen helpen!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("Bestanden in behandeling"), "pendingSync": MessageLookupByLibrary.simpleMessage( @@ -1428,26 +1501,29 @@ class MessageLookup extends MessageLookupByLibrary { "people": MessageLookupByLibrary.simpleMessage("Personen"), "peopleUsingYourCode": MessageLookupByLibrary.simpleMessage( "Mensen die jouw code gebruiken"), + "peopleWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Selecteer de mensen die je wilt zien op je beginscherm."), "permDeleteWarning": MessageLookupByLibrary.simpleMessage( "Alle bestanden in de prullenbak zullen permanent worden verwijderd\n\nDeze actie kan niet ongedaan worden gemaakt"), "permanentlyDelete": MessageLookupByLibrary.simpleMessage("Permanent verwijderen"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage( "Permanent verwijderen van apparaat?"), - "personIsAge": m58, + "personIsAge": m59, "personName": MessageLookupByLibrary.simpleMessage("Naam van persoon"), - "personTurningAge": m59, + "personTurningAge": m60, "pets": MessageLookupByLibrary.simpleMessage("Harige kameraden"), "photoDescriptions": MessageLookupByLibrary.simpleMessage("Foto beschrijvingen"), "photoGridSize": MessageLookupByLibrary.simpleMessage("Foto raster grootte"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("foto"), - "photocountPhotos": m60, + "photocountPhotos": m61, "photos": MessageLookupByLibrary.simpleMessage("Foto\'s"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage( "Foto\'s toegevoegd door u zullen worden verwijderd uit het album"), + "photosCount": m62, "photosKeepRelativeTimeDifference": MessageLookupByLibrary.simpleMessage( "Foto\'s behouden relatief tijdsverschil"), @@ -1460,7 +1536,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Album afspelen op TV"), "playOriginal": MessageLookupByLibrary.simpleMessage("Origineel afspelen"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playStream": MessageLookupByLibrary.simpleMessage("Stream afspelen"), "playstoreSubscription": MessageLookupByLibrary.simpleMessage("PlayStore abonnement"), @@ -1473,14 +1549,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Neem contact op met klantenservice als het probleem aanhoudt"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage( "Geef alstublieft toestemming"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Log opnieuw in"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Selecteer snelle links om te verwijderen"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Probeer het nog eens"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1495,7 +1571,7 @@ class MessageLookup extends MessageLookupByLibrary { "Gelieve even te wachten voordat u opnieuw probeert"), "pleaseWaitThisWillTakeAWhile": MessageLookupByLibrary.simpleMessage( "Een ogenblik geduld, dit zal even duren."), - "posingWithThem": m65, + "posingWithThem": m66, "preparingLogs": MessageLookupByLibrary.simpleMessage("Logboeken voorbereiden..."), "preserveMore": MessageLookupByLibrary.simpleMessage("Meer bewaren"), @@ -1513,7 +1589,7 @@ class MessageLookup extends MessageLookupByLibrary { "proceed": MessageLookupByLibrary.simpleMessage("Verder"), "processed": MessageLookupByLibrary.simpleMessage("Verwerkt"), "processing": MessageLookupByLibrary.simpleMessage("Verwerken"), - "processingImport": m66, + "processingImport": m67, "processingVideos": MessageLookupByLibrary.simpleMessage("Video\'s verwerken"), "publicLinkCreated": @@ -1526,10 +1602,10 @@ class MessageLookup extends MessageLookupByLibrary { "raiseTicket": MessageLookupByLibrary.simpleMessage("Meld probleem"), "rateTheApp": MessageLookupByLibrary.simpleMessage("Beoordeel de app"), "rateUs": MessageLookupByLibrary.simpleMessage("Beoordeel ons"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "reassignMe": MessageLookupByLibrary.simpleMessage("\"Ik\" opnieuw toewijzen"), - "reassignedToName": m68, + "reassignedToName": m69, "reassigningLoading": MessageLookupByLibrary.simpleMessage("Opnieuw toewijzen..."), "recover": MessageLookupByLibrary.simpleMessage("Herstellen"), @@ -1540,7 +1616,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Account herstellen"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage("Herstel gestart"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("Herstelsleutel"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( "Herstelsleutel gekopieerd naar klembord"), @@ -1554,12 +1630,12 @@ class MessageLookup extends MessageLookupByLibrary { "Herstel sleutel geverifieerd"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "Je herstelsleutel is de enige manier om je foto\'s te herstellen als je je wachtwoord bent vergeten. Je vindt je herstelsleutel in Instellingen > Account.\n\nVoer hier je herstelsleutel in om te controleren of je hem correct hebt opgeslagen."), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage("Herstel succesvol!"), "recoveryWarning": MessageLookupByLibrary.simpleMessage( "Een vertrouwd contact probeert toegang te krijgen tot je account"), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "Het huidige apparaat is niet krachtig genoeg om je wachtwoord te verifiëren, dus moeten we de code een keer opnieuw genereren op een manier die met alle apparaten werkt.\n\nLog in met behulp van uw herstelcode en genereer opnieuw uw wachtwoord (je kunt dezelfde indien gewenst opnieuw gebruiken)."), "recreatePasswordTitle": MessageLookupByLibrary.simpleMessage( @@ -1575,7 +1651,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Geef deze code aan je vrienden"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Ze registreren voor een betaald plan"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("Referenties"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Verwijzingen zijn momenteel gepauzeerd"), @@ -1607,7 +1683,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Verwijder link"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Deelnemer verwijderen"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Verwijder persoonslabel"), "removePublicLink": @@ -1629,7 +1705,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Bestandsnaam wijzigen"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Abonnement verlengen"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Een fout melden"), "reportBug": MessageLookupByLibrary.simpleMessage("Fout melden"), "resendEmail": @@ -1655,7 +1731,7 @@ class MessageLookup extends MessageLookupByLibrary { "reviewSuggestions": MessageLookupByLibrary.simpleMessage("Suggesties beoordelen"), "right": MessageLookupByLibrary.simpleMessage("Rechts"), - "roadtripWithThem": m75, + "roadtripWithThem": m76, "rotate": MessageLookupByLibrary.simpleMessage("Roteren"), "rotateLeft": MessageLookupByLibrary.simpleMessage("Roteer links"), "rotateRight": MessageLookupByLibrary.simpleMessage("Rechtsom draaien"), @@ -1711,8 +1787,8 @@ class MessageLookup extends MessageLookupByLibrary { "Nodig mensen uit, en je ziet alle foto\'s die door hen worden gedeeld hier"), "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage( "Personen worden hier getoond zodra verwerking en synchroniseren voltooid is"), - "searchResultCount": m76, - "searchSectionsLengthMismatch": m77, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("Beveiliging"), "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage( "Bekijk publieke album links in de app"), @@ -1750,6 +1826,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Selecteer je gezicht"), "selectYourPlan": MessageLookupByLibrary.simpleMessage("Kies uw abonnement"), + "selectedAlbums": m79, "selectedFilesAreNotOnEnte": MessageLookupByLibrary.simpleMessage( "Geselecteerde bestanden staan niet op Ente"), "selectedFoldersWillBeEncryptedAndBackedUp": @@ -1761,9 +1838,9 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeRemovedFromThisPerson": MessageLookupByLibrary.simpleMessage( "Geselecteerde bestanden worden van deze persoon verwijderd, maar niet uit uw bibliotheek verwijderd."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, - "selfiesWithThem": m80, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, + "selfiesWithThem": m82, "send": MessageLookupByLibrary.simpleMessage("Verzenden"), "sendEmail": MessageLookupByLibrary.simpleMessage("E-mail versturen"), "sendInvite": @@ -1795,16 +1872,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Deel nu een album"), "shareLink": MessageLookupByLibrary.simpleMessage("Link delen"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Deel alleen met de mensen die u wilt"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Download Ente zodat we gemakkelijk foto\'s en video\'s in originele kwaliteit kunnen delen\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Delen met niet-Ente gebruikers"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage("Deel jouw eerste album"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1815,7 +1892,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Nieuwe gedeelde foto\'s"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "Ontvang meldingen wanneer iemand een foto toevoegt aan een gedeeld album waar je deel van uitmaakt"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Gedeeld met mij"), "sharedWithYou": MessageLookupByLibrary.simpleMessage("Gedeeld met jou"), @@ -1833,12 +1910,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Log uit op andere apparaten"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Ik ga akkoord met de gebruiksvoorwaarden en privacybeleid"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "Het wordt uit alle albums verwijderd."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("Overslaan"), + "smartMemories": + MessageLookupByLibrary.simpleMessage("Slimme herinneringen"), "social": MessageLookupByLibrary.simpleMessage("Sociale media"), "someItemsAreInBothEnteAndYourDevice": MessageLookupByLibrary.simpleMessage( "Sommige bestanden bevinden zich zowel in Ente als op jouw apparaat."), @@ -1854,6 +1933,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Er is iets fout gegaan, probeer het opnieuw"), "sorry": MessageLookupByLibrary.simpleMessage("Sorry"), + "sorryBackupFailedDesc": MessageLookupByLibrary.simpleMessage( + "Sorry, we kunnen dit bestand nu niet back-uppen, we zullen het later opnieuw proberen."), "sorryCouldNotAddToFavorites": MessageLookupByLibrary.simpleMessage( "Sorry, kon niet aan favorieten worden toegevoegd!"), "sorryCouldNotRemoveFromFavorites": @@ -1866,15 +1947,15 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Sorry, we konden geen beveiligde sleutels genereren op dit apparaat.\n\nGelieve je aan te melden vanaf een ander apparaat."), "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), + "Sorry, we moesten je back-ups pauzeren"), "sort": MessageLookupByLibrary.simpleMessage("Sorteren"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Sorteren op"), "sortNewestFirst": MessageLookupByLibrary.simpleMessage("Nieuwste eerst"), "sortOldestFirst": MessageLookupByLibrary.simpleMessage("Oudste eerst"), "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ Succes"), - "sportsWithThem": m89, - "spotlightOnThem": m90, + "sportsWithThem": m91, + "spotlightOnThem": m92, "spotlightOnYourself": MessageLookupByLibrary.simpleMessage("Spotlicht op jezelf"), "startAccountRecoveryTitle": @@ -1888,14 +1969,14 @@ class MessageLookup extends MessageLookupByLibrary { "storage": MessageLookupByLibrary.simpleMessage("Opslagruimte"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Familie"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Jij"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage("Opslaglimiet overschreden"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "streamDetails": MessageLookupByLibrary.simpleMessage("Stream details"), "strongStrength": MessageLookupByLibrary.simpleMessage("Sterk"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("Abonneer"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "Je hebt een actief betaald abonnement nodig om delen mogelijk te maken."), @@ -1913,7 +1994,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Features voorstellen"), "sunrise": MessageLookupByLibrary.simpleMessage("Aan de horizon"), "support": MessageLookupByLibrary.simpleMessage("Ondersteuning"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("Synchronisatie gestopt"), "syncing": MessageLookupByLibrary.simpleMessage("Synchroniseren..."), @@ -1925,7 +2006,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Tik om te ontgrendelen"), "tapToUpload": MessageLookupByLibrary.simpleMessage("Tik om te uploaden"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Het lijkt erop dat er iets fout is gegaan. Probeer het later opnieuw. Als de fout zich blijft voordoen, neem dan contact op met ons supportteam."), "terminate": MessageLookupByLibrary.simpleMessage("Beëindigen"), @@ -1949,7 +2030,7 @@ class MessageLookup extends MessageLookupByLibrary { "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage( "Deze bestanden zullen worden verwijderd van uw apparaat."), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage( "Ze zullen uit alle albums worden verwijderd."), "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( @@ -1967,12 +2048,12 @@ class MessageLookup extends MessageLookupByLibrary { "Deze foto heeft geen exif gegevens"), "thisIsMeExclamation": MessageLookupByLibrary.simpleMessage("Dit ben ik!"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage("Dit is uw verificatie-ID"), "thisWeekThroughTheYears": MessageLookupByLibrary.simpleMessage("Deze week door de jaren"), - "thisWeekXYearsAgo": m99, + "thisWeekXYearsAgo": m101, "thisWillLogYouOutOfTheFollowingDevice": MessageLookupByLibrary.simpleMessage( "Dit zal je uitloggen van het volgende apparaat:"), @@ -1984,7 +2065,7 @@ class MessageLookup extends MessageLookupByLibrary { "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( "Hiermee worden openbare links van alle geselecteerde snelle links verwijderd."), - "throughTheYears": m100, + "throughTheYears": m102, "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": MessageLookupByLibrary.simpleMessage( "Om appvergrendeling in te schakelen, moet u een toegangscode of schermvergrendeling instellen in uw systeeminstellingen."), @@ -1999,13 +2080,13 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("totaal"), "totalSize": MessageLookupByLibrary.simpleMessage("Totale grootte"), "trash": MessageLookupByLibrary.simpleMessage("Prullenbak"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("Knippen"), - "tripInYear": m102, - "tripToLocation": m103, + "tripInYear": m104, + "tripToLocation": m105, "trustedContacts": MessageLookupByLibrary.simpleMessage("Vertrouwde contacten"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("Probeer opnieuw"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "Schakel back-up in om bestanden die toegevoegd zijn aan deze map op dit apparaat automatisch te uploaden."), @@ -2024,7 +2105,7 @@ class MessageLookup extends MessageLookupByLibrary { "Tweestapsverificatie succesvol gereset"), "twofactorSetup": MessageLookupByLibrary.simpleMessage("Tweestapsverificatie"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("Uit archief halen"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("Album uit archief halen"), @@ -2050,10 +2131,10 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage("Map selectie bijwerken..."), "upgrade": MessageLookupByLibrary.simpleMessage("Upgraden"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Bestanden worden geüpload naar album..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage( "1 herinnering veiligstellen..."), "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( @@ -2071,7 +2152,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("Gebruik geselecteerde foto"), "usedSpace": MessageLookupByLibrary.simpleMessage("Gebruikte ruimte"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Verificatie mislukt, probeer het opnieuw"), @@ -2079,7 +2160,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Verificatie ID"), "verify": MessageLookupByLibrary.simpleMessage("Verifiëren"), "verifyEmail": MessageLookupByLibrary.simpleMessage("Bevestig e-mail"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Verifiëren"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("Bevestig passkey"), @@ -2090,6 +2171,8 @@ class MessageLookup extends MessageLookupByLibrary { "Herstelsleutel verifiëren..."), "videoInfo": MessageLookupByLibrary.simpleMessage("Video-info"), "videoSmallCase": MessageLookupByLibrary.simpleMessage("video"), + "videoStreaming": + MessageLookupByLibrary.simpleMessage("Video\'s met stream"), "videos": MessageLookupByLibrary.simpleMessage("Video\'s"), "viewActiveSessions": MessageLookupByLibrary.simpleMessage("Actieve sessies bekijken"), @@ -2103,9 +2186,11 @@ class MessageLookup extends MessageLookupByLibrary { "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( "Bekijk bestanden die de meeste opslagruimte verbruiken."), "viewLogs": MessageLookupByLibrary.simpleMessage("Logboeken bekijken"), + "viewPersonToUnlink": m112, "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("Toon herstelsleutel"), "viewer": MessageLookupByLibrary.simpleMessage("Kijker"), + "viewersSuccessfullyAdded": m113, "visitWebToManage": MessageLookupByLibrary.simpleMessage( "Bezoek alstublieft web.ente.io om uw abonnement te beheren"), "waitingForVerification": @@ -2118,15 +2203,17 @@ class MessageLookup extends MessageLookupByLibrary { "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "We ondersteunen het bewerken van foto\'s en albums waar je niet de eigenaar van bent nog niet"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Zwak"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Welkom terug!"), "whatsNew": MessageLookupByLibrary.simpleMessage("Nieuw"), "whyAddTrustContact": MessageLookupByLibrary.simpleMessage( "Vertrouwde contacten kunnen helpen bij het herstellen van je data."), + "widgets": MessageLookupByLibrary.simpleMessage("Widgets"), + "wishThemAHappyBirthday": m115, "yearShort": MessageLookupByLibrary.simpleMessage("jr"), "yearly": MessageLookupByLibrary.simpleMessage("Jaarlijks"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Ja"), "yesCancel": MessageLookupByLibrary.simpleMessage("Ja, opzeggen"), "yesConvertToViewer": @@ -2140,7 +2227,7 @@ class MessageLookup extends MessageLookupByLibrary { "yesResetPerson": MessageLookupByLibrary.simpleMessage("Ja, reset persoon"), "you": MessageLookupByLibrary.simpleMessage("Jij"), - "youAndThem": m114, + "youAndThem": m117, "youAreOnAFamilyPlan": MessageLookupByLibrary.simpleMessage( "U bent onderdeel van een familie abonnement!"), "youAreOnTheLatestVersion": @@ -2159,7 +2246,7 @@ class MessageLookup extends MessageLookupByLibrary { "Je kunt niet met jezelf delen"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( "U heeft geen gearchiveerde bestanden."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("Je account is verwijderd"), "yourMap": MessageLookupByLibrary.simpleMessage("Jouw kaart"), diff --git a/mobile/lib/generated/intl/messages_no.dart b/mobile/lib/generated/intl/messages_no.dart index c112a86ef0..b450399e28 100644 --- a/mobile/lib/generated/intl/messages_no.dart +++ b/mobile/lib/generated/intl/messages_no.dart @@ -78,226 +78,226 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'Slett ${count} element', other: 'Slett ${count} elementer')}"; - static String m22(currentlyDeleting, totalCount) => + static String m23(currentlyDeleting, totalCount) => "Sletter ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "Dette fjerner den offentlige lenken for tilgang til \"${albumName}\"."; - static String m24(supportEmail) => + static String m25(supportEmail) => "Vennligst send en e-post til ${supportEmail} fra din registrerte e-postadresse"; - static String m25(count, storageSaved) => + static String m26(count, storageSaved) => "Du har ryddet bort ${Intl.plural(count, one: '${count} duplikatfil', other: '${count} duplikatfiler')}, som frigjør (${storageSaved}!)"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} filer, ${formattedSize} hver"; - static String m28(newEmail) => "E-postadressen er endret til ${newEmail}"; + static String m29(newEmail) => "E-postadressen er endret til ${newEmail}"; - static String m29(email) => "${email} har ikke en Ente-konto."; + static String m30(email) => "${email} har ikke en Ente-konto."; - static String m30(email) => + static String m31(email) => "${email} har ikke en Ente-konto.\n\nsender dem en invitasjon til å dele bilder."; - static String m31(name) => "Omfavner ${name}"; + static String m32(name) => "Omfavner ${name}"; - static String m32(text) => "Ekstra bilder funnet for ${text}"; + static String m33(text) => "Ekstra bilder funnet for ${text}"; - static String m33(name) => "Festing med ${name}"; - - static String m34(count, formattedNumber) => - "${Intl.plural(count, one: '1 fil', other: '${formattedNumber} filer')} på denne enheten har blitt sikkerhetskopiert"; + static String m34(name) => "Festing med ${name}"; static String m35(count, formattedNumber) => + "${Intl.plural(count, one: '1 fil', other: '${formattedNumber} filer')} på denne enheten har blitt sikkerhetskopiert"; + + static String m36(count, formattedNumber) => "${Intl.plural(count, one: '1 fil', other: '${formattedNumber} filer')} I dette albumet har blitt sikkerhetskopiert"; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "${storageAmountInGB} GB hver gang noen melder seg på en betalt plan og bruker koden din"; - static String m37(endDate) => "Prøveperioden varer til ${endDate}"; + static String m38(endDate) => "Prøveperioden varer til ${endDate}"; - static String m39(sizeInMBorGB) => "Frigjør ${sizeInMBorGB}"; + static String m40(sizeInMBorGB) => "Frigjør ${sizeInMBorGB}"; - static String m41(currentlyProcessing, totalCount) => + static String m42(currentlyProcessing, totalCount) => "Behandler ${currentlyProcessing} / ${totalCount}"; - static String m42(name) => "Tur med ${name}"; + static String m43(name) => "Tur med ${name}"; - static String m43(count) => + static String m44(count) => "${Intl.plural(count, one: '${count} element', other: '${count} elementer')}"; - static String m44(name) => "Siste gang med ${name}"; + static String m45(name) => "Siste gang med ${name}"; - static String m45(email) => + static String m46(email) => "${email} har invitert deg til å være en betrodd kontakt"; - static String m46(expiryTime) => "Lenken utløper på ${expiryTime}"; + static String m47(expiryTime) => "Lenken utløper på ${expiryTime}"; - static String m47(email) => "Knytt personen til ${email}"; + static String m48(email) => "Knytt personen til ${email}"; - static String m48(personName, email) => + static String m49(personName, email) => "Dette knytter ${personName} til ${email}"; - static String m49(count, formattedCount) => + static String m50(count, formattedCount) => "${Intl.plural(count, zero: 'ingen minner', one: '${formattedCount} minne', other: '${formattedCount} minner')}"; - static String m50(count) => + static String m51(count) => "${Intl.plural(count, one: 'Flytt elementet', other: 'Flytt elementene')}"; - static String m51(albumName) => "Flyttet til ${albumName}"; + static String m52(albumName) => "Flyttet til ${albumName}"; - static String m52(personName) => "Ingen forslag for ${personName}"; + static String m53(personName) => "Ingen forslag for ${personName}"; - static String m53(name) => "Ikke ${name}?"; + static String m54(name) => "Ikke ${name}?"; - static String m54(familyAdminEmail) => + static String m55(familyAdminEmail) => "Vennligst kontakt ${familyAdminEmail} for å endre koden din."; - static String m55(name) => "Fest med ${name}"; + static String m56(name) => "Fest med ${name}"; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Passordstyrke: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "Snakk med ${providerName} kundestøtte hvis du ble belastet"; - static String m58(name, age) => "${name} er ${age}!"; + static String m59(name, age) => "${name} er ${age}!"; - static String m59(name, age) => "${name} fyller ${age} snart"; + static String m60(name, age) => "${name} fyller ${age} snart"; - static String m60(count) => + static String m61(count) => "${Intl.plural(count, zero: 'Ingen bilder', one: '1 bilde', other: '${count} bilder')}"; - static String m62(endDate) => + static String m63(endDate) => "Prøveperioden varer til ${endDate}.\nDu kan velge en betalt plan etterpå."; - static String m63(toEmail) => "Vennligst send oss en e-post på ${toEmail}"; + static String m64(toEmail) => "Vennligst send oss en e-post på ${toEmail}"; - static String m64(toEmail) => "Vennligst send loggene til \n${toEmail}"; + static String m65(toEmail) => "Vennligst send loggene til \n${toEmail}"; - static String m65(name) => "Poseringer med ${name}"; + static String m66(name) => "Poseringer med ${name}"; - static String m66(folderName) => "Behandler ${folderName}..."; + static String m67(folderName) => "Behandler ${folderName}..."; - static String m67(storeName) => "Vurder oss på ${storeName}"; + static String m68(storeName) => "Vurder oss på ${storeName}"; - static String m68(name) => + static String m69(name) => "Tildeler deg til ${name}${name}${name}${name}${name}"; - static String m69(days, email) => + static String m70(days, email) => "Du kan få tilgang til kontoen etter ${days} dager. En varsling vil bli sendt til ${email}."; - static String m70(email) => + static String m71(email) => "Du kan nå gjenopprette ${email} sin konto ved å sette et nytt passord."; - static String m71(email) => "${email} prøver å gjenopprette kontoen din."; + static String m72(email) => "${email} prøver å gjenopprette kontoen din."; - static String m72(storageInGB) => + static String m73(storageInGB) => "3. Begge dere får ${storageInGB} GB* gratis"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} vil bli fjernet fra dette delte albumet\n\nAlle bilder lagt til av dem vil også bli fjernet fra albumet"; - static String m74(endDate) => "Abonnement fornyes på ${endDate}"; + static String m75(endDate) => "Abonnement fornyes på ${endDate}"; - static String m75(name) => "Biltur med ${name}"; + static String m76(name) => "Biltur med ${name}"; - static String m76(count) => + static String m77(count) => "${Intl.plural(count, one: '${count} resultat funnet', other: '${count} resultater funnet')}"; - static String m77(snapshotLength, searchLength) => + static String m78(snapshotLength, searchLength) => "Uoverensstemmelse i seksjonslengde: ${snapshotLength} != ${searchLength}"; - static String m78(count) => "${count} valgt"; + static String m80(count) => "${count} valgt"; - static String m79(count, yourCount) => "${count} valgt (${yourCount} dine)"; + static String m81(count, yourCount) => "${count} valgt (${yourCount} dine)"; - static String m80(name) => "Selfier med ${name}"; + static String m82(name) => "Selfier med ${name}"; - static String m81(verificationID) => + static String m83(verificationID) => "Her er min verifiserings-ID: ${verificationID} for ente.io."; - static String m82(verificationID) => + static String m84(verificationID) => "Hei, kan du bekrefte at dette er din ente.io verifiserings-ID: ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Gi vervekode: ${referralCode} \n\nBruk den i Innstillinger → General → Verving for å få ${referralStorageInGB} GB gratis etter at du har registrert deg for en betalt plan\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Del med bestemte personer', one: 'Delt med 1 person', other: 'Delt med ${numberOfPeople} personer')}"; - static String m85(emailIDs) => "Delt med ${emailIDs}"; + static String m87(emailIDs) => "Delt med ${emailIDs}"; - static String m86(fileType) => + static String m88(fileType) => "Denne ${fileType} vil bli slettet fra enheten din."; - static String m87(fileType) => + static String m89(fileType) => "Denne ${fileType} er både i Ente og på enheten din."; - static String m88(fileType) => "Denne ${fileType} vil bli slettet fra Ente."; + static String m90(fileType) => "Denne ${fileType} vil bli slettet fra Ente."; - static String m89(name) => "Sport med ${name}"; + static String m91(name) => "Sport med ${name}"; - static String m90(name) => "Fremhev ${name}"; + static String m92(name) => "Fremhev ${name}"; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} av ${totalAmount} ${totalStorageUnit} brukt"; - static String m93(id) => + static String m95(id) => "Din ${id} er allerede koblet til en annen Ente-konto.\nHvis du ønsker å bruke din ${id} med denne kontoen, vennligst kontakt vår brukerstøtte\'\'"; - static String m94(endDate) => + static String m96(endDate) => "Abonnementet ditt blir avsluttet den ${endDate}"; - static String m95(completed, total) => "${completed}/${total} minner bevart"; + static String m97(completed, total) => "${completed}/${total} minner bevart"; - static String m96(ignoreReason) => + static String m98(ignoreReason) => "Trykk for å laste opp, opplasting er ignorert nå på grunn av ${ignoreReason}"; - static String m97(storageAmountInGB) => "De får også ${storageAmountInGB} GB"; + static String m99(storageAmountInGB) => "De får også ${storageAmountInGB} GB"; - static String m98(email) => "Dette er ${email} sin verifiserings-ID"; - - static String m99(count) => - "${Intl.plural(count, one: 'Denne uka, ${count} år siden', other: 'Denne uka, ${count} år siden')}"; - - static String m100(dateFormat) => "${dateFormat} gjennom årene"; + static String m100(email) => "Dette er ${email} sin verifiserings-ID"; static String m101(count) => + "${Intl.plural(count, one: 'Denne uka, ${count} år siden', other: 'Denne uka, ${count} år siden')}"; + + static String m102(dateFormat) => "${dateFormat} gjennom årene"; + + static String m103(count) => "${Intl.plural(count, zero: 'Snart', one: '1 dag', other: '${count} dager')}"; - static String m102(year) => "Reise i ${year}"; + static String m104(year) => "Reise i ${year}"; - static String m103(location) => "Reise til ${location}"; + static String m105(location) => "Reise til ${location}"; - static String m104(email) => + static String m106(email) => "Du er invitert til å være en betrodd kontakt av ${email}."; - static String m105(galleryType) => + static String m107(galleryType) => "Galleritype ${galleryType} støttes ikke for nytt navn"; - static String m106(ignoreReason) => + static String m108(ignoreReason) => "Opplastingen ble ignorert på grunn av ${ignoreReason}"; - static String m107(count) => "Bevarer ${count} minner..."; + static String m109(count) => "Bevarer ${count} minner..."; - static String m108(endDate) => "Gyldig til ${endDate}"; + static String m110(endDate) => "Gyldig til ${endDate}"; - static String m109(email) => "Verifiser ${email}"; + static String m111(email) => "Verifiser ${email}"; - static String m112(email) => + static String m114(email) => "Vi har sendt en e-post til ${email}"; - static String m113(count) => - "${Intl.plural(count, one: '${count} år siden', other: '${count} år siden')}"; + static String m116(count) => + "${Intl.plural(count, other: '${count} år siden')}"; - static String m114(name) => "Du og ${name}"; + static String m117(name) => "Du og ${name}"; - static String m115(storageSaved) => "Du har frigjort ${storageSaved}!"; + static String m118(storageSaved) => "Du har frigjort ${storageSaved}!"; final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { @@ -590,8 +590,6 @@ class MessageLookup extends MessageLookupByLibrary { "click": MessageLookupByLibrary.simpleMessage("• Klikk"), "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage( "• Klikk på menyen med tre prikker"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "close": MessageLookupByLibrary.simpleMessage("Lukk"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage( "Grupper etter tidspunkt for opptak"), @@ -736,7 +734,7 @@ class MessageLookup extends MessageLookupByLibrary { "deleteItemCount": m21, "deleteLocation": MessageLookupByLibrary.simpleMessage("Slett sted"), "deletePhotos": MessageLookupByLibrary.simpleMessage("Slett bilder"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Det mangler en hovedfunksjon jeg trenger"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -775,7 +773,7 @@ class MessageLookup extends MessageLookupByLibrary { "Seere kan fremdeles ta skjermbilder eller lagre en kopi av bildene dine ved bruk av eksterne verktøy"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Vær oppmerksom på"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage("Deaktiver tofaktor"), "disablingTwofactorAuthentication": @@ -820,9 +818,9 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("Nedlasting mislyktes"), "downloading": MessageLookupByLibrary.simpleMessage("Laster ned..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("Rediger"), "editLocation": MessageLookupByLibrary.simpleMessage("Rediger plassering"), @@ -838,16 +836,16 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("E-post"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage( "E-postadressen er allerede registrert."), - "emailChangedTo": m28, - "emailDoesNotHaveEnteAccount": m29, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailDoesNotHaveEnteAccount": m30, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage( "E-postadressen er ikke registrert."), "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("E-postbekreftelse"), "emailYourLogs": MessageLookupByLibrary.simpleMessage("Send loggene dine på e-post"), - "embracingThem": m31, + "embracingThem": m32, "emergencyContacts": MessageLookupByLibrary.simpleMessage("Nødkontakter"), "empty": MessageLookupByLibrary.simpleMessage("Tom"), @@ -923,7 +921,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Eksporter dine data"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage("Ekstra bilder funnet"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage( "Ansikt ikke gruppert ennå, vennligst kom tilbake senere"), "faceRecognition": @@ -962,7 +960,7 @@ class MessageLookup extends MessageLookupByLibrary { "faq": MessageLookupByLibrary.simpleMessage("Ofte stilte spørsmål"), "faqs": MessageLookupByLibrary.simpleMessage("Ofte stilte spørsmål"), "favorite": MessageLookupByLibrary.simpleMessage("Favoritt"), - "feastingWithThem": m33, + "feastingWithThem": m34, "feedback": MessageLookupByLibrary.simpleMessage("Tilbakemelding"), "file": MessageLookupByLibrary.simpleMessage("Fil"), "fileFailedToSaveToGallery": MessageLookupByLibrary.simpleMessage( @@ -976,8 +974,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Filtyper"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Filtyper og navn"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("Filene er slettet"), "filesSavedToGallery": @@ -994,13 +992,13 @@ class MessageLookup extends MessageLookupByLibrary { "foundFaces": MessageLookupByLibrary.simpleMessage("Fant ansikter"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage( "Gratis lagringplass aktivert"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage( "Gratis lagringsplass som kan brukes"), "freeTrial": MessageLookupByLibrary.simpleMessage("Gratis prøveversjon"), - "freeTrialValidTill": m37, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("Frigjør plass på enheten"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( @@ -1013,7 +1011,7 @@ class MessageLookup extends MessageLookupByLibrary { "general": MessageLookupByLibrary.simpleMessage("Generelt"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Genererer krypteringsnøkler..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("Gå til innstillinger"), "googlePlayId": MessageLookupByLibrary.simpleMessage("Google Play ID"), @@ -1042,7 +1040,7 @@ class MessageLookup extends MessageLookupByLibrary { "hideSharedItemsFromHomeGallery": MessageLookupByLibrary.simpleMessage( "Skjul delte elementer fra hjemgalleriet"), "hiding": MessageLookupByLibrary.simpleMessage("Skjuler..."), - "hikingWithThem": m42, + "hikingWithThem": m43, "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("Hostet på OSM France"), "howItWorks": @@ -1099,7 +1097,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Det ser ut til at noe gikk galt. Prøv på nytt etter en stund. Hvis feilen vedvarer, kan du kontakte kundestøtte."), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Elementer viser gjenværende dager før de slettes for godt"), @@ -1120,7 +1118,7 @@ class MessageLookup extends MessageLookupByLibrary { "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( "Vær vennlig og hjelp oss med denne informasjonen"), "language": MessageLookupByLibrary.simpleMessage("Språk"), - "lastTimeWithThem": m44, + "lastTimeWithThem": m45, "lastUpdated": MessageLookupByLibrary.simpleMessage("Sist oppdatert"), "lastYearsTrip": MessageLookupByLibrary.simpleMessage("Fjorårets tur"), "leave": MessageLookupByLibrary.simpleMessage("Forlat"), @@ -1131,7 +1129,7 @@ class MessageLookup extends MessageLookupByLibrary { "left": MessageLookupByLibrary.simpleMessage("Venstre"), "legacy": MessageLookupByLibrary.simpleMessage("Arv"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("Eldre kontoer"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage( "Arv-funksjonen lar betrodde kontakter få tilgang til kontoen din i ditt fravær."), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( @@ -1147,7 +1145,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("for raskere deling"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Aktivert"), "linkExpired": MessageLookupByLibrary.simpleMessage("Utløpt"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Lenkeutløp"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("Lenken har utløpt"), @@ -1155,8 +1153,8 @@ class MessageLookup extends MessageLookupByLibrary { "linkPerson": MessageLookupByLibrary.simpleMessage("Knytt til person"), "linkPersonCaption": MessageLookupByLibrary.simpleMessage("for bedre delingsopplevelse"), - "linkPersonToEmail": m47, - "linkPersonToEmailConfirmation": m48, + "linkPersonToEmail": m48, + "linkPersonToEmailConfirmation": m49, "livePhotos": MessageLookupByLibrary.simpleMessage("Live-bilder"), "loadMessage1": MessageLookupByLibrary.simpleMessage( "Du kan dele abonnementet med familien din"), @@ -1215,8 +1213,6 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Lang-trykk på en gjenstand for å vise i fullskjerm"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "loopVideoOff": MessageLookupByLibrary.simpleMessage("Gjenta video av"), "loopVideoOn": MessageLookupByLibrary.simpleMessage("Gjenta video på"), "lostDevice": MessageLookupByLibrary.simpleMessage("Mistet enhet?"), @@ -1243,7 +1239,7 @@ class MessageLookup extends MessageLookupByLibrary { "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), "me": MessageLookupByLibrary.simpleMessage("Meg"), - "memoryCount": m49, + "memoryCount": m50, "merchandise": MessageLookupByLibrary.simpleMessage("Varer"), "mergeWithExisting": MessageLookupByLibrary.simpleMessage("Slå sammen med eksisterende"), @@ -1275,13 +1271,13 @@ class MessageLookup extends MessageLookupByLibrary { "mostRecent": MessageLookupByLibrary.simpleMessage("Nyeste"), "mostRelevant": MessageLookupByLibrary.simpleMessage("Mest relevant"), "mountains": MessageLookupByLibrary.simpleMessage("Over åsene"), - "moveItem": m50, + "moveItem": m51, "moveSelectedPhotosToOneDate": MessageLookupByLibrary.simpleMessage( "Flytt valgte bilder til en dato"), "moveToAlbum": MessageLookupByLibrary.simpleMessage("Flytt til album"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Flytt til skjult album"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("Flyttet til papirkurven"), "movingFilesToAlbum": @@ -1296,7 +1292,6 @@ class MessageLookup extends MessageLookupByLibrary { "newAlbum": MessageLookupByLibrary.simpleMessage("Nytt album"), "newLocation": MessageLookupByLibrary.simpleMessage("Ny plassering"), "newPerson": MessageLookupByLibrary.simpleMessage("Ny person"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "newRange": MessageLookupByLibrary.simpleMessage("Ny rekkevidde"), "newToEnte": MessageLookupByLibrary.simpleMessage("Ny til Ente"), "newest": MessageLookupByLibrary.simpleMessage("Nyeste"), @@ -1336,10 +1331,10 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Ingen resultater"), "noResultsFound": MessageLookupByLibrary.simpleMessage("Ingen resultater funnet"), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage("Ingen systemlås funnet"), - "notPersonLabel": m53, + "notPersonLabel": m54, "notThisPerson": MessageLookupByLibrary.simpleMessage("Ikke denne personen?"), "nothingSharedWithYouYet": @@ -1352,10 +1347,7 @@ class MessageLookup extends MessageLookupByLibrary { "onEnte": MessageLookupByLibrary.simpleMessage( "På ente"), "onTheRoad": MessageLookupByLibrary.simpleMessage("På veien igjen"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("Bare de"), "oops": MessageLookupByLibrary.simpleMessage("Oisann"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( @@ -1386,7 +1378,7 @@ class MessageLookup extends MessageLookupByLibrary { "pairingComplete": MessageLookupByLibrary.simpleMessage("Sammenkobling fullført"), "panorama": MessageLookupByLibrary.simpleMessage("Panora"), - "partyWithThem": m55, + "partyWithThem": m56, "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage("Bekreftelse venter fortsatt"), "passkey": MessageLookupByLibrary.simpleMessage("Tilgangsnøkkel"), @@ -1396,7 +1388,7 @@ class MessageLookup extends MessageLookupByLibrary { "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage("Passordet ble endret"), "passwordLock": MessageLookupByLibrary.simpleMessage("Passordlås"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "Passordstyrken beregnes basert på passordets lengde, brukte tegn, og om passordet finnes blant de 10 000 mest brukte passordene"), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -1407,7 +1399,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Betaling feilet"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Betalingen din mislyktes. Kontakt kundestøtte og vi vil hjelpe deg!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("Ventende elementer"), "pendingSync": @@ -1421,16 +1413,16 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Slette for godt"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage("Slett permanent fra enhet?"), - "personIsAge": m58, + "personIsAge": m59, "personName": MessageLookupByLibrary.simpleMessage("Personnavn"), - "personTurningAge": m59, + "personTurningAge": m60, "pets": MessageLookupByLibrary.simpleMessage("Pelsvenner"), "photoDescriptions": MessageLookupByLibrary.simpleMessage("Bildebeskrivelser"), "photoGridSize": MessageLookupByLibrary.simpleMessage("Bilderutenettstørrelse"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("bilde"), - "photocountPhotos": m60, + "photocountPhotos": m61, "photos": MessageLookupByLibrary.simpleMessage("Bilder"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage( @@ -1446,7 +1438,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Spill av album på TV"), "playOriginal": MessageLookupByLibrary.simpleMessage("Spill av original"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playStream": MessageLookupByLibrary.simpleMessage("Spill av strøm"), "playstoreSubscription": MessageLookupByLibrary.simpleMessage("PlayStore abonnement"), @@ -1459,14 +1451,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Vennligst kontakt kundestøtte hvis problemet vedvarer"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage("Vennligst gi tillatelser"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Vennligst logg inn igjen"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage("Velg hurtiglenker å fjerne"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Vennligst prøv igjen"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1480,7 +1472,7 @@ class MessageLookup extends MessageLookupByLibrary { "Vennligst vent en stund før du prøver på nytt"), "pleaseWaitThisWillTakeAWhile": MessageLookupByLibrary.simpleMessage( "Vennligst vent, dette vil ta litt tid."), - "posingWithThem": m65, + "posingWithThem": m66, "preparingLogs": MessageLookupByLibrary.simpleMessage("Forbereder logger..."), "preserveMore": MessageLookupByLibrary.simpleMessage("Behold mer"), @@ -1498,7 +1490,7 @@ class MessageLookup extends MessageLookupByLibrary { "proceed": MessageLookupByLibrary.simpleMessage("Fortsett"), "processed": MessageLookupByLibrary.simpleMessage("Behandlet"), "processing": MessageLookupByLibrary.simpleMessage("Behandler"), - "processingImport": m66, + "processingImport": m67, "processingVideos": MessageLookupByLibrary.simpleMessage("Behandler videoer"), "publicLinkCreated": @@ -1511,9 +1503,9 @@ class MessageLookup extends MessageLookupByLibrary { "raiseTicket": MessageLookupByLibrary.simpleMessage("Opprett sak"), "rateTheApp": MessageLookupByLibrary.simpleMessage("Vurder appen"), "rateUs": MessageLookupByLibrary.simpleMessage("Vurder oss"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "reassignMe": MessageLookupByLibrary.simpleMessage("Tildel \"Meg\""), - "reassignedToName": m68, + "reassignedToName": m69, "reassigningLoading": MessageLookupByLibrary.simpleMessage("Tildeler..."), "recover": MessageLookupByLibrary.simpleMessage("Gjenopprett"), @@ -1524,7 +1516,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Gjenopprett konto"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage("Gjenoppretting startet"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("Gjenopprettingsnøkkel"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( @@ -1539,12 +1531,12 @@ class MessageLookup extends MessageLookupByLibrary { "Gjenopprettingsnøkkel bekreftet"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "Gjenopprettingsnøkkelen er den eneste måten å gjenopprette bildene dine på hvis du glemmer passordet ditt. Du finner gjenopprettingsnøkkelen din i Innstillinger > Konto.\n\nVennligst skriv inn gjenopprettingsnøkkelen din her for å bekrefte at du har lagret den riktig."), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage( "Gjenopprettingen var vellykket!"), "recoveryWarning": MessageLookupByLibrary.simpleMessage( "En betrodd kontakt prøver å få tilgang til kontoen din"), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "Den gjeldende enheten er ikke kraftig nok til å verifisere passordet ditt, men vi kan regenerere på en måte som fungerer på alle enheter.\n\nVennligst logg inn med gjenopprettingsnøkkelen og regenerer passordet (du kan bruke den samme igjen om du vil)."), "recreatePasswordTitle": @@ -1560,7 +1552,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Gi denne koden til vennene dine"), "referralStep2": MessageLookupByLibrary.simpleMessage( "De registrerer seg for en betalt plan"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("Vervinger"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Vervinger er for øyeblikket satt på pause"), @@ -1591,7 +1583,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Fjern lenke"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Fjern deltaker"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Fjern etikett for person"), "removePublicLink": @@ -1612,7 +1604,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("Gi nytt filnavn"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Forny abonnement"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Rapporter en feil"), "reportBug": MessageLookupByLibrary.simpleMessage("Rapporter feil"), "resendEmail": @@ -1638,7 +1630,7 @@ class MessageLookup extends MessageLookupByLibrary { "reviewSuggestions": MessageLookupByLibrary.simpleMessage("Gjennomgå forslag"), "right": MessageLookupByLibrary.simpleMessage("Høyre"), - "roadtripWithThem": m75, + "roadtripWithThem": m76, "rotate": MessageLookupByLibrary.simpleMessage("Roter"), "rotateLeft": MessageLookupByLibrary.simpleMessage("Roter mot venstre"), "rotateRight": MessageLookupByLibrary.simpleMessage("Roter mot høyre"), @@ -1693,8 +1685,8 @@ class MessageLookup extends MessageLookupByLibrary { "Inviter folk, og du vil se alle bilder som deles av dem her"), "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage( "Folk vil vises her når behandling og synkronisering er fullført"), - "searchResultCount": m76, - "searchSectionsLengthMismatch": m77, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("Sikkerhet"), "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage( "Se offentlige albumlenker i appen"), @@ -1742,9 +1734,9 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeRemovedFromThisPerson": MessageLookupByLibrary.simpleMessage( "Valgte elementer fjernes fra denne personen, men blir ikke slettet fra biblioteket ditt."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, - "selfiesWithThem": m80, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, + "selfiesWithThem": m82, "send": MessageLookupByLibrary.simpleMessage("Send"), "sendEmail": MessageLookupByLibrary.simpleMessage("Send e-post"), "sendInvite": MessageLookupByLibrary.simpleMessage("Send invitasjon"), @@ -1774,16 +1766,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Del et album nå"), "shareLink": MessageLookupByLibrary.simpleMessage("Del link"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage("Del bare med de du vil"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Last ned Ente slik at vi lett kan dele bilder og videoer av original kvalitet\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Del med brukere som ikke har Ente"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage("Del ditt første album"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1794,7 +1786,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Nye delte bilder"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "Motta varsler når noen legger til et bilde i et delt album som du er en del av"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Delt med meg"), "sharedWithYou": MessageLookupByLibrary.simpleMessage("Delt med deg"), "sharing": MessageLookupByLibrary.simpleMessage("Deler..."), @@ -1810,11 +1802,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Logg ut andre enheter"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Jeg godtar bruksvilkårene og personvernreglene"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "Den vil bli slettet fra alle album."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("Hopp over"), "social": MessageLookupByLibrary.simpleMessage("Sosial"), "someItemsAreInBothEnteAndYourDevice": @@ -1843,15 +1835,13 @@ class MessageLookup extends MessageLookupByLibrary { "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "Beklager, vi kunne ikke generere sikre nøkler på denne enheten.\n\nvennligst registrer deg fra en annen enhet."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "sort": MessageLookupByLibrary.simpleMessage("Sorter"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Sorter etter"), "sortNewestFirst": MessageLookupByLibrary.simpleMessage("Nyeste først"), "sortOldestFirst": MessageLookupByLibrary.simpleMessage("Eldste først"), "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ Suksess"), - "sportsWithThem": m89, - "spotlightOnThem": m90, + "sportsWithThem": m91, + "spotlightOnThem": m92, "spotlightOnYourself": MessageLookupByLibrary.simpleMessage("Fremhev deg selv"), "startAccountRecoveryTitle": @@ -1866,15 +1856,15 @@ class MessageLookup extends MessageLookupByLibrary { "storage": MessageLookupByLibrary.simpleMessage("Lagring"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Familie"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Deg"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage("Lagringsplassen er full"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "streamDetails": MessageLookupByLibrary.simpleMessage("Strømmedetaljer"), "strongStrength": MessageLookupByLibrary.simpleMessage("Sterkt"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("Abonner"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "Du trenger et aktivt betalt abonnement for å aktivere deling."), @@ -1892,7 +1882,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Foreslå funksjoner"), "sunrise": MessageLookupByLibrary.simpleMessage("På horisonten"), "support": MessageLookupByLibrary.simpleMessage("Brukerstøtte"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("Synkronisering stoppet"), "syncing": MessageLookupByLibrary.simpleMessage("Synkroniserer..."), @@ -1905,7 +1895,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Trykk for å låse opp"), "tapToUpload": MessageLookupByLibrary.simpleMessage("Trykk for å laste opp"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Det ser ut som noe gikk galt. Prøv på nytt etter en stund. Hvis feilen vedvarer, kontakt kundestøtte."), "terminate": MessageLookupByLibrary.simpleMessage("Avslutte"), @@ -1928,7 +1918,7 @@ class MessageLookup extends MessageLookupByLibrary { "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage( "Disse elementene vil bli slettet fra enheten din."), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage( "De vil bli slettet fra alle album."), "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( @@ -1946,12 +1936,12 @@ class MessageLookup extends MessageLookupByLibrary { "Dette bildet har ingen exif-data"), "thisIsMeExclamation": MessageLookupByLibrary.simpleMessage("Dette er meg!"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( "Dette er din bekreftelses-ID"), "thisWeekThroughTheYears": MessageLookupByLibrary.simpleMessage("Denne uka gjennom årene"), - "thisWeekXYearsAgo": m99, + "thisWeekXYearsAgo": m101, "thisWillLogYouOutOfTheFollowingDevice": MessageLookupByLibrary.simpleMessage( "Dette vil logge deg ut av følgende enhet:"), @@ -1963,7 +1953,7 @@ class MessageLookup extends MessageLookupByLibrary { "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( "Dette fjerner de offentlige lenkene av alle valgte hurtiglenker."), - "throughTheYears": m100, + "throughTheYears": m102, "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": MessageLookupByLibrary.simpleMessage( "For å aktivere applås, vennligst angi passord eller skjermlås i systeminnstillingene."), @@ -1977,13 +1967,13 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("totalt"), "totalSize": MessageLookupByLibrary.simpleMessage("Total størrelse"), "trash": MessageLookupByLibrary.simpleMessage("Papirkurv"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("Beskjær"), - "tripInYear": m102, - "tripToLocation": m103, + "tripInYear": m104, + "tripToLocation": m105, "trustedContacts": MessageLookupByLibrary.simpleMessage("Betrodde kontakter"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("Prøv igjen"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "Slå på sikkerhetskopi for å automatisk laste opp filer lagt til denne enhetsmappen i Ente."), @@ -2001,7 +1991,7 @@ class MessageLookup extends MessageLookupByLibrary { "Tofaktorautentisering ble tilbakestilt"), "twofactorSetup": MessageLookupByLibrary.simpleMessage("Oppsett av to-faktor"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("Opphev arkivering"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("Gjenopprett album"), @@ -2025,10 +2015,10 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage("Oppdaterer mappevalg..."), "upgrade": MessageLookupByLibrary.simpleMessage("Oppgrader"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Laster opp filer til albumet..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage("Bevarer 1 minne..."), "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( @@ -2048,7 +2038,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Bruk valgt bilde"), "usedSpace": MessageLookupByLibrary.simpleMessage("Benyttet lagringsplass"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Bekreftelse mislyktes, vennligst prøv igjen"), @@ -2057,7 +2047,7 @@ class MessageLookup extends MessageLookupByLibrary { "verify": MessageLookupByLibrary.simpleMessage("Bekreft"), "verifyEmail": MessageLookupByLibrary.simpleMessage("Bekreft e-postadresse"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Bekreft"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("Bekreft tilgangsnøkkel"), @@ -2094,7 +2084,7 @@ class MessageLookup extends MessageLookupByLibrary { "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "Vi støtter ikke redigering av bilder og album som du ikke eier ennå"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Svakt"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Velkommen tilbake!"), @@ -2103,7 +2093,7 @@ class MessageLookup extends MessageLookupByLibrary { "Betrodd kontakt kan hjelpe til med å gjenopprette dine data."), "yearShort": MessageLookupByLibrary.simpleMessage("år"), "yearly": MessageLookupByLibrary.simpleMessage("Årlig"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Ja"), "yesCancel": MessageLookupByLibrary.simpleMessage("Ja, avslutt"), "yesConvertToViewer": @@ -2117,7 +2107,7 @@ class MessageLookup extends MessageLookupByLibrary { "yesResetPerson": MessageLookupByLibrary.simpleMessage("Ja, tilbakestill person"), "you": MessageLookupByLibrary.simpleMessage("Deg"), - "youAndThem": m114, + "youAndThem": m117, "youAreOnAFamilyPlan": MessageLookupByLibrary.simpleMessage( "Du har et familieabonnement!"), "youAreOnTheLatestVersion": MessageLookupByLibrary.simpleMessage( @@ -2136,7 +2126,7 @@ class MessageLookup extends MessageLookupByLibrary { "Du kan ikke dele med deg selv"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( "Du har ingen arkiverte elementer."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage( "Brukeren din har blitt slettet"), "yourMap": MessageLookupByLibrary.simpleMessage("Ditt kart"), diff --git a/mobile/lib/generated/intl/messages_or.dart b/mobile/lib/generated/intl/messages_or.dart index 67eb8daaa6..a55b91293d 100644 --- a/mobile/lib/generated/intl/messages_or.dart +++ b/mobile/lib/generated/intl/messages_or.dart @@ -20,17 +20,9 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'or'; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => { - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups") - }; + static Map _notInlinedMessages(_) => + {"wishThemAHappyBirthday": m115}; } diff --git a/mobile/lib/generated/intl/messages_pl.dart b/mobile/lib/generated/intl/messages_pl.dart index 2a82cbb320..81e1ea1cfb 100644 --- a/mobile/lib/generated/intl/messages_pl.dart +++ b/mobile/lib/generated/intl/messages_pl.dart @@ -66,178 +66,180 @@ class MessageLookup extends MessageLookupByLibrary { static String m20(endpoint) => "Połączono z ${endpoint}"; static String m21(count) => - "${Intl.plural(count, one: 'Usuń ${count} element', few: 'Usuń ${count} elementy', many: 'Usuń ${count} elementów', other: 'Usuń ${count} elementu')}"; + "${Intl.plural(count, one: 'Usuń ${count} element', other: 'Usuń ${count} elementu')}"; - static String m22(currentlyDeleting, totalCount) => + static String m23(currentlyDeleting, totalCount) => "Usuwanie ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "Spowoduje to usunięcie publicznego linku dostępu do \"${albumName}\"."; - static String m24(supportEmail) => + static String m25(supportEmail) => "Wyślij wiadomość e-mail na ${supportEmail} z zarejestrowanego adresu e-mail"; - static String m25(count, storageSaved) => + static String m26(count, storageSaved) => "Wyczyszczono ${Intl.plural(count, one: '${count} zdduplikowany plik', other: '${count} zdduplikowane pliki')}, oszczędzając (${storageSaved}!)"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} plików, każdy po ${formattedSize}"; - static String m28(newEmail) => "Adres e-mail został zmieniony na ${newEmail}"; + static String m29(newEmail) => "Adres e-mail został zmieniony na ${newEmail}"; - static String m30(email) => + static String m31(email) => "${email} nie posiada konta Ente.\n\nWyślij im zaproszenie do udostępniania zdjęć."; - static String m32(text) => "Znaleziono dodatkowe zdjęcia dla ${text}"; - - static String m34(count, formattedNumber) => - "${Intl.plural(count, one: '1 plikowi', other: '${formattedNumber} plikom')} na tym urządzeniu została bezpiecznie utworzona kopia zapasowa"; + static String m33(text) => "Znaleziono dodatkowe zdjęcia dla ${text}"; static String m35(count, formattedNumber) => + "${Intl.plural(count, one: '1 plikowi', other: '${formattedNumber} plikom')} na tym urządzeniu została bezpiecznie utworzona kopia zapasowa"; + + static String m36(count, formattedNumber) => "${Intl.plural(count, one: '1 plikowi', other: '${formattedNumber} plikom')} w tym albumie została bezpiecznie utworzona kopia zapasowa"; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "${storageAmountInGB} GB za każdym razem, gdy ktoś zarejestruje się w płatnym planie i użyje twojego kodu"; - static String m37(endDate) => "Okres próbny ważny do ${endDate}"; + static String m38(endDate) => "Okres próbny ważny do ${endDate}"; - static String m39(sizeInMBorGB) => "Zwolnij ${sizeInMBorGB}"; + static String m40(sizeInMBorGB) => "Zwolnij ${sizeInMBorGB}"; - static String m41(currentlyProcessing, totalCount) => + static String m42(currentlyProcessing, totalCount) => "Przetwarzanie ${currentlyProcessing} / ${totalCount}"; - static String m43(count) => - "${Intl.plural(count, one: '${count} element', few: '${count} elementy', many: '${count} elementów', other: '${count} elementu')}"; + static String m44(count) => + "${Intl.plural(count, one: '${count} element', other: '${count} elementu')}"; - static String m45(email) => + static String m46(email) => "${email} zaprosił Cię do zostania zaufanym kontaktem"; - static String m46(expiryTime) => "Link wygaśnie ${expiryTime}"; + static String m47(expiryTime) => "Link wygaśnie ${expiryTime}"; - static String m51(albumName) => "Pomyślnie przeniesiono do ${albumName}"; + static String m52(albumName) => "Pomyślnie przeniesiono do ${albumName}"; - static String m52(personName) => "Brak sugestii dla ${personName}"; + static String m53(personName) => "Brak sugestii dla ${personName}"; - static String m53(name) => "Nie ${name}?"; + static String m54(name) => "Nie ${name}?"; - static String m54(familyAdminEmail) => + static String m55(familyAdminEmail) => "Skontaktuj się z ${familyAdminEmail}, aby zmienić swój kod."; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Siła hasła: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "Porozmawiaj ze wsparciem ${providerName} jeśli zostałeś obciążony"; - static String m62(endDate) => + static String m63(endDate) => "Bezpłatny okres próbny ważny do ${endDate}.\nNastępnie możesz wybrać płatny plan."; - static String m63(toEmail) => + static String m64(toEmail) => "Prosimy o kontakt mailowy pod adresem ${toEmail}"; - static String m64(toEmail) => "Prosimy wysłać logi do ${toEmail}"; + static String m65(toEmail) => "Prosimy wysłać logi do ${toEmail}"; - static String m66(folderName) => "Przetwarzanie ${folderName}..."; + static String m67(folderName) => "Przetwarzanie ${folderName}..."; - static String m67(storeName) => "Oceń nas na ${storeName}"; + static String m68(storeName) => "Oceń nas na ${storeName}"; - static String m69(days, email) => + static String m70(days, email) => "Możesz uzyskać dostęp do konta po dniu ${days} dni. Powiadomienie zostanie wysłane na ${email}."; - static String m70(email) => + static String m71(email) => "Możesz teraz odzyskać konto ${email} poprzez ustawienie nowego hasła."; - static String m71(email) => "${email} próbuje odzyskać Twoje konto."; + static String m72(email) => "${email} próbuje odzyskać Twoje konto."; - static String m72(storageInGB) => + static String m73(storageInGB) => "3. Oboje otrzymujecie ${storageInGB} GB* za darmo"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} zostanie usunięty z tego udostępnionego albumu\n\nWszelkie dodane przez nich zdjęcia zostaną usunięte z albumu"; - static String m74(endDate) => "Subskrypcja odnowi się ${endDate}"; + static String m75(endDate) => "Subskrypcja odnowi się ${endDate}"; - static String m76(count) => - "${Intl.plural(count, one: 'Znaleziono ${count} wynik', few: 'Znaleziono ${count} wyniki', other: 'Znaleziono ${count} wyników')}"; + static String m77(count) => + "${Intl.plural(count, one: 'Znaleziono ${count} wynik', other: 'Znaleziono ${count} wyników')}"; - static String m77(snapshotLength, searchLength) => + static String m78(snapshotLength, searchLength) => "Niezgodność długości sekcji: ${snapshotLength} != ${searchLength}"; - static String m78(count) => "Wybrano ${count}"; + static String m80(count) => "Wybrano ${count}"; - static String m79(count, yourCount) => + static String m81(count, yourCount) => "Wybrano ${count} (twoich ${yourCount})"; - static String m81(verificationID) => + static String m83(verificationID) => "Oto mój identyfikator weryfikacyjny: ${verificationID} dla ente.io."; - static String m82(verificationID) => + static String m84(verificationID) => "Hej, czy możesz potwierdzić, że to jest Twój identyfikator weryfikacyjny ente.io: ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Kod polecający: ${referralCode} \n\nZastosuj go w: Ustawienia → Ogólne → Polecanie, aby otrzymać ${referralStorageInGB} GB za darmo po zarejestrowaniu się w płatnym planie\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Udostępnione określonym osobom', one: 'Udostępnione 1 osobie', other: 'Udostępnione ${numberOfPeople} osobom')}"; - static String m85(emailIDs) => "Udostępnione z ${emailIDs}"; + static String m87(emailIDs) => "Udostępnione z ${emailIDs}"; - static String m86(fileType) => + static String m88(fileType) => "Ten ${fileType} zostanie usunięty z Twojego urządzenia."; - static String m87(fileType) => + static String m89(fileType) => "Ten ${fileType} jest zarówno w Ente, jak i na twoim urządzeniu."; - static String m88(fileType) => "Ten ${fileType} zostanie usunięty z Ente."; + static String m90(fileType) => "Ten ${fileType} zostanie usunięty z Ente."; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "Użyto ${usedAmount} ${usedStorageUnit} z ${totalAmount} ${totalStorageUnit}"; - static String m93(id) => + static String m95(id) => "Twoje ${id} jest już połączony z innym kontem Ente.\nJeśli chcesz użyć swojego ${id} za pomocą tego konta, skontaktuj się z naszym wsparciem technicznym"; - static String m94(endDate) => + static String m96(endDate) => "Twoja subskrypcja zostanie anulowana dnia ${endDate}"; - static String m95(completed, total) => + static String m97(completed, total) => "Zachowano ${completed}/${total} wspomnień"; - static String m96(ignoreReason) => + static String m98(ignoreReason) => "Naciśnij, aby przesłać, przesyłanie jest obecnie ignorowane z powodu ${ignoreReason}"; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "Oni również otrzymują ${storageAmountInGB} GB"; - static String m98(email) => "To jest identyfikator weryfikacyjny ${email}"; + static String m100(email) => "To jest identyfikator weryfikacyjny ${email}"; - static String m101(count) => - "${Intl.plural(count, zero: 'Wkrótce', one: '1 dzień', few: '${count} dni', other: '${count} dni')}"; + static String m103(count) => + "${Intl.plural(count, zero: 'Wkrótce', one: '1 dzień', other: '${count} dni')}"; - static String m104(email) => + static String m106(email) => "Zostałeś zaproszony do bycia dziedzicznym kontaktem przez ${email}."; - static String m105(galleryType) => + static String m107(galleryType) => "Typ galerii ${galleryType} nie jest obsługiwany dla zmiany nazwy"; - static String m106(ignoreReason) => + static String m108(ignoreReason) => "Przesyłanie jest ignorowane z powodu ${ignoreReason}"; - static String m107(count) => "Zachowywanie ${count} wspomnień..."; + static String m109(count) => "Zachowywanie ${count} wspomnień..."; - static String m108(endDate) => "Ważne do ${endDate}"; + static String m110(endDate) => "Ważne do ${endDate}"; - static String m109(email) => "Zweryfikuj ${email}"; + static String m111(email) => "Zweryfikuj ${email}"; - static String m112(email) => + static String m114(email) => "Wysłaliśmy wiadomość na adres ${email}"; - static String m113(count) => - "${Intl.plural(count, one: '${count} rok temu', few: '${count} lata temu', many: '${count} lat temu', other: '${count} lata temu')}"; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; - static String m115(storageSaved) => "Pomyślnie zwolniłeś/aś ${storageSaved}!"; + static String m116(count) => + "${Intl.plural(count, one: '${count} rok temu', other: '${count} lata temu')}"; + + static String m118(storageSaved) => "Pomyślnie zwolniłeś/aś ${storageSaved}!"; final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { @@ -528,8 +530,6 @@ class MessageLookup extends MessageLookupByLibrary { "click": MessageLookupByLibrary.simpleMessage("• Kliknij"), "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage( "• Kliknij na menu przepełnienia"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "close": MessageLookupByLibrary.simpleMessage("Zamknij"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage( "Club według czasu przechwycenia"), @@ -672,7 +672,7 @@ class MessageLookup extends MessageLookupByLibrary { "deleteLocation": MessageLookupByLibrary.simpleMessage("Usuń lokalizację"), "deletePhotos": MessageLookupByLibrary.simpleMessage("Usuń zdjęcia"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Brakuje kluczowej funkcji, której potrzebuję"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -712,7 +712,7 @@ class MessageLookup extends MessageLookupByLibrary { "Widzowie mogą nadal robić zrzuty ekranu lub zapisywać kopie zdjęć za pomocą programów trzecich"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Uwaga"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Wyłącz uwierzytelnianie dwustopniowe"), "disablingTwofactorAuthentication": @@ -755,9 +755,9 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("Pobieranie nie powiodło się"), "downloading": MessageLookupByLibrary.simpleMessage("Pobieranie..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("Edytuj"), "editLocation": MessageLookupByLibrary.simpleMessage("Edytuj lokalizację"), @@ -772,8 +772,8 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("Adres e-mail"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage( "Adres e-mail jest już zarejestrowany."), - "emailChangedTo": m28, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage( "Adres e-mail nie jest zarejestrowany."), "emailVerificationToggle": @@ -856,7 +856,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Eksportuj swoje dane"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage( "Znaleziono dodatkowe zdjęcia"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage( "Twarz jeszcze nie zgrupowana, prosimy wrócić później"), "faceRecognition": @@ -908,8 +908,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Rodzaje plików"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Typy plików i nazwy"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("Pliki usunięto"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage("Pliki zapisane do galerii"), @@ -925,13 +925,13 @@ class MessageLookup extends MessageLookupByLibrary { "foundFaces": MessageLookupByLibrary.simpleMessage("Znaleziono twarze"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage( "Bezpłatna pamięć, którą odebrano"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("Darmowa pamięć użyteczna"), "freeTrial": MessageLookupByLibrary.simpleMessage("Darmowy okres próbny"), - "freeTrialValidTill": m37, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage( "Zwolnij miejsce na urządzeniu"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( @@ -943,7 +943,7 @@ class MessageLookup extends MessageLookupByLibrary { "general": MessageLookupByLibrary.simpleMessage("Ogólne"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Generowanie kluczy szyfrujących..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("Przejdź do ustawień"), "googlePlayId": @@ -1026,7 +1026,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Wygląda na to, że coś poszło nie tak. Spróbuj ponownie po pewnym czasie. Jeśli błąd będzie się powtarzał, skontaktuj się z naszym zespołem pomocy technicznej."), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Elementy pokazują liczbę dni pozostałych przed trwałym usunięciem"), @@ -1056,7 +1056,7 @@ class MessageLookup extends MessageLookupByLibrary { "legacy": MessageLookupByLibrary.simpleMessage("Dziedzictwo"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("Odziedziczone konta"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage( "Dziedzictwo pozwala zaufanym kontaktom na dostęp do Twojego konta w razie Twojej nieobecności."), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( @@ -1071,7 +1071,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Połącz adres e-mail"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Aktywny"), "linkExpired": MessageLookupByLibrary.simpleMessage("Wygasł"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Wygaśnięcie linku"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("Link wygasł"), "linkNeverExpires": MessageLookupByLibrary.simpleMessage("Nigdy"), @@ -1135,8 +1135,6 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Długo naciśnij element, aby wyświetlić go na pełnym ekranie"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "loopVideoOff": MessageLookupByLibrary.simpleMessage("Pętla wideo wyłączona"), "loopVideoOn": @@ -1200,7 +1198,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Przenieś do albumu"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Przenieś do ukrytego albumu"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("Przeniesiono do kosza"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1215,7 +1213,6 @@ class MessageLookup extends MessageLookupByLibrary { "newAlbum": MessageLookupByLibrary.simpleMessage("Nowy album"), "newLocation": MessageLookupByLibrary.simpleMessage("Nowa lokalizacja"), "newPerson": MessageLookupByLibrary.simpleMessage("Nowa osoba"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "newToEnte": MessageLookupByLibrary.simpleMessage("Nowy/a do Ente"), "newest": MessageLookupByLibrary.simpleMessage("Najnowsze"), "next": MessageLookupByLibrary.simpleMessage("Dalej"), @@ -1254,10 +1251,10 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Brak wyników"), "noResultsFound": MessageLookupByLibrary.simpleMessage("Nie znaleziono wyników"), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage( "Nie znaleziono blokady systemowej"), - "notPersonLabel": m53, + "notPersonLabel": m54, "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( "Nic Ci jeszcze nie udostępniono"), "nothingToSeeHere": MessageLookupByLibrary.simpleMessage( @@ -1267,10 +1264,7 @@ class MessageLookup extends MessageLookupByLibrary { "onDevice": MessageLookupByLibrary.simpleMessage("Na urządzeniu"), "onEnte": MessageLookupByLibrary.simpleMessage("W ente"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("Tylko te"), "oops": MessageLookupByLibrary.simpleMessage("Ups"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( @@ -1307,7 +1301,7 @@ class MessageLookup extends MessageLookupByLibrary { "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage( "Hasło zostało pomyślnie zmienione"), "passwordLock": MessageLookupByLibrary.simpleMessage("Blokada hasłem"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "Siła hasła jest obliczana, biorąc pod uwagę długość hasła, użyte znaki, i czy hasło pojawi się w 10 000 najczęściej używanych haseł"), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -1318,7 +1312,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Płatność się nie powiodła"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Niestety Twoja płatność nie powiodła się. Skontaktuj się z pomocą techniczną, a my Ci pomożemy!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("Oczekujące elementy"), "pendingSync": @@ -1348,7 +1342,7 @@ class MessageLookup extends MessageLookupByLibrary { "pinLock": MessageLookupByLibrary.simpleMessage("Blokada PIN"), "playOnTv": MessageLookupByLibrary.simpleMessage( "Odtwórz album na telewizorze"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("Subskrypcja PlayStore"), "pleaseCheckYourInternetConnectionAndTryAgain": @@ -1360,14 +1354,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Skontaktuj się z pomocą techniczną, jeśli problem będzie się powtarzał"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage( "Prosimy przyznać uprawnienia"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Zaloguj się ponownie"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Prosimy wybrać szybkie linki do usunięcia"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Spróbuj ponownie"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1395,7 +1389,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Udostępnianie prywatne"), "proceed": MessageLookupByLibrary.simpleMessage("Kontynuuj"), "processed": MessageLookupByLibrary.simpleMessage("Przetworzone"), - "processingImport": m66, + "processingImport": m67, "publicLinkCreated": MessageLookupByLibrary.simpleMessage("Utworzono publiczny link"), "publicLinkEnabled": @@ -1405,7 +1399,7 @@ class MessageLookup extends MessageLookupByLibrary { "raiseTicket": MessageLookupByLibrary.simpleMessage("Zgłoś"), "rateTheApp": MessageLookupByLibrary.simpleMessage("Oceń aplikację"), "rateUs": MessageLookupByLibrary.simpleMessage("Oceń nas"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "recover": MessageLookupByLibrary.simpleMessage("Odzyskaj"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Odzyskaj konto"), @@ -1414,7 +1408,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Odzyskaj konto"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage("Odzyskiwanie rozpoczęte"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("Klucz odzyskiwania"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( @@ -1429,12 +1423,12 @@ class MessageLookup extends MessageLookupByLibrary { "Klucz odzyskiwania zweryfikowany"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "Twój klucz odzyskiwania jest jedynym sposobem na odzyskanie zdjęć, jeśli zapomnisz hasła. Klucz odzyskiwania można znaleźć w Ustawieniach > Konto.\n\nWprowadź tutaj swój klucz odzyskiwania, aby sprawdzić, czy został zapisany poprawnie."), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage("Odzyskano pomyślnie!"), "recoveryWarning": MessageLookupByLibrary.simpleMessage( "Zaufany kontakt próbuje uzyskać dostęp do Twojego konta"), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "Obecne urządzenie nie jest wystarczająco wydajne, aby zweryfikować hasło, ale możemy je wygenerować w sposób działający na wszystkich urządzeniach.\n\nZaloguj się przy użyciu klucza odzyskiwania i wygeneruj nowe hasło (jeśli chcesz, możesz ponownie użyć tego samego)."), "recreatePasswordTitle": @@ -1450,7 +1444,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Przekaż ten kod swoim znajomym"), "referralStep2": MessageLookupByLibrary.simpleMessage("2. Wykupują płatny plan"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("Polecenia"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Wysyłanie poleceń jest obecnie wstrzymane"), @@ -1480,7 +1474,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Usuń link"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Usuń użytkownika"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Usuń etykietę osoby"), "removePublicLink": @@ -1501,7 +1495,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("Zmień nazwę pliku"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Odnów subskrypcję"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Zgłoś błąd"), "reportBug": MessageLookupByLibrary.simpleMessage("Zgłoś błąd"), "resendEmail": @@ -1579,8 +1573,8 @@ class MessageLookup extends MessageLookupByLibrary { "Zaproś ludzi, a zobaczysz tutaj wszystkie udostępnione przez nich zdjęcia"), "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage( "Osoby będą wyświetlane tutaj po zakończeniu przetwarzania i synchronizacji"), - "searchResultCount": m76, - "searchSectionsLengthMismatch": m77, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("Bezpieczeństwo"), "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage( "Zobacz publiczne linki do albumów w aplikacji"), @@ -1613,8 +1607,8 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage( "Wybrane elementy zostaną usunięte ze wszystkich albumów i przeniesione do kosza."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, "send": MessageLookupByLibrary.simpleMessage("Wyślij"), "sendEmail": MessageLookupByLibrary.simpleMessage("Wyślij e-mail"), "sendInvite": @@ -1643,16 +1637,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Udostępnij teraz album"), "shareLink": MessageLookupByLibrary.simpleMessage("Udostępnij link"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Udostępnij tylko ludziom, którym chcesz"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Pobierz Ente, abyśmy mogli łatwo udostępniać zdjęcia i wideo w oryginalnej jakości\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Udostępnij użytkownikom bez konta Ente"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage( "Udostępnij swój pierwszy album"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1665,7 +1659,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Nowe udostępnione zdjęcia"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "Otrzymuj powiadomienia, gdy ktoś doda zdjęcie do udostępnionego albumu, którego jesteś częścią"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Udostępnione ze mną"), "sharedWithYou": @@ -1682,11 +1676,11 @@ class MessageLookup extends MessageLookupByLibrary { "Wyloguj z pozostałych urządzeń"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Akceptuję warunki korzystania z usługi i politykę prywatności"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "To zostanie usunięte ze wszystkich albumów."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("Pomiń"), "social": MessageLookupByLibrary.simpleMessage("Społeczność"), "someItemsAreInBothEnteAndYourDevice": @@ -1715,8 +1709,6 @@ class MessageLookup extends MessageLookupByLibrary { "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "Przepraszamy, nie mogliśmy wygenerować bezpiecznych kluczy na tym urządzeniu.\n\nZarejestruj się z innego urządzenia."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "sort": MessageLookupByLibrary.simpleMessage("Sortuj"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Sortuj według"), "sortNewestFirst": @@ -1736,13 +1728,13 @@ class MessageLookup extends MessageLookupByLibrary { "storage": MessageLookupByLibrary.simpleMessage("Pamięć"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Rodzina"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Ty"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage("Przekroczono limit pamięci"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "strongStrength": MessageLookupByLibrary.simpleMessage("Silne"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("Subskrybuj"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "Potrzebujesz aktywnej płatnej subskrypcji, aby włączyć udostępnianie."), @@ -1759,7 +1751,7 @@ class MessageLookup extends MessageLookupByLibrary { "suggestFeatures": MessageLookupByLibrary.simpleMessage("Zaproponuj funkcje"), "support": MessageLookupByLibrary.simpleMessage("Wsparcie techniczne"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("Synchronizacja zatrzymana"), "syncing": MessageLookupByLibrary.simpleMessage("Synchronizowanie..."), @@ -1772,7 +1764,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Naciśnij, aby odblokować"), "tapToUpload": MessageLookupByLibrary.simpleMessage("Naciśnij, aby przesłać"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Wygląda na to, że coś poszło nie tak. Spróbuj ponownie po pewnym czasie. Jeśli błąd będzie się powtarzał, skontaktuj się z naszym zespołem pomocy technicznej."), "terminate": MessageLookupByLibrary.simpleMessage("Zakończ"), @@ -1796,7 +1788,7 @@ class MessageLookup extends MessageLookupByLibrary { "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage( "Te elementy zostaną usunięte z Twojego urządzenia."), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage( "Zostaną one usunięte ze wszystkich albumów."), "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( @@ -1812,7 +1804,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ten e-mail jest już używany"), "thisImageHasNoExifData": MessageLookupByLibrary.simpleMessage( "Ten obraz nie posiada danych exif"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( "To jest Twój Identyfikator Weryfikacji"), "thisWillLogYouOutOfTheFollowingDevice": @@ -1836,11 +1828,11 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("ogółem"), "totalSize": MessageLookupByLibrary.simpleMessage("Całkowity rozmiar"), "trash": MessageLookupByLibrary.simpleMessage("Kosz"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("Przytnij"), "trustedContacts": MessageLookupByLibrary.simpleMessage("Zaufane kontakty"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("Spróbuj ponownie"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "Włącz kopię zapasową, aby automatycznie przesyłać pliki dodane do folderu urządzenia do Ente."), @@ -1860,7 +1852,7 @@ class MessageLookup extends MessageLookupByLibrary { "Pomyślnie zresetowano uwierzytelnianie dwustopniowe"), "twofactorSetup": MessageLookupByLibrary.simpleMessage( "Uwierzytelnianie dwustopniowe"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("Przywróć z archiwum"), "unarchiveAlbum": @@ -1885,10 +1877,10 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage( "Aktualizowanie wyboru folderu..."), "upgrade": MessageLookupByLibrary.simpleMessage("Ulepsz"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Przesyłanie plików do albumu..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage( "Zachowywanie 1 wspomnienia..."), "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( @@ -1906,7 +1898,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("Użyj zaznaczone zdjęcie"), "usedSpace": MessageLookupByLibrary.simpleMessage("Zajęta przestrzeń"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Weryfikacja nie powiodła się, spróbuj ponownie"), @@ -1915,7 +1907,7 @@ class MessageLookup extends MessageLookupByLibrary { "verify": MessageLookupByLibrary.simpleMessage("Zweryfikuj"), "verifyEmail": MessageLookupByLibrary.simpleMessage("Zweryfikuj adres e-mail"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Zweryfikuj"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("Zweryfikuj klucz dostępu"), @@ -1953,15 +1945,16 @@ class MessageLookup extends MessageLookupByLibrary { "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "Nie wspieramy edycji zdjęć i albumów, których jeszcze nie posiadasz"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Słabe"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Witaj ponownie!"), "whatsNew": MessageLookupByLibrary.simpleMessage("Co nowego"), "whyAddTrustContact": MessageLookupByLibrary.simpleMessage( "Zaufany kontakt może pomóc w odzyskaniu Twoich danych."), + "wishThemAHappyBirthday": m115, "yearShort": MessageLookupByLibrary.simpleMessage("r"), "yearly": MessageLookupByLibrary.simpleMessage("Rocznie"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Tak"), "yesCancel": MessageLookupByLibrary.simpleMessage("Tak, anuluj"), "yesConvertToViewer": @@ -1993,7 +1986,7 @@ class MessageLookup extends MessageLookupByLibrary { "Nie możesz udostępnić samemu sobie"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( "Nie masz żadnych zarchiwizowanych elementów."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage( "Twoje konto zostało usunięte"), "yourMap": MessageLookupByLibrary.simpleMessage("Twoja mapa"), diff --git a/mobile/lib/generated/intl/messages_pt.dart b/mobile/lib/generated/intl/messages_pt.dart index 8583931540..9831a7ba65 100644 --- a/mobile/lib/generated/intl/messages_pt.dart +++ b/mobile/lib/generated/intl/messages_pt.dart @@ -73,223 +73,225 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'Apagar ${count} item', other: 'Apagar ${count} itens')}"; - static String m22(currentlyDeleting, totalCount) => + static String m23(currentlyDeleting, totalCount) => "Apagar ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "Isto removerá o link público para acessar \"${albumName}\"."; - static String m24(supportEmail) => + static String m25(supportEmail) => "Envie um e-mail para ${supportEmail} a partir do seu endereço de e-mail registado"; - static String m25(count, storageSaved) => + static String m26(count, storageSaved) => "Você limpou ${Intl.plural(count, one: '${count} arquivo duplicado', other: '${count} arquivos duplicados')}, guardando (${storageSaved}!)"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} arquivos, ${formattedSize} cada"; - static String m28(newEmail) => "Email alterado para ${newEmail}"; + static String m29(newEmail) => "Email alterado para ${newEmail}"; - static String m29(email) => "${email} não possui uma conta Ente."; + static String m30(email) => "${email} não possui uma conta Ente."; - static String m30(email) => + static String m31(email) => "${email} não possui uma conta Ente.\n\nEnvie um convite para compartilhar fotos."; - static String m31(name) => "Abraçando ${name}"; + static String m32(name) => "Abraçando ${name}"; - static String m32(text) => "Fotos extras encontradas para ${text}"; + static String m33(text) => "Fotos extras encontradas para ${text}"; - static String m33(name) => "Tendo banquete com ${name}"; - - static String m34(count, formattedNumber) => - "${Intl.plural(count, one: '1 arquivo', other: '${formattedNumber} arquivos')} neste dispositivo teve um backup seguro"; + static String m34(name) => "Tendo banquete com ${name}"; static String m35(count, formattedNumber) => + "${Intl.plural(count, one: '1 arquivo', other: '${formattedNumber} arquivos')} neste dispositivo teve um backup seguro"; + + static String m36(count, formattedNumber) => "${Intl.plural(count, one: '1 arquivo', other: '${formattedNumber} arquivos')} neste álbum teve um backup seguro"; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "${storageAmountInGB} GB sempre que alguém se inscreve num plano pago e aplica o seu código"; - static String m37(endDate) => "Teste gratuito válido até ${endDate}"; + static String m38(endDate) => "Teste gratuito válido até ${endDate}"; - static String m39(sizeInMBorGB) => "Libertar ${sizeInMBorGB}"; + static String m40(sizeInMBorGB) => "Libertar ${sizeInMBorGB}"; - static String m41(currentlyProcessing, totalCount) => + static String m42(currentlyProcessing, totalCount) => "Processando ${currentlyProcessing} / ${totalCount}"; - static String m42(name) => "Caminhando com ${name}"; + static String m43(name) => "Caminhando com ${name}"; - static String m43(count) => + static String m44(count) => "${Intl.plural(count, one: '${count} item', other: '${count} itens')}"; - static String m44(name) => "Últimos momentos com ${name}"; + static String m45(name) => "Últimos momentos com ${name}"; - static String m45(email) => + static String m46(email) => "${email} convidou você para ser um contato confiável"; - static String m46(expiryTime) => "O link expirará em ${expiryTime}"; + static String m47(expiryTime) => "O link expirará em ${expiryTime}"; - static String m47(email) => "Vincular pessoa a ${email}"; + static String m48(email) => "Vincular pessoa a ${email}"; - static String m48(personName, email) => + static String m49(personName, email) => "Isso vinculará ${personName} a ${email}"; - static String m51(albumName) => "Movido com sucesso para ${albumName}"; + static String m52(albumName) => "Movido com sucesso para ${albumName}"; - static String m52(personName) => "Sem sugestões para ${personName}"; + static String m53(personName) => "Sem sugestões para ${personName}"; - static String m53(name) => "Não é ${name}?"; + static String m54(name) => "Não é ${name}?"; - static String m54(familyAdminEmail) => + static String m55(familyAdminEmail) => "Entre em contato com ${familyAdminEmail} para alterar o seu código."; - static String m55(name) => "Festejando com ${name}"; + static String m56(name) => "Festejando com ${name}"; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Força da palavra-passe: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "Por favor, fale com o suporte ${providerName} se você foi cobrado"; - static String m58(name, age) => "${name} está com ${age}!"; + static String m59(name, age) => "${name} está com ${age}!"; - static String m59(name, age) => "${name} terá ${age} em breve"; - - static String m60(count) => - "${Intl.plural(count, zero: 'Sem fotos', one: '1 foto', other: '${count} fotos')}"; + static String m60(name, age) => "${name} terá ${age} em breve"; static String m61(count) => + "${Intl.plural(count, zero: 'Sem fotos', one: '1 foto', other: '${count} fotos')}"; + + static String m62(count) => "${Intl.plural(count, zero: '0 fotos', one: '1 foto', other: '${count} fotos')}"; - static String m62(endDate) => + static String m63(endDate) => "Teste gratuito válido até ${endDate}.\nVocê pode escolher um plano pago depois."; - static String m63(toEmail) => + static String m64(toEmail) => "Por favor, envie-nos um e-mail para ${toEmail}"; - static String m64(toEmail) => "Por favor, envie os logs para \n${toEmail}"; + static String m65(toEmail) => "Por favor, envie os logs para \n${toEmail}"; - static String m65(name) => "Fazendo pose com ${name}"; + static String m66(name) => "Fazendo pose com ${name}"; - static String m66(folderName) => "Processando ${folderName}..."; + static String m67(folderName) => "Processando ${folderName}..."; - static String m67(storeName) => "Avalie-nos em ${storeName}"; + static String m68(storeName) => "Avalie-nos em ${storeName}"; - static String m68(name) => "Atribuído a ${name}"; + static String m69(name) => "Atribuído a ${name}"; - static String m69(days, email) => + static String m70(days, email) => "Você poderá acessar a conta após ${days} dias. Uma notificação será enviada para ${email}."; - static String m70(email) => + static String m71(email) => "Você pode recuperar a conta com e-mail ${email} por definir uma nova senha."; - static String m71(email) => "${email} está tentando recuperar sua conta."; + static String m72(email) => "${email} está tentando recuperar sua conta."; - static String m72(storageInGB) => "3. Ambos ganham ${storageInGB} GB* grátis"; + static String m73(storageInGB) => "3. Ambos ganham ${storageInGB} GB* grátis"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} será removido deste álbum compartilhado\n\nQuaisquer fotos adicionadas por elas também serão removidas do álbum"; - static String m74(endDate) => "A subscrição é renovada em ${endDate}"; + static String m75(endDate) => "A subscrição é renovada em ${endDate}"; - static String m75(name) => "Viajando de carro com ${name}"; + static String m76(name) => "Viajando de carro com ${name}"; - static String m76(count) => + static String m77(count) => "${Intl.plural(count, one: '${count} ano atrás', other: '${count} anos atrás')}"; - static String m77(snapshotLength, searchLength) => + static String m78(snapshotLength, searchLength) => "Incompatibilidade de comprimento de seções: ${snapshotLength} != ${searchLength}"; - static String m78(count) => "${count} selecionado(s)"; + static String m80(count) => "${count} selecionado(s)"; - static String m79(count, yourCount) => + static String m81(count, yourCount) => "${count} selecionado(s) (${yourCount} seus)"; - static String m80(name) => "Tirando selfies com ${name}"; + static String m82(name) => "Tirando selfies com ${name}"; - static String m81(verificationID) => + static String m83(verificationID) => "Aqui está o meu ID de verificação: ${verificationID} para ente.io."; - static String m82(verificationID) => + static String m84(verificationID) => "Ei, você pode confirmar que este é seu ID de verificação do ente.io: ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Insira o código de referência: ${referralCode} \n\nAplique-o em Configurações → Geral → Indicações para obter ${referralStorageInGB} GB gratuitamente após a sua inscrição para um plano pago\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Compartilhe com pessoas específicas', one: 'Compartilhado com 1 pessoa', other: 'Compartilhado com ${numberOfPeople} pessoas')}"; - static String m85(emailIDs) => "Partilhado com ${emailIDs}"; + static String m87(emailIDs) => "Partilhado com ${emailIDs}"; - static String m86(fileType) => + static String m88(fileType) => "Este ${fileType} será eliminado do seu dispositivo."; - static String m87(fileType) => + static String m89(fileType) => "Este ${fileType} encontra-se tanto no Ente como no seu dispositivo."; - static String m88(fileType) => "Este ${fileType} será eliminado do Ente."; + static String m90(fileType) => "Este ${fileType} será eliminado do Ente."; - static String m89(name) => "Jogando esportes com ${name}"; + static String m91(name) => "Jogando esportes com ${name}"; - static String m90(name) => "Destacar ${name}"; + static String m92(name) => "Destacar ${name}"; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} de ${totalAmount} ${totalStorageUnit} usado"; - static String m93(id) => + static String m95(id) => "Seu ${id} já está vinculado a outra conta Ente.\nSe você gostaria de usar seu ${id} com esta conta, por favor contate nosso suporte\'\'"; - static String m94(endDate) => "A sua subscrição será cancelada em ${endDate}"; + static String m96(endDate) => "A sua subscrição será cancelada em ${endDate}"; - static String m95(completed, total) => + static String m97(completed, total) => "${completed}/${total} memórias preservadas"; - static String m96(ignoreReason) => + static String m98(ignoreReason) => "Toque para enviar, atualmente o envio é ignorado devido a ${ignoreReason}"; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "Eles também recebem ${storageAmountInGB} GB"; - static String m98(email) => "Este é o ID de verificação de ${email}"; - - static String m99(count) => - "${Intl.plural(count, one: 'Esta semana, ${count} ano atrás', other: 'Esta semana, ${count} anos atrás')}"; - - static String m100(dateFormat) => "${dateFormat} com o passar dos anos"; + static String m100(email) => "Este é o ID de verificação de ${email}"; static String m101(count) => + "${Intl.plural(count, one: 'Esta semana, ${count} ano atrás', other: 'Esta semana, ${count} anos atrás')}"; + + static String m102(dateFormat) => "${dateFormat} com o passar dos anos"; + + static String m103(count) => "${Intl.plural(count, zero: 'Brevemente', one: '1 dia', other: '${count} dias')}"; - static String m102(year) => "Viajem em ${year}"; + static String m104(year) => "Viajem em ${year}"; - static String m103(location) => "Viajem à ${location}"; + static String m105(location) => "Viajem à ${location}"; - static String m104(email) => + static String m106(email) => "Você foi convidado para ser um contato legado por ${email}."; - static String m105(galleryType) => + static String m107(galleryType) => "Tipo de galeria ${galleryType} não é permitido para renomear"; - static String m106(ignoreReason) => "Envio ignorado devido à ${ignoreReason}"; + static String m108(ignoreReason) => "Envio ignorado devido à ${ignoreReason}"; - static String m107(count) => "Preservar ${count} memórias..."; + static String m109(count) => "Preservar ${count} memórias..."; - static String m108(endDate) => "Válido até ${endDate}"; + static String m110(endDate) => "Válido até ${endDate}"; - static String m109(email) => "Verificar e-mail"; + static String m111(email) => "Verificar e-mail"; - static String m112(email) => + static String m114(email) => "Enviamos um e-mail para ${email}"; - static String m113(count) => + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + + static String m116(count) => "${Intl.plural(count, one: '${count} ano atrás', other: '${count} anos atrás')}"; - static String m114(name) => "Você e ${name}"; + static String m117(name) => "Você e ${name}"; - static String m115(storageSaved) => + static String m118(storageSaved) => "Você liberou ${storageSaved} com sucesso!"; final messages = _notInlinedMessages(_notInlinedMessages); @@ -512,6 +514,7 @@ class MessageLookup extends MessageLookupByLibrary { "Cópia de segurança de vídeos"), "beach": MessageLookupByLibrary.simpleMessage("Areia e o mar"), "birthday": MessageLookupByLibrary.simpleMessage("Aniversário"), + "birthdays": MessageLookupByLibrary.simpleMessage("Birthdays"), "blackFridaySale": MessageLookupByLibrary.simpleMessage("Promoção Black Friday"), "blog": MessageLookupByLibrary.simpleMessage("Blog"), @@ -726,7 +729,7 @@ class MessageLookup extends MessageLookupByLibrary { "deleteLocation": MessageLookupByLibrary.simpleMessage("Apagar localização"), "deletePhotos": MessageLookupByLibrary.simpleMessage("Apagar fotos"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Falta uma funcionalidade-chave de que eu necessito"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -766,7 +769,7 @@ class MessageLookup extends MessageLookupByLibrary { "Visualizadores ainda podem fazer capturas de tela ou salvar uma cópia das suas fotos usando ferramentas externas"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Por favor, observe"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Desativar autenticação de dois fatores"), "disablingTwofactorAuthentication": @@ -811,9 +814,9 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("Falha no download"), "downloading": MessageLookupByLibrary.simpleMessage("A transferir..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("Editar"), "editLocation": MessageLookupByLibrary.simpleMessage("Editar localização"), @@ -827,14 +830,14 @@ class MessageLookup extends MessageLookupByLibrary { "Edições para localização só serão vistas dentro do Ente"), "eligible": MessageLookupByLibrary.simpleMessage("elegível"), "email": MessageLookupByLibrary.simpleMessage("Email"), - "emailChangedTo": m28, - "emailDoesNotHaveEnteAccount": m29, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailDoesNotHaveEnteAccount": m30, + "emailNoEnteAccount": m31, "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("Verificação por e-mail"), "emailYourLogs": MessageLookupByLibrary.simpleMessage("Enviar logs por e-mail"), - "embracingThem": m31, + "embracingThem": m32, "emergencyContacts": MessageLookupByLibrary.simpleMessage("Contatos de emergência"), "empty": MessageLookupByLibrary.simpleMessage("Esvaziar"), @@ -911,7 +914,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Exportar os seus dados"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage( "Fotos adicionais encontradas"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage( "Rosto não agrupado ainda, volte aqui mais tarde"), "faceRecognition": @@ -950,7 +953,7 @@ class MessageLookup extends MessageLookupByLibrary { "faq": MessageLookupByLibrary.simpleMessage("Perguntas Frequentes"), "faqs": MessageLookupByLibrary.simpleMessage("Perguntas frequentes"), "favorite": MessageLookupByLibrary.simpleMessage("Favorito"), - "feastingWithThem": m33, + "feastingWithThem": m34, "feedback": MessageLookupByLibrary.simpleMessage("Opinião"), "file": MessageLookupByLibrary.simpleMessage("Arquivo"), "fileFailedToSaveToGallery": MessageLookupByLibrary.simpleMessage( @@ -964,8 +967,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Tipos de arquivo"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Tipos de arquivo e nomes"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("Arquivos apagados"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage( @@ -984,12 +987,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Rostos encontrados"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage( "Armazenamento gratuito reclamado"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage( "Armazenamento livre utilizável"), "freeTrial": MessageLookupByLibrary.simpleMessage("Teste grátis"), - "freeTrialValidTill": m37, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage( "Libertar espaço no dispositivo"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( @@ -1001,7 +1004,7 @@ class MessageLookup extends MessageLookupByLibrary { "general": MessageLookupByLibrary.simpleMessage("Geral"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Gerando chaves de encriptação..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("Ir para as definições"), "googlePlayId": @@ -1016,6 +1019,8 @@ class MessageLookup extends MessageLookupByLibrary { "guestView": MessageLookupByLibrary.simpleMessage("Visão de convidado"), "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( "Para ativar a vista de convidado, configure o código de acesso do dispositivo ou o bloqueio do ecrã nas definições do sistema."), + "happyBirthday": + MessageLookupByLibrary.simpleMessage("Happy birthday! 🥳"), "hearUsExplanation": MessageLookupByLibrary.simpleMessage( "Não monitorizamos as instalações de aplicações. Ajudaria se nos dissesse onde nos encontrou!"), "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( @@ -1031,7 +1036,7 @@ class MessageLookup extends MessageLookupByLibrary { "hideSharedItemsFromHomeGallery": MessageLookupByLibrary.simpleMessage( "Ocultar itens compartilhados da galeria inicial"), "hiding": MessageLookupByLibrary.simpleMessage("Ocultando..."), - "hikingWithThem": m42, + "hikingWithThem": m43, "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("Hospedado na OSM France"), "howItWorks": MessageLookupByLibrary.simpleMessage("Como funciona"), @@ -1088,7 +1093,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Parece que algo correu mal. Por favor, tente novamente após algum tempo. Se o erro persistir, contacte a nossa equipa de apoio."), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Os itens mostram o número de dias restantes antes da eliminação permanente"), @@ -1109,7 +1114,7 @@ class MessageLookup extends MessageLookupByLibrary { "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( "Por favor, ajude-nos com esta informação"), "language": MessageLookupByLibrary.simpleMessage("Idioma"), - "lastTimeWithThem": m44, + "lastTimeWithThem": m45, "lastUpdated": MessageLookupByLibrary.simpleMessage("Última atualização"), "lastYearsTrip": @@ -1124,7 +1129,7 @@ class MessageLookup extends MessageLookupByLibrary { "legacy": MessageLookupByLibrary.simpleMessage("Legado"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("Contas legadas"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage( "O legado permite que contatos confiáveis acessem sua conta em sua ausência."), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( @@ -1141,7 +1146,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("para compartilhar rápido"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Ativado"), "linkExpired": MessageLookupByLibrary.simpleMessage("Expirado"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Link expirado"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("O link expirou"), @@ -1149,8 +1154,8 @@ class MessageLookup extends MessageLookupByLibrary { "linkPerson": MessageLookupByLibrary.simpleMessage("Vincular pessoa"), "linkPersonCaption": MessageLookupByLibrary.simpleMessage( "para melhor experiência de compartilhamento"), - "linkPersonToEmail": m47, - "linkPersonToEmailConfirmation": m48, + "linkPersonToEmail": m48, + "linkPersonToEmailConfirmation": m49, "livePhotos": MessageLookupByLibrary.simpleMessage("Fotos Em Tempo Real"), "loadMessage1": MessageLookupByLibrary.simpleMessage( @@ -1276,7 +1281,7 @@ class MessageLookup extends MessageLookupByLibrary { "moveToAlbum": MessageLookupByLibrary.simpleMessage("Mover para álbum"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Mover para álbum oculto"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("Mover para o lixo"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1331,10 +1336,10 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Nenhum resultado"), "noResultsFound": MessageLookupByLibrary.simpleMessage( "Não foram encontrados resultados"), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage( "Nenhum bloqueio de sistema encontrado"), - "notPersonLabel": m53, + "notPersonLabel": m54, "notThisPerson": MessageLookupByLibrary.simpleMessage("Não é esta pessoa?"), "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( @@ -1350,7 +1355,7 @@ class MessageLookup extends MessageLookupByLibrary { "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("Apenas eles"), "oops": MessageLookupByLibrary.simpleMessage("Oops"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( @@ -1381,7 +1386,7 @@ class MessageLookup extends MessageLookupByLibrary { "pairingComplete": MessageLookupByLibrary.simpleMessage("Emparelhamento concluído"), "panorama": MessageLookupByLibrary.simpleMessage("Panorama"), - "partyWithThem": m55, + "partyWithThem": m56, "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage( "A verificação ainda está pendente"), "passkey": MessageLookupByLibrary.simpleMessage("Chave de acesso"), @@ -1392,7 +1397,7 @@ class MessageLookup extends MessageLookupByLibrary { "Palavra-passe alterada com sucesso"), "passwordLock": MessageLookupByLibrary.simpleMessage("Bloqueio da palavra-passe"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "A força da palavra-passe é calculada tendo em conta o comprimento da palavra-passe, os caracteres utilizados e se a palavra-passe aparece ou não nas 10.000 palavras-passe mais utilizadas"), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -1403,7 +1408,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("O pagamento falhou"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Infelizmente o seu pagamento falhou. Entre em contato com o suporte e nós ajudaremos você!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("Itens pendentes"), "pendingSync": MessageLookupByLibrary.simpleMessage("Sincronização pendente"), @@ -1416,21 +1421,21 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Eliminar permanentemente"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage( "Apagar permanentemente do dispositivo?"), - "personIsAge": m58, + "personIsAge": m59, "personName": MessageLookupByLibrary.simpleMessage("Nome da pessoa"), - "personTurningAge": m59, + "personTurningAge": m60, "pets": MessageLookupByLibrary.simpleMessage("Companhia de pelos"), "photoDescriptions": MessageLookupByLibrary.simpleMessage("Descrições das fotos"), "photoGridSize": MessageLookupByLibrary.simpleMessage("Tamanho da grelha de fotos"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("foto"), - "photocountPhotos": m60, + "photocountPhotos": m61, "photos": MessageLookupByLibrary.simpleMessage("Fotos"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage( "As fotos adicionadas por si serão removidas do álbum"), - "photosCount": m61, + "photosCount": m62, "photosKeepRelativeTimeDifference": MessageLookupByLibrary.simpleMessage( "As fotos mantêm a diferença de tempo relativo"), @@ -1442,7 +1447,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Reproduzir álbum na TV"), "playOriginal": MessageLookupByLibrary.simpleMessage("Reproduzir original"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playStream": MessageLookupByLibrary.simpleMessage("Reproduzir transmissão"), "playstoreSubscription": @@ -1456,14 +1461,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Por favor, contate o suporte se o problema persistir"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage( "Por favor, conceda as permissões"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage( "Por favor, inicie sessão novamente"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Selecione links rápidos para remover"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Por favor, tente novamente"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1478,7 +1483,7 @@ class MessageLookup extends MessageLookupByLibrary { "Por favor, aguarde algum tempo antes de tentar novamente"), "pleaseWaitThisWillTakeAWhile": MessageLookupByLibrary.simpleMessage( "Aguarde um pouco, isso talvez leve um tempo."), - "posingWithThem": m65, + "posingWithThem": m66, "preparingLogs": MessageLookupByLibrary.simpleMessage("Preparando logs..."), "preserveMore": MessageLookupByLibrary.simpleMessage("Preservar mais"), @@ -1496,7 +1501,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Partilha privada"), "proceed": MessageLookupByLibrary.simpleMessage("Continuar"), "processing": MessageLookupByLibrary.simpleMessage("Processando"), - "processingImport": m66, + "processingImport": m67, "processingVideos": MessageLookupByLibrary.simpleMessage("Processando vídeos"), "publicLinkCreated": @@ -1509,11 +1514,13 @@ class MessageLookup extends MessageLookupByLibrary { "raiseTicket": MessageLookupByLibrary.simpleMessage("Abrir ticket"), "rateTheApp": MessageLookupByLibrary.simpleMessage("Avaliar aplicação"), "rateUs": MessageLookupByLibrary.simpleMessage("Avalie-nos"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "reassignMe": MessageLookupByLibrary.simpleMessage("Reatribuir \"Eu\""), - "reassignedToName": m68, + "reassignedToName": m69, "reassigningLoading": MessageLookupByLibrary.simpleMessage("Reatribuindo..."), + "receiveRemindersOnBirthdays": MessageLookupByLibrary.simpleMessage( + "Receive reminders when it\'s someone\'s birthday. Tapping on the notification will take you to photos of the birthday person."), "recover": MessageLookupByLibrary.simpleMessage("Recuperar"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Recuperar conta"), @@ -1522,7 +1529,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Recuperar conta"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage("A recuperação iniciou"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("Chave de recuperação"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( @@ -1537,12 +1544,12 @@ class MessageLookup extends MessageLookupByLibrary { "Chave de recuperação verificada"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "A sua chave de recuperação é a única forma de recuperar as suas fotografias se se esquecer da sua palavra-passe. Pode encontrar a sua chave de recuperação em Definições > Conta.\n\n\nIntroduza aqui a sua chave de recuperação para verificar se a guardou corretamente."), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage("Recuperação bem sucedida!"), "recoveryWarning": MessageLookupByLibrary.simpleMessage( "Um contato confiável está tentando acessar sua conta"), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "O dispositivo atual não é suficientemente poderoso para verificar a palavra-passe, mas podemos regenerar novamente de uma maneira que funcione no seu dispositivo.\n\nPor favor, iniciar sessão utilizando código de recuperação e gerar novamente a sua palavra-passe (pode utilizar a mesma se quiser)."), "recreatePasswordTitle": @@ -1558,7 +1565,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Envie este código aos seus amigos"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Eles se inscrevem em um plano pago"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("Referências"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "As referências estão atualmente em pausa"), @@ -1587,7 +1594,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Remover link"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Remover participante"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Remover etiqueta da pessoa"), "removePublicLink": @@ -1607,7 +1614,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("Renomear arquivo"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Renovar subscrição"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Reporte um bug"), "reportBug": MessageLookupByLibrary.simpleMessage("Reportar bug"), "resendEmail": MessageLookupByLibrary.simpleMessage("Reenviar e-mail"), @@ -1632,7 +1639,7 @@ class MessageLookup extends MessageLookupByLibrary { "reviewSuggestions": MessageLookupByLibrary.simpleMessage("Revisar sugestões"), "right": MessageLookupByLibrary.simpleMessage("Direita"), - "roadtripWithThem": m75, + "roadtripWithThem": m76, "rotate": MessageLookupByLibrary.simpleMessage("Rodar"), "rotateLeft": MessageLookupByLibrary.simpleMessage("Rodar para a esquerda"), @@ -1686,8 +1693,8 @@ class MessageLookup extends MessageLookupByLibrary { "Fotos de grupo que estão sendo tiradas em algum raio da foto"), "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage( "Convide pessoas e verá todas as fotos partilhadas por elas aqui"), - "searchResultCount": m76, - "searchSectionsLengthMismatch": m77, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("Segurança"), "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage( "Ver links de álbum compartilhado no aplicativo"), @@ -1737,9 +1744,9 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeRemovedFromThisPerson": MessageLookupByLibrary.simpleMessage( "Os itens selecionados serão removidos desta pessoa, entretanto não serão excluídos da sua biblioteca."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, - "selfiesWithThem": m80, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, + "selfiesWithThem": m82, "send": MessageLookupByLibrary.simpleMessage("Enviar"), "sendEmail": MessageLookupByLibrary.simpleMessage("Enviar email"), "sendInvite": MessageLookupByLibrary.simpleMessage("Enviar convite"), @@ -1770,16 +1777,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Partilhar um álbum"), "shareLink": MessageLookupByLibrary.simpleMessage("Partilhar link"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Partilhar apenas com as pessoas que deseja"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Descarregue o Ente para poder partilhar facilmente fotografias e vídeos de qualidade original\n\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Compartilhar com usuários que não usam Ente"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage( "Partilhe o seu primeiro álbum"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1792,7 +1799,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Novas fotos partilhadas"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "Receber notificações quando alguém adiciona uma foto a um álbum partilhado do qual faz parte"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Partilhado comigo"), "sharedWithYou": @@ -1811,11 +1818,11 @@ class MessageLookup extends MessageLookupByLibrary { "Terminar a sessão noutros dispositivos"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Eu concordo com os termos de serviço e política de privacidade"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "Será eliminado de todos os álbuns."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("Pular"), "social": MessageLookupByLibrary.simpleMessage("Social"), "someItemsAreInBothEnteAndYourDevice": @@ -1853,8 +1860,8 @@ class MessageLookup extends MessageLookupByLibrary { "sortOldestFirst": MessageLookupByLibrary.simpleMessage("Mais antigos primeiro"), "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ Sucesso"), - "sportsWithThem": m89, - "spotlightOnThem": m90, + "sportsWithThem": m91, + "spotlightOnThem": m92, "spotlightOnYourself": MessageLookupByLibrary.simpleMessage("Destacar si mesmo"), "startAccountRecoveryTitle": @@ -1869,15 +1876,15 @@ class MessageLookup extends MessageLookupByLibrary { "storage": MessageLookupByLibrary.simpleMessage("Armazenamento"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Família"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Tu"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage( "Limite de armazenamento excedido"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "streamDetails": MessageLookupByLibrary.simpleMessage("Detalhes da transmissão"), "strongStrength": MessageLookupByLibrary.simpleMessage("Forte"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("Subscrever"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "Você precisa de uma assinatura paga ativa para ativar o compartilhamento."), @@ -1895,7 +1902,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Sugerir recursos"), "sunrise": MessageLookupByLibrary.simpleMessage("No horizonte"), "support": MessageLookupByLibrary.simpleMessage("Suporte"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("Sincronização interrompida"), "syncing": MessageLookupByLibrary.simpleMessage("Sincronizando..."), @@ -1907,7 +1914,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Toque para desbloquear"), "tapToUpload": MessageLookupByLibrary.simpleMessage("Toque para enviar"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Parece que algo correu mal. Por favor, tente novamente mais tarde. Se o erro persistir, entre em contacto com a nossa equipa de suporte."), "terminate": MessageLookupByLibrary.simpleMessage("Terminar"), @@ -1930,7 +1937,7 @@ class MessageLookup extends MessageLookupByLibrary { "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage( "Estes itens serão eliminados do seu dispositivo."), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage( "Serão eliminados de todos os álbuns."), "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( @@ -1948,12 +1955,12 @@ class MessageLookup extends MessageLookupByLibrary { "Esta imagem não tem dados exif"), "thisIsMeExclamation": MessageLookupByLibrary.simpleMessage("Este é você!"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( "Este é o seu ID de verificação"), "thisWeekThroughTheYears": MessageLookupByLibrary.simpleMessage( "Esta semana com o passar dos anos"), - "thisWeekXYearsAgo": m99, + "thisWeekXYearsAgo": m101, "thisWillLogYouOutOfTheFollowingDevice": MessageLookupByLibrary.simpleMessage( "Irá desconectar a sua conta do seguinte dispositivo:"), @@ -1965,7 +1972,7 @@ class MessageLookup extends MessageLookupByLibrary { "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( "Isto removerá links públicos de todos os links rápidos selecionados."), - "throughTheYears": m100, + "throughTheYears": m102, "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": MessageLookupByLibrary.simpleMessage( "Para ativar o bloqueio de aplicações, configure o código de acesso do dispositivo ou o bloqueio de ecrã nas definições do sistema."), @@ -1979,13 +1986,13 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("total"), "totalSize": MessageLookupByLibrary.simpleMessage("Tamanho total"), "trash": MessageLookupByLibrary.simpleMessage("Lixo"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("Cortar"), - "tripInYear": m102, - "tripToLocation": m103, + "tripInYear": m104, + "tripToLocation": m105, "trustedContacts": MessageLookupByLibrary.simpleMessage("Contatos confiáveis"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("Tente novamente"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "Ative o backup para enviar automaticamente arquivos adicionados a esta pasta do dispositivo para o Ente."), @@ -2004,7 +2011,7 @@ class MessageLookup extends MessageLookupByLibrary { "Autenticação de dois fatores redefinida com êxito"), "twofactorSetup": MessageLookupByLibrary.simpleMessage( "Configuração de dois fatores"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("Desarquivar"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("Desarquivar álbum"), @@ -2027,10 +2034,10 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage( "Atualizando seleção de pasta..."), "upgrade": MessageLookupByLibrary.simpleMessage("Atualizar"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Enviar ficheiros para o álbum..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage("Preservar 1 memória..."), "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( @@ -2048,7 +2055,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("Utilizar foto selecionada"), "usedSpace": MessageLookupByLibrary.simpleMessage("Espaço utilizado"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Falha na verificação, por favor tente novamente"), @@ -2056,7 +2063,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("ID de Verificação"), "verify": MessageLookupByLibrary.simpleMessage("Verificar"), "verifyEmail": MessageLookupByLibrary.simpleMessage("Verificar email"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Verificar"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("Verificar chave de acesso"), @@ -2097,16 +2104,17 @@ class MessageLookup extends MessageLookupByLibrary { "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "Não suportamos a edição de fotos e álbuns que ainda não possui"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Fraca"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Bem-vindo(a) de volta!"), "whatsNew": MessageLookupByLibrary.simpleMessage("O que há de novo"), "whyAddTrustContact": MessageLookupByLibrary.simpleMessage( "Um contato confiável pode ajudá-lo em recuperar seus dados."), + "wishThemAHappyBirthday": m115, "yearShort": MessageLookupByLibrary.simpleMessage("ano"), "yearly": MessageLookupByLibrary.simpleMessage("Anual"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Sim"), "yesCancel": MessageLookupByLibrary.simpleMessage("Sim, cancelar"), "yesConvertToViewer": MessageLookupByLibrary.simpleMessage( @@ -2121,7 +2129,7 @@ class MessageLookup extends MessageLookupByLibrary { "yesResetPerson": MessageLookupByLibrary.simpleMessage("Sim, repor pessoa"), "you": MessageLookupByLibrary.simpleMessage("Tu"), - "youAndThem": m114, + "youAndThem": m117, "youAreOnAFamilyPlan": MessageLookupByLibrary.simpleMessage( "Você está em um plano familiar!"), "youAreOnTheLatestVersion": MessageLookupByLibrary.simpleMessage( @@ -2140,7 +2148,7 @@ class MessageLookup extends MessageLookupByLibrary { "Não podes partilhar contigo mesmo"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( "Não tem nenhum item arquivado."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("A sua conta foi eliminada"), "yourMap": MessageLookupByLibrary.simpleMessage("Seu mapa"), diff --git a/mobile/lib/generated/intl/messages_pt_BR.dart b/mobile/lib/generated/intl/messages_pt_BR.dart index 92c8fc258e..59a7836b17 100644 --- a/mobile/lib/generated/intl/messages_pt_BR.dart +++ b/mobile/lib/generated/intl/messages_pt_BR.dart @@ -82,242 +82,248 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'Excluir ${count} item', other: 'Excluir ${count} itens')}"; - static String m22(currentlyDeleting, totalCount) => + static String m22(count) => + "E também excluir todas as fotos (e vídeos) presente dentro desses ${count} álbuns e de todos os álbuns que eles fazem parte?"; + + static String m23(currentlyDeleting, totalCount) => "Excluindo ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "Isso removerá o link público para acessar \"${albumName}\"."; - static String m24(supportEmail) => - "Envie um e-mail para ${supportEmail} a partir do seu endereço de e-mail registrado"; + static String m25(supportEmail) => + "Envie um e-mail para ${supportEmail} a partir do e-mail registrado"; - static String m25(count, storageSaved) => + static String m26(count, storageSaved) => "Você limpou ${Intl.plural(count, one: '${count} arquivo duplicado', other: '${count} arquivos duplicados')}, salvando (${storageSaved}!)"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} arquivos, ${formattedSize} cada"; - static String m27(name) => "Este e-mail já está vinculado a ${name}."; + static String m28(name) => "Este e-mail já está vinculado a ${name}."; - static String m28(newEmail) => "E-mail alterado para ${newEmail}"; + static String m29(newEmail) => "E-mail alterado para ${newEmail}"; - static String m29(email) => "${email} não possui uma conta Ente."; + static String m30(email) => "${email} não possui uma conta Ente."; - static String m30(email) => + static String m31(email) => "${email} não tem uma conta Ente.\n\nEnvie-os um convite para compartilhar fotos."; - static String m31(name) => "Abraçando ${name}"; + static String m32(name) => "Abraçando ${name}"; - static String m32(text) => "Fotos adicionais encontradas para ${text}"; + static String m33(text) => "Fotos adicionais encontradas para ${text}"; - static String m33(name) => "Tendo banquete com ${name}"; - - static String m34(count, formattedNumber) => - "${Intl.plural(count, one: '1 arquivo', other: '${formattedNumber} arquivos')} deste dispositivo foi copiado com segurança"; + static String m34(name) => "Tendo banquete com ${name}"; static String m35(count, formattedNumber) => - "${Intl.plural(count, one: '1 arquivo', other: '${formattedNumber} arquivos')} deste álbum foi copiado com segurança"; + "${Intl.plural(count, one: '1 arquivo', other: '${formattedNumber} arquivos')} deste dispositivo foi(ram) salvos em segurança"; - static String m36(storageAmountInGB) => - "${storageAmountInGB} GB cada vez que alguém se inscrever a um plano pago e aplicar seu código"; + static String m36(count, formattedNumber) => + "${Intl.plural(count, one: '1 arquivo', other: '${formattedNumber} arquivos')} deste álbum foi(ram) salvo(s) em segurança"; - static String m37(endDate) => "A avaliação grátis acaba em ${endDate}"; + static String m37(storageAmountInGB) => + "${storageAmountInGB} GB toda vez que alguém utilizar seu código num plano pago"; - static String m38(count) => + static String m38(endDate) => "A avaliação grátis acaba em ${endDate}"; + + static String m39(count) => "Você ainda pode acessá${Intl.plural(count, one: '-lo', other: '-los')} no Ente se você tiver uma assinatura ativa"; - static String m39(sizeInMBorGB) => "Liberar ${sizeInMBorGB}"; + static String m40(sizeInMBorGB) => "Liberar ${sizeInMBorGB}"; - static String m40(count, formattedSize) => - "${Intl.plural(count, one: 'Ele pode excluído para liberar ${formattedSize}', other: 'Eles podem ser excluídos do dispositivo para liberar ${formattedSize}')}"; + static String m41(count, formattedSize) => + "${Intl.plural(count, one: 'Ele pode excluído do dispositivo para liberar ${formattedSize}', other: 'Eles podem ser excluídos do dispositivo para liberar ${formattedSize}')}"; - static String m41(currentlyProcessing, totalCount) => + static String m42(currentlyProcessing, totalCount) => "Processando ${currentlyProcessing} / ${totalCount}"; - static String m42(name) => "Caminhando com ${name}"; + static String m43(name) => "Caminhando com ${name}"; - static String m43(count) => + static String m44(count) => "${Intl.plural(count, one: '${count} item', other: '${count} itens')}"; - static String m44(name) => "Últimos momentos com ${name}"; + static String m45(name) => "Últimos momentos com ${name}"; - static String m45(email) => + static String m46(email) => "${email} convidou você para ser um contato confiável"; - static String m46(expiryTime) => "O link expirará em ${expiryTime}"; + static String m47(expiryTime) => "O link expirará em ${expiryTime}"; - static String m47(email) => "Vincular pessoa a ${email}"; + static String m48(email) => "Vincular pessoa a ${email}"; - static String m48(personName, email) => + static String m49(personName, email) => "Isso vinculará ${personName} a ${email}"; - static String m49(count, formattedCount) => + static String m50(count, formattedCount) => "${Intl.plural(count, zero: 'sem memórias', one: '${formattedCount} memória', other: '${formattedCount} memórias')}"; - static String m50(count) => + static String m51(count) => "${Intl.plural(count, one: 'Mover item', other: 'Mover itens')}"; - static String m51(albumName) => "Movido com sucesso para ${albumName}"; + static String m52(albumName) => "Movido com sucesso para ${albumName}"; - static String m52(personName) => "Sem sugestões para ${personName}"; + static String m53(personName) => "Sem sugestões para ${personName}"; - static String m53(name) => "Não é ${name}?"; + static String m54(name) => "Não é ${name}?"; - static String m54(familyAdminEmail) => + static String m55(familyAdminEmail) => "Entre em contato com ${familyAdminEmail} para alterar o seu código."; - static String m55(name) => "Festejando com ${name}"; + static String m56(name) => "Festejando com ${name}"; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Força da senha: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "Fale com o suporte ${providerName} se você foi cobrado"; - static String m58(name, age) => "${name} tem ${age} anos!"; + static String m59(name, age) => "${name} tem ${age} anos!"; - static String m59(name, age) => "${name} terá ${age} em breve"; - - static String m60(count) => - "${Intl.plural(count, zero: 'Sem fotos', one: '1 foto', other: '${count} fotos')}"; + static String m60(name, age) => "${name} terá ${age} em breve"; static String m61(count) => + "${Intl.plural(count, zero: 'Sem fotos', one: '1 foto', other: '${count} fotos')}"; + + static String m62(count) => "${Intl.plural(count, zero: '0 fotos', one: '1 foto', other: '${count} fotos')}"; - static String m62(endDate) => + static String m63(endDate) => "Avaliação grátis válida até ${endDate}.\nVocê pode alterar para um plano pago depois."; - static String m63(toEmail) => "Envie-nos um e-mail para ${toEmail}"; + static String m64(toEmail) => "Envie-nos um e-mail para ${toEmail}"; - static String m64(toEmail) => "Envie os registros para \n${toEmail}"; + static String m65(toEmail) => "Envie os registros para \n${toEmail}"; - static String m65(name) => "Fazendo pose com ${name}"; + static String m66(name) => "Fazendo pose com ${name}"; - static String m66(folderName) => "Processando ${folderName}..."; + static String m67(folderName) => "Processando ${folderName}..."; - static String m67(storeName) => "Avalie-nos no ${storeName}"; + static String m68(storeName) => "Avalie-nos no ${storeName}"; - static String m68(name) => "Atribuído a ${name}"; + static String m69(name) => "Atribuído a ${name}"; - static String m69(days, email) => + static String m70(days, email) => "Você poderá acessar a conta após ${days} dias. Uma notificação será enviada para ${email}."; - static String m70(email) => + static String m71(email) => "Você pode recuperar a conta com e-mail ${email} por definir uma nova senha."; - static String m71(email) => "${email} está tentando recuperar sua conta."; + static String m72(email) => "${email} está tentando recuperar sua conta."; - static String m72(storageInGB) => - "3. Ambos os dois ganham ${storageInGB} GB* grátis"; + static String m73(storageInGB) => "3. Ambos ganham ${storageInGB} GB* grátis"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} será removido do álbum compartilhado\n\nQualquer foto adicionada por ele será removida."; - static String m74(endDate) => "Renovação de assinatura em ${endDate}"; + static String m75(endDate) => "Renovação de assinatura em ${endDate}"; - static String m75(name) => "Viajando de carro com ${name}"; + static String m76(name) => "Viajando de carro com ${name}"; - static String m76(count) => + static String m77(count) => "${Intl.plural(count, one: '${count} resultado encontrado', other: '${count} resultados encontrados')}"; - static String m77(snapshotLength, searchLength) => + static String m78(snapshotLength, searchLength) => "Incompatibilidade de comprimento de seções: ${snapshotLength} != ${searchLength}"; - static String m78(count) => "${count} selecionado(s)"; + static String m79(count) => "${count} selecionado(s)"; - static String m79(count, yourCount) => + static String m80(count) => "${count} selecionado(s)"; + + static String m81(count, yourCount) => "${count} selecionado(s) (${yourCount} seus)"; - static String m80(name) => "Tirando selfies com ${name}"; + static String m82(name) => "Tirando selfies com ${name}"; - static String m81(verificationID) => + static String m83(verificationID) => "Aqui está meu ID de verificação para o ente.io: ${verificationID}"; - static String m82(verificationID) => + static String m84(verificationID) => "Ei, você pode confirmar se este ID de verificação do ente.io é seu?: ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => - "Código de referência do Ente: ${referralCode} \n\nAplique-o em Configurações → Geral → Referências para obter ${referralStorageInGB} GB grátis após a sua inscrição num plano pago\n\nhttps://ente.io"; + static String m85(referralCode, referralStorageInGB) => + "Código de referência Ente: ${referralCode} \n\nAplique-o em Opções → Geral → Referências para obter ${referralStorageInGB} GB grátis após a inscrição num plano pago\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Compartilhe com pessoas específicas', one: 'Compartilhado com 1 pessoa', other: 'Compartilhado com ${numberOfPeople} pessoas')}"; - static String m85(emailIDs) => "Compartilhado com ${emailIDs}"; + static String m87(emailIDs) => "Compartilhado com ${emailIDs}"; - static String m86(fileType) => + static String m88(fileType) => "Este ${fileType} será excluído do dispositivo."; - static String m87(fileType) => + static String m89(fileType) => "Este ${fileType} está no Ente e em seu dispositivo."; - static String m88(fileType) => "Este ${fileType} será excluído do Ente."; + static String m90(fileType) => "Este ${fileType} será excluído do Ente."; - static String m89(name) => "Jogando esportes com ${name}"; + static String m91(name) => "Jogando esportes com ${name}"; - static String m90(name) => "Destacar ${name}"; + static String m92(name) => "Destacar ${name}"; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} de ${totalAmount} ${totalStorageUnit} usado"; - static String m93(id) => + static String m95(id) => "Seu ${id} já está vinculado a outra conta Ente. Se você gostaria de usar seu ${id} com esta conta, entre em contato conosco\""; - static String m94(endDate) => "Sua assinatura será cancelada em ${endDate}"; + static String m96(endDate) => "Sua assinatura será cancelada em ${endDate}"; - static String m95(completed, total) => + static String m97(completed, total) => "${completed}/${total} memórias preservadas"; - static String m96(ignoreReason) => + static String m98(ignoreReason) => "Toque para enviar, atualmente o envio é ignorado devido a ${ignoreReason}"; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "Eles também recebem ${storageAmountInGB} GB"; - static String m98(email) => "Este é o ID de verificação de ${email}"; - - static String m99(count) => - "${Intl.plural(count, one: 'Esta semana, ${count} ano atrás', other: 'Esta semana, ${count} anos atrás')}"; - - static String m100(dateFormat) => "${dateFormat} com o passar dos anos"; + static String m100(email) => "Este é o ID de verificação de ${email}"; static String m101(count) => + "${Intl.plural(count, one: 'Esta semana, ${count} ano atrás', other: 'Esta semana, ${count} anos atrás')}"; + + static String m102(dateFormat) => "${dateFormat} com o passar dos anos"; + + static String m103(count) => "${Intl.plural(count, zero: 'Em breve', one: '1 dia', other: '${count} dias')}"; - static String m102(year) => "Viajem em ${year}"; + static String m104(year) => "Viajem em ${year}"; - static String m103(location) => "Viajem à ${location}"; + static String m105(location) => "Viajem à ${location}"; - static String m104(email) => + static String m106(email) => "Você foi convidado para ser um contato legado por ${email}."; - static String m105(galleryType) => + static String m107(galleryType) => "O tipo de galeria ${galleryType} não é suportado para renomear"; - static String m106(ignoreReason) => + static String m108(ignoreReason) => "O envio é ignorado devido a ${ignoreReason}"; - static String m107(count) => "Preservando ${count} memórias..."; + static String m109(count) => "Preservando ${count} memórias..."; - static String m108(endDate) => "Válido até ${endDate}"; + static String m110(endDate) => "Válido até ${endDate}"; - static String m109(email) => "Verificar ${email}"; + static String m111(email) => "Verificar ${email}"; - static String m110(name) => "Visualizar ${name} para desvincular"; - - static String m111(count) => - "${Intl.plural(count, zero: 'Adicionado 0 vizualizadores', one: 'Adicionado 1 visualizador', other: 'Adicionado ${count} visualizadores')}"; - - static String m112(email) => "Enviamos um e-mail à ${email}"; + static String m112(name) => "Visualizar ${name} para desvincular"; static String m113(count) => + "${Intl.plural(count, zero: 'Adicionado 0 vizualizadores', one: 'Adicionado 1 visualizador', other: 'Adicionado ${count} visualizadores')}"; + + static String m114(email) => "Enviamos um e-mail à ${email}"; + + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + + static String m116(count) => "${Intl.plural(count, one: '${count} ano atrás', other: '${count} anos atrás')}"; - static String m114(name) => "Você e ${name}"; + static String m117(name) => "Você e ${name}"; - static String m115(storageSaved) => + static String m118(storageSaved) => "Você liberou ${storageSaved} com sucesso!"; final messages = _notInlinedMessages(_notInlinedMessages); @@ -335,12 +341,17 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Bem-vindo(a) de volta!"), "ackPasswordLostWarning": MessageLookupByLibrary.simpleMessage( "Eu entendo que se eu perder minha senha, posso perder meus dados, já que meus dados são criptografados de ponta a ponta."), + "actionNotSupportedOnFavouritesAlbum": + MessageLookupByLibrary.simpleMessage( + "Ação não suportada em álbum favorito"), "activeSessions": MessageLookupByLibrary.simpleMessage("Sessões ativas"), "add": MessageLookupByLibrary.simpleMessage("Adicionar"), "addAName": MessageLookupByLibrary.simpleMessage("Adicione um nome"), "addANewEmail": MessageLookupByLibrary.simpleMessage("Adicionar um novo e-mail"), + "addAlbumWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Adicione um widget de álbum a sua tela inicial e volte aqui para personalizar."), "addCollaborator": MessageLookupByLibrary.simpleMessage("Adicionar colaborador"), "addCollaborators": m1, @@ -351,6 +362,8 @@ class MessageLookup extends MessageLookupByLibrary { "addLocation": MessageLookupByLibrary.simpleMessage("Adicionar localização"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Adicionar"), + "addMemoriesWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Adicione um widget de memória a sua tela inicial e volte aqui para personalizar."), "addMore": MessageLookupByLibrary.simpleMessage("Adicionar mais"), "addName": MessageLookupByLibrary.simpleMessage("Adicionar pessoa"), "addNameOrMerge": @@ -362,6 +375,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Detalhes dos complementos"), "addOnValidTill": m3, "addOns": MessageLookupByLibrary.simpleMessage("Complementos"), + "addParticipants": + MessageLookupByLibrary.simpleMessage("Adicionar participante"), + "addPeopleWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Adicione um widget de pessoas a sua tela inicial e volte aqui para personalizar."), "addPhotos": MessageLookupByLibrary.simpleMessage("Adicionar fotos"), "addSelected": MessageLookupByLibrary.simpleMessage("Adicionar selecionado"), @@ -396,6 +413,8 @@ class MessageLookup extends MessageLookupByLibrary { "albumUpdated": MessageLookupByLibrary.simpleMessage("Álbum atualizado"), "albums": MessageLookupByLibrary.simpleMessage("Álbuns"), + "albumsWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Selecione os álbuns que deseje vê-los na sua tela inicial."), "allClear": MessageLookupByLibrary.simpleMessage("✨ Tudo limpo"), "allMemoriesPreserved": MessageLookupByLibrary.simpleMessage( "Todas as memórias preservadas"), @@ -415,7 +434,7 @@ class MessageLookup extends MessageLookupByLibrary { "allowPeopleToAddPhotos": MessageLookupByLibrary.simpleMessage( "Permitir que pessoas adicionem fotos"), "allowPermBody": MessageLookupByLibrary.simpleMessage( - "Permita o acesso a suas fotos das Configurações para que Ente possa exibir e copiar com segurança sua biblioteca."), + "Permita o acesso a suas fotos nas Opções para que Ente exiba e salva em segurança sua fototeca."), "allowPermTitle": MessageLookupByLibrary.simpleMessage("Permita acesso às Fotos"), "androidBiometricHint": @@ -449,7 +468,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Aplicar código"), "appstoreSubscription": MessageLookupByLibrary.simpleMessage("Assinatura da AppStore"), - "archive": MessageLookupByLibrary.simpleMessage("Arquive"), + "archive": MessageLookupByLibrary.simpleMessage("Arquivo"), "archiveAlbum": MessageLookupByLibrary.simpleMessage("Arquivar álbum"), "archiving": MessageLookupByLibrary.simpleMessage("Arquivando..."), "areYouSureThatYouWantToLeaveTheFamily": @@ -526,29 +545,56 @@ class MessageLookup extends MessageLookupByLibrary { "O pareamento automático só funciona com dispositivos que suportam o Chromecast."), "available": MessageLookupByLibrary.simpleMessage("Disponível"), "availableStorageSpace": m10, - "backedUpFolders": MessageLookupByLibrary.simpleMessage( - "Pastas copiadas com segurança"), + "backedUpFolders": + MessageLookupByLibrary.simpleMessage("Pastas salvas em segurança"), "backgroundWithThem": m11, - "backup": MessageLookupByLibrary.simpleMessage("Cópia de segurança"), + "backup": MessageLookupByLibrary.simpleMessage("Salvar em segurança"), "backupFailed": MessageLookupByLibrary.simpleMessage( - "Falhou ao copiar com segurança"), - "backupFile": MessageLookupByLibrary.simpleMessage( - "Copiar arquivo com segurança"), + "Falhou ao salvar em segurança"), + "backupFile": + MessageLookupByLibrary.simpleMessage("Salvar arquivo em segurança"), "backupOverMobileData": MessageLookupByLibrary.simpleMessage( - "Salvamento com segurança usando dados móveis"), + "Salvar fotos com dados móveis"), "backupSettings": MessageLookupByLibrary.simpleMessage( - "Opções de cópia de segurança"), - "backupStatus": MessageLookupByLibrary.simpleMessage( - "Status da cópia de segurança"), + "Ajustes de salvar em segurança"), + "backupStatus": + MessageLookupByLibrary.simpleMessage("Estado das mídias salvas"), "backupStatusDescription": MessageLookupByLibrary.simpleMessage( - "Os itens que foram salvos com segurança aparecerão aqui"), - "backupVideos": MessageLookupByLibrary.simpleMessage( - "Cópia de segurança de vídeos"), + "Os itens salvos em segurança aparecerão aqui"), + "backupVideos": + MessageLookupByLibrary.simpleMessage("Salvar vídeos em segurança"), "beach": MessageLookupByLibrary.simpleMessage("Areia e o mar"), "birthday": MessageLookupByLibrary.simpleMessage("Aniversário"), + "birthdayNotifications": + MessageLookupByLibrary.simpleMessage("Notificações de aniversário"), + "birthdays": MessageLookupByLibrary.simpleMessage("Aniversários"), "blackFridaySale": MessageLookupByLibrary.simpleMessage("Promoção Black Friday"), "blog": MessageLookupByLibrary.simpleMessage("Blog"), + "cLDesc1": MessageLookupByLibrary.simpleMessage( + "Com a versão beta de streaming de vídeo e o trabalho em uploads e downloads resumíveis, agora aumentamos o limite de upload de arquivos para 10GB. Isso já está disponível nos aplicativos desktop e móvel."), + "cLDesc2": MessageLookupByLibrary.simpleMessage( + "Os uploads em segundo plano agora também são suportados no iOS, além dos dispositivos Android. Não é necessário abrir o aplicativo para fazer backup de suas fotos e vídeos mais recentes."), + "cLDesc3": MessageLookupByLibrary.simpleMessage( + "Fizemos melhorias significativas em nossa experiência de memórias, incluindo reprodução automática, deslizar para a próxima memória e muito mais."), + "cLDesc4": MessageLookupByLibrary.simpleMessage( + "Junto com várias melhorias internas, agora é muito mais fácil ver todos os rostos detectados, fornecer feedback sobre rostos similares e adicionar/remover rostos de uma única foto."), + "cLDesc5": MessageLookupByLibrary.simpleMessage( + "Agora você receberá uma notificação opcional para todos os aniversários que salvou no Ente, junto com uma coleção de suas melhores fotos."), + "cLDesc6": MessageLookupByLibrary.simpleMessage( + "Não é mais necessário esperar que uploads/downloads sejam concluídos antes de fechar o aplicativo. Todos os uploads e downloads agora podem ser pausados no meio do caminho e retomados de onde você parou."), + "cLTitle1": MessageLookupByLibrary.simpleMessage( + "Upload de arquivos de vídeo grandes"), + "cLTitle2": + MessageLookupByLibrary.simpleMessage("Upload em segundo plano"), + "cLTitle3": MessageLookupByLibrary.simpleMessage( + "Reprodução automática de memórias"), + "cLTitle4": MessageLookupByLibrary.simpleMessage( + "Reconhecimento facial aprimorado"), + "cLTitle5": + MessageLookupByLibrary.simpleMessage("Notificações de aniversário"), + "cLTitle6": MessageLookupByLibrary.simpleMessage( + "Uploads e downloads resumíveis"), "cachedData": MessageLookupByLibrary.simpleMessage("Dados armazenados em cache"), "calculating": MessageLookupByLibrary.simpleMessage("Calculando..."), @@ -618,7 +664,7 @@ class MessageLookup extends MessageLookupByLibrary { "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage("• Clique no menu adicional"), "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), + "Clique para instalar a nossa melhor versão até então"), "close": MessageLookupByLibrary.simpleMessage("Fechar"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage( "Agrupar por tempo de captura"), @@ -685,13 +731,13 @@ class MessageLookup extends MessageLookupByLibrary { "convertToAlbum": MessageLookupByLibrary.simpleMessage("Converter para álbum"), "copyEmailAddress": - MessageLookupByLibrary.simpleMessage("Copiar endereço de e-mail"), + MessageLookupByLibrary.simpleMessage("Copiar e-mail"), "copyLink": MessageLookupByLibrary.simpleMessage("Copiar link"), "copypasteThisCodentoYourAuthenticatorApp": MessageLookupByLibrary.simpleMessage( - "Copie e cole este código\npara o aplicativo autenticador"), + "Copie e cole o código no aplicativo autenticador"), "couldNotBackUpTryLater": MessageLookupByLibrary.simpleMessage( - "Nós não podemos copiar com segurança seus dados.\nNós tentaremos novamente mais tarde."), + "Nós não podemos salvar seus dados.\nNós tentaremos novamente mais tarde."), "couldNotFreeUpSpace": MessageLookupByLibrary.simpleMessage( "Não foi possível liberar espaço"), "couldNotUpdateSubscription": MessageLookupByLibrary.simpleMessage( @@ -750,7 +796,7 @@ class MessageLookup extends MessageLookupByLibrary { "deleteConfirmDialogBody": MessageLookupByLibrary.simpleMessage( "Esta conta está vinculada aos outros aplicativos do Ente, se você usar algum. Seus dados baixados, entre todos os aplicativos do Ente, serão programados para exclusão, e sua conta será permanentemente excluída."), "deleteEmailRequest": MessageLookupByLibrary.simpleMessage( - "Por favor, envie um e-mail a account-deletion@ente.io do seu endereço de e-mail registrado."), + "Por favor, envie um e-mail a account-deletion@ente.io do seu e-mail registrado."), "deleteEmptyAlbums": MessageLookupByLibrary.simpleMessage("Excluir álbuns vazios"), "deleteEmptyAlbumsWithQuestionMark": @@ -764,8 +810,9 @@ class MessageLookup extends MessageLookupByLibrary { "deleteItemCount": m21, "deleteLocation": MessageLookupByLibrary.simpleMessage("Excluir localização"), + "deleteMultipleAlbumDialog": m22, "deletePhotos": MessageLookupByLibrary.simpleMessage("Excluir fotos"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Está faltando um recurso-chave que eu preciso"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -783,7 +830,7 @@ class MessageLookup extends MessageLookupByLibrary { "deselectAll": MessageLookupByLibrary.simpleMessage("Deselecionar tudo"), "designedToOutlive": - MessageLookupByLibrary.simpleMessage("Feito para ter longevidade"), + MessageLookupByLibrary.simpleMessage("Feito para reviver memórias"), "details": MessageLookupByLibrary.simpleMessage("Detalhes"), "developerSettings": MessageLookupByLibrary.simpleMessage("Opções de desenvolvedor"), @@ -796,7 +843,7 @@ class MessageLookup extends MessageLookupByLibrary { "deviceLock": MessageLookupByLibrary.simpleMessage("Bloqueio do dispositivo"), "deviceLockExplanation": MessageLookupByLibrary.simpleMessage( - "Desativa o bloqueio de tela quando o Ente está de fundo e têm uma cópia de segurança sendo feita. Isso normalmente não é necessário, no entanto, ajuda a envios grandes e importações iniciais de bibliotecas maiores concluírem mais rápido."), + "Desativa o bloqueio de tela se o Ente estiver de fundo e uma cópia de segurança ainda estiver em andamento. Às vezes, isso não é necessário, mas ajuda a agilizar envios grandes e importações iniciais de bibliotecas maiores."), "deviceNotFound": MessageLookupByLibrary.simpleMessage("Dispositivo não encontrado"), "didYouKnow": MessageLookupByLibrary.simpleMessage("Você sabia?"), @@ -806,7 +853,7 @@ class MessageLookup extends MessageLookupByLibrary { "Os visualizadores podem fazer capturas de tela ou salvar uma cópia de suas fotos usando ferramentas externas"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Por favor, saiba que"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Desativar autenticação de dois fatores"), "disablingTwofactorAuthentication": @@ -850,11 +897,11 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("Falhou ao baixar"), "downloading": MessageLookupByLibrary.simpleMessage("Baixando..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("Editar"), - "editEmailAlreadyLinked": m27, + "editEmailAlreadyLinked": m28, "editLocation": MessageLookupByLibrary.simpleMessage("Editar localização"), "editLocationTagTitle": @@ -869,16 +916,16 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("E-mail"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage("E-mail já registrado."), - "emailChangedTo": m28, - "emailDoesNotHaveEnteAccount": m29, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailDoesNotHaveEnteAccount": m30, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage("E-mail não registrado."), "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("Verificação por e-mail"), "emailYourLogs": MessageLookupByLibrary.simpleMessage("Enviar registros por e-mail"), - "embracingThem": m31, + "embracingThem": m32, "emergencyContacts": MessageLookupByLibrary.simpleMessage("Contatos de emergência"), "empty": MessageLookupByLibrary.simpleMessage("Esvaziar"), @@ -894,7 +941,7 @@ class MessageLookup extends MessageLookupByLibrary { "Isso exibirá suas fotos em um mapa mundial.\n\nEste mapa é hospedado por Open Street Map, e as exatas localizações das fotos nunca serão compartilhadas.\n\nVocê pode desativar esta função a qualquer momento em Opções."), "enabled": MessageLookupByLibrary.simpleMessage("Ativado"), "encryptingBackup": MessageLookupByLibrary.simpleMessage( - "Criptografando cópia de segurança..."), + "Criptografando salvar em segurança..."), "encryption": MessageLookupByLibrary.simpleMessage("Criptografia"), "encryptionKeys": MessageLookupByLibrary.simpleMessage("Chaves de criptografia"), @@ -913,9 +960,9 @@ class MessageLookup extends MessageLookupByLibrary { "Sua família também poderá ser adicionada ao seu plano."), "enterAlbumName": MessageLookupByLibrary.simpleMessage("Inserir nome do álbum"), - "enterCode": MessageLookupByLibrary.simpleMessage("Insira o código"), + "enterCode": MessageLookupByLibrary.simpleMessage("Inserir código"), "enterCodeDescription": MessageLookupByLibrary.simpleMessage( - "Insira o código fornecido pelo seu amigo para reivindicar o armazenamento grátis para os dois"), + "Insira o código fornecido por um amigo para reivindicar armazenamento grátis para ambos"), "enterDateOfBirth": MessageLookupByLibrary.simpleMessage("Aniversário (opcional)"), "enterEmail": MessageLookupByLibrary.simpleMessage("Inserir e-mail"), @@ -934,11 +981,13 @@ class MessageLookup extends MessageLookupByLibrary { "Inserir código de referência"), "enterThe6digitCodeFromnyourAuthenticatorApp": MessageLookupByLibrary.simpleMessage( - "Digite o código de 6 dígitos do\naplicativo de autenticador"), - "enterValidEmail": MessageLookupByLibrary.simpleMessage( - "Insira um endereço de e-mail válido."), - "enterYourEmailAddress": MessageLookupByLibrary.simpleMessage( - "Insira seu endereço de e-mail"), + "Digite o código de 6 dígitos do\naplicativo autenticador"), + "enterValidEmail": + MessageLookupByLibrary.simpleMessage("Insira um e-mail válido."), + "enterYourEmailAddress": + MessageLookupByLibrary.simpleMessage("Insira seu e-mail"), + "enterYourNewEmailAddress": + MessageLookupByLibrary.simpleMessage("Insira seu novo e-mail"), "enterYourPassword": MessageLookupByLibrary.simpleMessage("Insira sua senha"), "enterYourRecoveryKey": MessageLookupByLibrary.simpleMessage( @@ -957,7 +1006,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Exportar dados"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage( "Fotos adicionais encontradas"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage( "Rosto não agrupado ainda, volte aqui mais tarde"), "faceRecognition": @@ -996,7 +1045,7 @@ class MessageLookup extends MessageLookupByLibrary { "faq": MessageLookupByLibrary.simpleMessage("Perguntas frequentes"), "faqs": MessageLookupByLibrary.simpleMessage("Perguntas frequentes"), "favorite": MessageLookupByLibrary.simpleMessage("Favorito"), - "feastingWithThem": m33, + "feastingWithThem": m34, "feedback": MessageLookupByLibrary.simpleMessage("Feedback"), "file": MessageLookupByLibrary.simpleMessage("Arquivo"), "fileFailedToSaveToGallery": MessageLookupByLibrary.simpleMessage( @@ -1010,8 +1059,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Tipos de arquivo"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Tipos de arquivo e nomes"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("Arquivos excluídos"), "filesSavedToGallery": @@ -1021,7 +1070,7 @@ class MessageLookup extends MessageLookupByLibrary { "findThemQuickly": MessageLookupByLibrary.simpleMessage("Busque-os rapidamente"), "flip": MessageLookupByLibrary.simpleMessage("Inverter"), - "food": MessageLookupByLibrary.simpleMessage("Amor por culinária"), + "food": MessageLookupByLibrary.simpleMessage("Delícias de cozinha"), "forYourMemories": MessageLookupByLibrary.simpleMessage("para suas memórias"), "forgotPassword": @@ -1030,26 +1079,26 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Rostos encontrados"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("Armaz. grátis reivindicado"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("Armazenamento disponível"), "freeTrial": MessageLookupByLibrary.simpleMessage("Avaliação grátis"), - "freeTrialValidTill": m37, - "freeUpAccessPostDelete": m38, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAccessPostDelete": m39, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage( "Liberar espaço no dispositivo"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Economize espaço em seu dispositivo por limpar arquivos já salvos com segurança."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Liberar espaço"), - "freeUpSpaceSaving": m40, + "freeUpSpaceSaving": m41, "gallery": MessageLookupByLibrary.simpleMessage("Galeria"), "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Até 1.000 memórias exibidas na galeria"), "general": MessageLookupByLibrary.simpleMessage("Geral"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Gerando chaves de criptografia..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("Ir às opções"), "googlePlayId": MessageLookupByLibrary.simpleMessage("ID do Google Play"), @@ -1063,6 +1112,8 @@ class MessageLookup extends MessageLookupByLibrary { "guestView": MessageLookupByLibrary.simpleMessage("Vista do convidado"), "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( "Para ativar a vista do convidado, defina uma senha de acesso no dispositivo ou bloqueie sua tela nas opções do sistema."), + "happyBirthday": + MessageLookupByLibrary.simpleMessage("Feliz aniversário! 🥳"), "hearUsExplanation": MessageLookupByLibrary.simpleMessage( "Não rastreamos instalações de aplicativo. Seria útil se você contasse onde nos encontrou!"), "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( @@ -1078,12 +1129,12 @@ class MessageLookup extends MessageLookupByLibrary { "hideSharedItemsFromHomeGallery": MessageLookupByLibrary.simpleMessage( "Ocultar itens compartilhados da galeria inicial"), "hiding": MessageLookupByLibrary.simpleMessage("Ocultando..."), - "hikingWithThem": m42, + "hikingWithThem": m43, "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("Hospedado em OSM France"), "howItWorks": MessageLookupByLibrary.simpleMessage("Como funciona"), "howToViewShareeVerificationID": MessageLookupByLibrary.simpleMessage( - "Peça-os para manterem pressionado no endereço de e-mail na tela de opções, e verifique-se os IDs de ambos os dispositivos correspondem."), + "Peça-os para pressionarem no e-mail a partir das Opções, e verifique-se os IDs de ambos os dispositivos correspondem."), "iOSGoToSettingsDescription": MessageLookupByLibrary.simpleMessage( "A autenticação biométrica não está definida no dispositivo. Ative o Touch ID ou Face ID no dispositivo."), "iOSLockOut": MessageLookupByLibrary.simpleMessage( @@ -1117,7 +1168,7 @@ class MessageLookup extends MessageLookupByLibrary { "installManually": MessageLookupByLibrary.simpleMessage("Instalar manualmente"), "invalidEmailAddress": - MessageLookupByLibrary.simpleMessage("Endereço de e-mail inválido"), + MessageLookupByLibrary.simpleMessage("E-mail inválido"), "invalidEndpoint": MessageLookupByLibrary.simpleMessage("Ponto final inválido"), "invalidEndpointMessage": MessageLookupByLibrary.simpleMessage( @@ -1135,7 +1186,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Parece que algo deu errado. Tente novamente mais tarde. Caso o erro persistir, por favor, entre em contato com nossa equipe."), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Os itens exibem o número de dias restantes antes da exclusão permanente"), @@ -1156,7 +1207,7 @@ class MessageLookup extends MessageLookupByLibrary { "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( "Ajude-nos com esta informação"), "language": MessageLookupByLibrary.simpleMessage("Idioma"), - "lastTimeWithThem": m44, + "lastTimeWithThem": m45, "lastUpdated": MessageLookupByLibrary.simpleMessage("Última atualização"), "lastYearsTrip": @@ -1171,7 +1222,7 @@ class MessageLookup extends MessageLookupByLibrary { "legacy": MessageLookupByLibrary.simpleMessage("Legado"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("Contas legadas"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage( "O legado permite que contatos confiáveis acessem sua conta em sua ausência."), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( @@ -1188,7 +1239,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("para compartilhar rápido"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Ativado"), "linkExpired": MessageLookupByLibrary.simpleMessage("Expirado"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Expiração do link"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("O link expirou"), @@ -1196,8 +1247,8 @@ class MessageLookup extends MessageLookupByLibrary { "linkPerson": MessageLookupByLibrary.simpleMessage("Vincular pessoa"), "linkPersonCaption": MessageLookupByLibrary.simpleMessage( "para melhorar o compartilhamento"), - "linkPersonToEmail": m47, - "linkPersonToEmailConfirmation": m48, + "linkPersonToEmail": m48, + "linkPersonToEmailConfirmation": m49, "livePhotos": MessageLookupByLibrary.simpleMessage("Fotos animadas"), "loadMessage1": MessageLookupByLibrary.simpleMessage( "Você pode compartilhar sua assinatura com seus familiares"), @@ -1212,7 +1263,7 @@ class MessageLookup extends MessageLookupByLibrary { "loadMessage6": MessageLookupByLibrary.simpleMessage( "Você pode compartilhar links para seus álbuns com seus entes queridos"), "loadMessage7": MessageLookupByLibrary.simpleMessage( - "Nossos aplicativos móveis são executados em segundo plano para criptografar e copiar com segurança quaisquer fotos novas que você acessar"), + "Nossos aplicativos móveis são executados em segundo plano para criptografar e salvar em segurança quaisquer fotos novas que você acessar"), "loadMessage8": MessageLookupByLibrary.simpleMessage( "web.ente.io tem um enviador mais rápido"), "loadMessage9": MessageLookupByLibrary.simpleMessage( @@ -1259,8 +1310,8 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Mantenha pressionado em um item para visualizá-lo em tela cheia"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), + "lookBackOnYourMemories": + MessageLookupByLibrary.simpleMessage("Revise suas memórias 🌄"), "loopVideoOff": MessageLookupByLibrary.simpleMessage("Repetir vídeo desativado"), "loopVideoOn": @@ -1290,7 +1341,10 @@ class MessageLookup extends MessageLookupByLibrary { "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), "me": MessageLookupByLibrary.simpleMessage("Eu"), - "memoryCount": m49, + "memories": MessageLookupByLibrary.simpleMessage("Memórias"), + "memoriesWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Selecione os tipos de memórias que deseje vê-las na sua tela inicial."), + "memoryCount": m50, "merchandise": MessageLookupByLibrary.simpleMessage("Produtos"), "mergeWithExisting": MessageLookupByLibrary.simpleMessage("Juntar com o existente"), @@ -1303,8 +1357,8 @@ class MessageLookup extends MessageLookupByLibrary { "Se ativar o aprendizado automático, Ente extrairá informações de geometria facial dos arquivos, incluindo aqueles compartilhados consigo.\n\nIsso acontecerá em seu dispositivo, e qualquer informação biométrica gerada será criptografada de ponta a ponta."), "mlConsentPrivacy": MessageLookupByLibrary.simpleMessage( "Clique aqui para mais detalhes sobre este recurso na política de privacidade"), - "mlConsentTitle": MessageLookupByLibrary.simpleMessage( - "Ativar aprendizado automático?"), + "mlConsentTitle": + MessageLookupByLibrary.simpleMessage("Ativar aprendizado auto.?"), "mlIndexingDescription": MessageLookupByLibrary.simpleMessage( "Saiba que o aprendizado automático afetará a bateria do dispositivo negativamente até todos os itens serem indexados. Utilize a versão para computadores para melhor indexação, todos os resultados se auto-sincronizaram."), "mobileWebDesktop": @@ -1321,14 +1375,14 @@ class MessageLookup extends MessageLookupByLibrary { "mostRecent": MessageLookupByLibrary.simpleMessage("Mais recente"), "mostRelevant": MessageLookupByLibrary.simpleMessage("Mais relevante"), "mountains": MessageLookupByLibrary.simpleMessage("Sob as montanhas"), - "moveItem": m50, + "moveItem": m51, "moveSelectedPhotosToOneDate": MessageLookupByLibrary.simpleMessage( "Mover fotos selecionadas para uma data"), "moveToAlbum": MessageLookupByLibrary.simpleMessage("Mover para o álbum"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Mover ao álbum oculto"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("Movido para a lixeira"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1343,7 +1397,7 @@ class MessageLookup extends MessageLookupByLibrary { "newAlbum": MessageLookupByLibrary.simpleMessage("Novo álbum"), "newLocation": MessageLookupByLibrary.simpleMessage("Nova localização"), "newPerson": MessageLookupByLibrary.simpleMessage("Nova pessoa"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), + "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" novo 📸"), "newRange": MessageLookupByLibrary.simpleMessage("Novo intervalo"), "newToEnte": MessageLookupByLibrary.simpleMessage("Novo no Ente"), "newest": MessageLookupByLibrary.simpleMessage("Mais recente"), @@ -1371,7 +1425,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Sem conexão à internet"), "noPhotosAreBeingBackedUpRightNow": MessageLookupByLibrary.simpleMessage( - "No momento não há fotos sendo copiadas com segurança"), + "No momento não há fotos sendo salvas em segurança"), "noPhotosFoundHere": MessageLookupByLibrary.simpleMessage( "Nenhuma foto encontrada aqui"), "noQuickLinksSelected": MessageLookupByLibrary.simpleMessage( @@ -1383,10 +1437,10 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Nenhum resultado"), "noResultsFound": MessageLookupByLibrary.simpleMessage("Nenhum resultado encontrado"), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage( "Nenhum bloqueio do sistema encontrado"), - "notPersonLabel": m53, + "notPersonLabel": m54, "notThisPerson": MessageLookupByLibrary.simpleMessage("Não é esta pessoa?"), "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( @@ -1400,10 +1454,13 @@ class MessageLookup extends MessageLookupByLibrary { "No ente"), "onTheRoad": MessageLookupByLibrary.simpleMessage("Na estrada novamente"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "onThisDay": MessageLookupByLibrary.simpleMessage("Neste dia"), + "onThisDayMemories": + MessageLookupByLibrary.simpleMessage("Memórias deste dia"), + "onThisDayNotificationExplanation": + MessageLookupByLibrary.simpleMessage( + "Receba lembretes de memórias deste dia em anos passados."), + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("Apenas eles"), "oops": MessageLookupByLibrary.simpleMessage("Ops"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( @@ -1433,7 +1490,7 @@ class MessageLookup extends MessageLookupByLibrary { "pairingComplete": MessageLookupByLibrary.simpleMessage("Pareamento concluído"), "panorama": MessageLookupByLibrary.simpleMessage("Panorama"), - "partyWithThem": m55, + "partyWithThem": m56, "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage("Verificação pendente"), "passkey": MessageLookupByLibrary.simpleMessage("Chave de acesso"), @@ -1444,45 +1501,49 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Senha alterada com sucesso"), "passwordLock": MessageLookupByLibrary.simpleMessage("Bloqueio por senha"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "A força da senha é calculada considerando o comprimento dos dígitos, carácteres usados, e se ou não a senha aparece nas 10.000 senhas usadas."), "passwordWarning": MessageLookupByLibrary.simpleMessage( "Nós não armazenamos esta senha, se você esquecer, nós não poderemos descriptografar seus dados"), + "pastYearsMemories": + MessageLookupByLibrary.simpleMessage("Memórias dos anos passados"), "paymentDetails": MessageLookupByLibrary.simpleMessage("Detalhes de pagamento"), "paymentFailed": MessageLookupByLibrary.simpleMessage("O pagamento falhou"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Infelizmente o pagamento falhou. Entre em contato com o suporte e nós ajudaremos você!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("Itens pendentes"), "pendingSync": MessageLookupByLibrary.simpleMessage("Sincronização pendente"), "people": MessageLookupByLibrary.simpleMessage("Pessoas"), "peopleUsingYourCode": - MessageLookupByLibrary.simpleMessage("Pessoas que usam seu código"), + MessageLookupByLibrary.simpleMessage("Pessoas que usou o código"), + "peopleWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Selecione as pessoas que deseje vê-las na sua tela inicial."), "permDeleteWarning": MessageLookupByLibrary.simpleMessage( "Todos os itens na lixeira serão excluídos permanentemente\n\nEsta ação não pode ser desfeita"), "permanentlyDelete": MessageLookupByLibrary.simpleMessage("Excluir permanentemente"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage( "Excluir permanentemente do dispositivo?"), - "personIsAge": m58, + "personIsAge": m59, "personName": MessageLookupByLibrary.simpleMessage("Nome da pessoa"), - "personTurningAge": m59, + "personTurningAge": m60, "pets": MessageLookupByLibrary.simpleMessage("Companhias peludas"), "photoDescriptions": MessageLookupByLibrary.simpleMessage("Descrições das fotos"), "photoGridSize": MessageLookupByLibrary.simpleMessage("Tamanho da grade de fotos"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("foto"), - "photocountPhotos": m60, + "photocountPhotos": m61, "photos": MessageLookupByLibrary.simpleMessage("Fotos"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage( "Suas fotos adicionadas serão removidas do álbum"), - "photosCount": m61, + "photosCount": m62, "photosKeepRelativeTimeDifference": MessageLookupByLibrary.simpleMessage( "As fotos mantêm a diferença de tempo relativo"), @@ -1494,7 +1555,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Reproduzir álbum na TV"), "playOriginal": MessageLookupByLibrary.simpleMessage("Reproduzir original"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playStream": MessageLookupByLibrary.simpleMessage("Reproduzir transmissão"), "playstoreSubscription": @@ -1508,14 +1569,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Por favor, contate o suporte se o problema persistir"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage( "Por favor, conceda as permissões"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Registre-se novamente"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Selecione links rápidos para remover"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Tente novamente"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1528,7 +1589,7 @@ class MessageLookup extends MessageLookupByLibrary { "Por favor, aguarde mais algum tempo antes de tentar novamente"), "pleaseWaitThisWillTakeAWhile": MessageLookupByLibrary.simpleMessage( "Aguarde um pouco, isso talvez leve um tempo."), - "posingWithThem": m65, + "posingWithThem": m66, "preparingLogs": MessageLookupByLibrary.simpleMessage("Preparando registros..."), "preserveMore": MessageLookupByLibrary.simpleMessage("Preservar mais"), @@ -1547,7 +1608,7 @@ class MessageLookup extends MessageLookupByLibrary { "proceed": MessageLookupByLibrary.simpleMessage("Continuar"), "processed": MessageLookupByLibrary.simpleMessage("Processado"), "processing": MessageLookupByLibrary.simpleMessage("Processando"), - "processingImport": m66, + "processingImport": m67, "processingVideos": MessageLookupByLibrary.simpleMessage("Processando vídeos"), "publicLinkCreated": @@ -1561,11 +1622,13 @@ class MessageLookup extends MessageLookupByLibrary { "rateTheApp": MessageLookupByLibrary.simpleMessage("Avalie o aplicativo"), "rateUs": MessageLookupByLibrary.simpleMessage("Avaliar"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "reassignMe": MessageLookupByLibrary.simpleMessage("Reatribuir \"Eu\""), - "reassignedToName": m68, + "reassignedToName": m69, "reassigningLoading": MessageLookupByLibrary.simpleMessage("Reatribuindo..."), + "receiveRemindersOnBirthdays": MessageLookupByLibrary.simpleMessage( + "Receba notificações quando alguém fizer um aniversário. Tocar na notificação o levará às fotos do aniversariante."), "recover": MessageLookupByLibrary.simpleMessage("Recuperar"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Recuperar conta"), @@ -1574,7 +1637,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Recuperar conta"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage("A recuperação iniciou"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("Chave de recuperação"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( @@ -1584,17 +1647,17 @@ class MessageLookup extends MessageLookupByLibrary { "recoveryKeySaveDescription": MessageLookupByLibrary.simpleMessage( "Não armazenamos esta chave, salve esta chave de 24 palavras em um lugar seguro."), "recoveryKeySuccessBody": MessageLookupByLibrary.simpleMessage( - "Ótimo! Sua chave de recuperação é válida. Obrigada por verificar.\n\nLembre-se de manter sua chave de recuperação copiada com segurança."), + "Ótimo! Sua chave de recuperação é válida. Obrigada por verificar.\n\nLembre-se de manter sua chave de recuperação salva em segurança."), "recoveryKeyVerified": MessageLookupByLibrary.simpleMessage( "Chave de recuperação verificada"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "Sua chave de recuperação é a única maneira de recuperar suas fotos se você esqueceu sua senha. Você pode encontrar sua chave de recuperação em Opções > Conta.\n\nInsira sua chave de recuperação aqui para verificar se você a salvou corretamente."), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage("Recuperação com sucesso!"), "recoveryWarning": MessageLookupByLibrary.simpleMessage( "Um contato confiável está tentando acessar sua conta"), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "O dispositivo atual não é poderoso o suficiente para verificar sua senha, no entanto, nós podemos regenerar numa maneira que funciona em todos os dispositivos.\n\nEntre usando a chave de recuperação e regenere sua senha (você pode usar a mesma novamente se desejar)."), "recreatePasswordTitle": @@ -1609,14 +1672,14 @@ class MessageLookup extends MessageLookupByLibrary { "1. Envie este código aos seus amigos"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Eles então se inscrevem num plano pago"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("Referências"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "As referências estão atualmente pausadas"), "rejectRecovery": MessageLookupByLibrary.simpleMessage("Rejeitar recuperação"), "remindToEmptyDeviceTrash": MessageLookupByLibrary.simpleMessage( - "Também vazio \"Excluído recentemente\" de \"Opções\" -> \"Armazenamento\" para reivindicar espaço liberado"), + "Também esvazie o \"Excluído Recentemente\" das \"Opções\" -> \"Armazenamento\" para liberar espaço"), "remindToEmptyEnteTrash": MessageLookupByLibrary.simpleMessage( "Também esvazie sua \"Lixeira\" para reivindicar o espaço liberado"), "remoteImages": MessageLookupByLibrary.simpleMessage("Imagens remotas"), @@ -1638,7 +1701,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Remover link"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Remover participante"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Remover etiqueta da pessoa"), "removePublicLink": @@ -1658,7 +1721,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("Renomear arquivo"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Renovar assinatura"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Informar um erro"), "reportBug": MessageLookupByLibrary.simpleMessage("Informar erro"), "resendEmail": MessageLookupByLibrary.simpleMessage("Reenviar e-mail"), @@ -1683,7 +1746,7 @@ class MessageLookup extends MessageLookupByLibrary { "reviewSuggestions": MessageLookupByLibrary.simpleMessage("Revisar sugestões"), "right": MessageLookupByLibrary.simpleMessage("Direita"), - "roadtripWithThem": m75, + "roadtripWithThem": m76, "rotate": MessageLookupByLibrary.simpleMessage("Girar"), "rotateLeft": MessageLookupByLibrary.simpleMessage("Girar para a esquerda"), @@ -1741,8 +1804,8 @@ class MessageLookup extends MessageLookupByLibrary { "Convide pessoas e você verá todas as fotos compartilhadas por elas aqui"), "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage( "As pessoas serão exibidas aqui quando o processamento e sincronização for concluído"), - "searchResultCount": m76, - "searchSectionsLengthMismatch": m77, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("Segurança"), "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage( "Ver links de álbum compartilhado no aplicativo"), @@ -1757,7 +1820,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Selecionar foto da capa"), "selectDate": MessageLookupByLibrary.simpleMessage("Selecionar data"), "selectFoldersForBackup": MessageLookupByLibrary.simpleMessage( - "Selecionar pastas para copiar com segurança"), + "Selecione as pastas para salvá-las"), "selectItemsToAdd": MessageLookupByLibrary.simpleMessage( "Selecionar itens para adicionar"), "selectLanguage": @@ -1780,20 +1843,21 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Selecione seu rosto"), "selectYourPlan": MessageLookupByLibrary.simpleMessage("Selecione seu plano"), + "selectedAlbums": m79, "selectedFilesAreNotOnEnte": MessageLookupByLibrary.simpleMessage( "Os arquivos selecionados não estão no Ente"), "selectedFoldersWillBeEncryptedAndBackedUp": MessageLookupByLibrary.simpleMessage( - "As pastas selecionadas serão criptografadas e armazenadas em copiadas com segurança"), + "As pastas selecionadas serão criptografadas e salvas em segurança"), "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage( "Os itens selecionados serão excluídos de todos os álbuns e movidos para a lixeira."), "selectedItemsWillBeRemovedFromThisPerson": MessageLookupByLibrary.simpleMessage( "Os itens selecionados serão removidos desta pessoa, entretanto não serão excluídos da sua biblioteca."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, - "selfiesWithThem": m80, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, + "selfiesWithThem": m82, "send": MessageLookupByLibrary.simpleMessage("Enviar"), "sendEmail": MessageLookupByLibrary.simpleMessage("Enviar e-mail"), "sendInvite": MessageLookupByLibrary.simpleMessage("Enviar convite"), @@ -1823,16 +1887,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Compartilhar um álbum agora"), "shareLink": MessageLookupByLibrary.simpleMessage("Compartilhar link"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Compartilhar apenas com as pessoas que você quiser"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Baixe o Ente para que nós possamos compartilhar com facilidade fotos e vídeos de qualidade original\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Compartilhar com usuários não ente"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage( "Compartilhar seu primeiro álbum"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1845,7 +1909,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Novas fotos compartilhadas"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "Receber notificações quando alguém adicionar uma foto a um álbum compartilhado que você faz parte"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Compartilhado comigo"), "sharedWithYou": @@ -1864,12 +1928,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Sair em outros dispositivos"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Eu concordo com os termos de serviço e a política de privacidade"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "Ele será excluído de todos os álbuns."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("Pular"), + "smartMemories": + MessageLookupByLibrary.simpleMessage("Memórias inteligentes"), "social": MessageLookupByLibrary.simpleMessage("Redes sociais"), "someItemsAreInBothEnteAndYourDevice": MessageLookupByLibrary.simpleMessage( @@ -1887,7 +1953,7 @@ class MessageLookup extends MessageLookupByLibrary { "Algo deu errado. Tente outra vez"), "sorry": MessageLookupByLibrary.simpleMessage("Desculpe"), "sorryBackupFailedDesc": MessageLookupByLibrary.simpleMessage( - "Desculpe, não podemos fazer cópia de segurança deste arquivo no momento, nós tentaremos mais tarde."), + "Desculpe, não podemos salvar em segurança este arquivo no momento, nós tentaremos mais tarde."), "sorryCouldNotAddToFavorites": MessageLookupByLibrary.simpleMessage( "Desculpe, não foi possível adicionar aos favoritos!"), "sorryCouldNotRemoveFromFavorites": @@ -1900,7 +1966,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Desculpe, não foi possível gerar chaves seguras neste dispositivo.\n\ninicie sessão com um dispositivo diferente."), "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), + "Desculpe, tivemos que pausar os salvamentos em segurança"), "sort": MessageLookupByLibrary.simpleMessage("Ordenar"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Ordenar por"), "sortNewestFirst": @@ -1908,14 +1974,14 @@ class MessageLookup extends MessageLookupByLibrary { "sortOldestFirst": MessageLookupByLibrary.simpleMessage("Antigos primeiro"), "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ Sucesso"), - "sportsWithThem": m89, - "spotlightOnThem": m90, + "sportsWithThem": m91, + "spotlightOnThem": m92, "spotlightOnYourself": MessageLookupByLibrary.simpleMessage("Destacar si mesmo"), "startAccountRecoveryTitle": MessageLookupByLibrary.simpleMessage("Iniciar recuperação"), - "startBackup": - MessageLookupByLibrary.simpleMessage("Iniciar cópia de segurança"), + "startBackup": MessageLookupByLibrary.simpleMessage( + "Iniciar a salvar em segurança"), "status": MessageLookupByLibrary.simpleMessage("Estado"), "stopCastingBody": MessageLookupByLibrary.simpleMessage("Deseja parar a transmissão?"), @@ -1924,15 +1990,15 @@ class MessageLookup extends MessageLookupByLibrary { "storage": MessageLookupByLibrary.simpleMessage("Armazenamento"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Família"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Você"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage( "Limite de armazenamento excedido"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "streamDetails": MessageLookupByLibrary.simpleMessage("Detalhes da transmissão"), "strongStrength": MessageLookupByLibrary.simpleMessage("Forte"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("Inscrever-se"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "Você precisa de uma inscrição paga ativa para ativar o compartilhamento."), @@ -1950,7 +2016,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Sugerir recurso"), "sunrise": MessageLookupByLibrary.simpleMessage("No horizonte"), "support": MessageLookupByLibrary.simpleMessage("Suporte"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("Sincronização interrompida"), "syncing": MessageLookupByLibrary.simpleMessage("Sincronizando..."), @@ -1962,7 +2028,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Toque para desbloquear"), "tapToUpload": MessageLookupByLibrary.simpleMessage("Toque para enviar"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Parece que algo deu errado. Tente novamente mais tarde. Caso o erro persistir, por favor, entre em contato com nossa equipe."), "terminate": MessageLookupByLibrary.simpleMessage("Encerrar"), @@ -1984,7 +2050,7 @@ class MessageLookup extends MessageLookupByLibrary { "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage( "Estes itens serão excluídos do seu dispositivo."), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage( "Eles serão excluídos de todos os álbuns."), "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( @@ -2002,12 +2068,12 @@ class MessageLookup extends MessageLookupByLibrary { "Esta imagem não possui dados EXIF"), "thisIsMeExclamation": MessageLookupByLibrary.simpleMessage("Este é você!"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( "Este é o seu ID de verificação"), "thisWeekThroughTheYears": MessageLookupByLibrary.simpleMessage( "Esta semana com o passar dos anos"), - "thisWeekXYearsAgo": m99, + "thisWeekXYearsAgo": m101, "thisWillLogYouOutOfTheFollowingDevice": MessageLookupByLibrary.simpleMessage( "Isso fará você sair do dispositivo a seguir:"), @@ -2019,7 +2085,7 @@ class MessageLookup extends MessageLookupByLibrary { "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( "Isto removerá links públicos de todos os links rápidos selecionados."), - "throughTheYears": m100, + "throughTheYears": m102, "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": MessageLookupByLibrary.simpleMessage( "Para ativar o bloqueio do aplicativo, defina uma senha de acesso no dispositivo ou bloqueie sua tela nas opções do sistema."), @@ -2033,16 +2099,16 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("total"), "totalSize": MessageLookupByLibrary.simpleMessage("Tamanho total"), "trash": MessageLookupByLibrary.simpleMessage("Lixeira"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("Recortar"), - "tripInYear": m102, - "tripToLocation": m103, + "tripInYear": m104, + "tripToLocation": m105, "trustedContacts": MessageLookupByLibrary.simpleMessage("Contatos confiáveis"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("Tente novamente"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( - "Ative a cópia de segurança para automaticamente enviar arquivos adicionados à pasta do dispositivo para o Ente."), + "Ative o salvamento em segurança para automaticamente enviar arquivos adicionados à pasta do dispositivo para o Ente."), "twitter": MessageLookupByLibrary.simpleMessage("Twitter/X"), "twoMonthsFreeOnYearlyPlans": MessageLookupByLibrary.simpleMessage( "2 meses grátis em planos anuais"), @@ -2058,7 +2124,7 @@ class MessageLookup extends MessageLookupByLibrary { "Autenticação de dois fatores redefinida com sucesso"), "twofactorSetup": MessageLookupByLibrary.simpleMessage( "Configuração de dois fatores"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("Desarquivar"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("Desarquivar álbum"), @@ -2081,19 +2147,19 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage( "Atualizando seleção de pasta..."), "upgrade": MessageLookupByLibrary.simpleMessage("Atualizar"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Enviando arquivos para o álbum..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage("Preservando 1 memória..."), "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( "Com 50% de desconto, até 4 de dezembro"), "usableReferralStorageInfo": MessageLookupByLibrary.simpleMessage( - "O armazenamento disponível é limitado pelo seu plano atual. O excesso de armazenamento reivindicado tornará automaticamente útil quando você atualizar seu plano."), + "O armazenamento disponível é limitado devido ao seu plano atual. O armazenamento adicional será aplicado quando você atualizar seu plano."), "useAsCover": MessageLookupByLibrary.simpleMessage("Usar como capa"), "useDifferentPlayerInfo": MessageLookupByLibrary.simpleMessage( - "Enfrentando problemas ao reproduzir este vídeo? Mantenha pressionado aqui ou tente outro reprodutor de vídeo"), + "Enfrentando problemas ao reproduzir este vídeo? Mantenha pressionado aqui para tentar outro reprodutor de vídeo"), "usePublicLinksForPeopleNotOnEnte": MessageLookupByLibrary.simpleMessage( "Usar links públicos para pessoas que não estão no Ente"), @@ -2102,7 +2168,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("Usar foto selecionada"), "usedSpace": MessageLookupByLibrary.simpleMessage("Espaço usado"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Falha na verificação. Tente novamente"), @@ -2110,7 +2176,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("ID de verificação"), "verify": MessageLookupByLibrary.simpleMessage("Verificar"), "verifyEmail": MessageLookupByLibrary.simpleMessage("Verificar e-mail"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Verificar"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("Verificar chave de acesso"), @@ -2137,11 +2203,11 @@ class MessageLookup extends MessageLookupByLibrary { "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( "Ver arquivos que consumem a maior parte do armazenamento."), "viewLogs": MessageLookupByLibrary.simpleMessage("Ver registros"), - "viewPersonToUnlink": m110, + "viewPersonToUnlink": m112, "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("Ver chave de recuperação"), "viewer": MessageLookupByLibrary.simpleMessage("Visualizador"), - "viewersSuccessfullyAdded": m111, + "viewersSuccessfullyAdded": m113, "visitWebToManage": MessageLookupByLibrary.simpleMessage( "Visite o web.ente.io para gerenciar sua assinatura"), "waitingForVerification": @@ -2154,16 +2220,18 @@ class MessageLookup extends MessageLookupByLibrary { "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "Não suportamos a edição de fotos e álbuns que você ainda não possui"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Fraca"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Bem-vindo(a) de volta!"), "whatsNew": MessageLookupByLibrary.simpleMessage("O que há de novo"), "whyAddTrustContact": MessageLookupByLibrary.simpleMessage( "Um contato confiável pode ajudá-lo em recuperar seus dados."), + "widgets": MessageLookupByLibrary.simpleMessage("Widgets"), + "wishThemAHappyBirthday": m115, "yearShort": MessageLookupByLibrary.simpleMessage("ano"), "yearly": MessageLookupByLibrary.simpleMessage("Anual"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Sim"), "yesCancel": MessageLookupByLibrary.simpleMessage("Sim"), "yesConvertToViewer": MessageLookupByLibrary.simpleMessage( @@ -2178,7 +2246,7 @@ class MessageLookup extends MessageLookupByLibrary { "yesResetPerson": MessageLookupByLibrary.simpleMessage("Sim, redefinir pessoa"), "you": MessageLookupByLibrary.simpleMessage("Você"), - "youAndThem": m114, + "youAndThem": m117, "youAreOnAFamilyPlan": MessageLookupByLibrary.simpleMessage( "Você está em um plano familiar!"), "youAreOnTheLatestVersion": MessageLookupByLibrary.simpleMessage( @@ -2197,7 +2265,7 @@ class MessageLookup extends MessageLookupByLibrary { "Não é possível compartilhar consigo mesmo"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( "Você não tem nenhum item arquivado."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("Sua conta foi excluída"), "yourMap": MessageLookupByLibrary.simpleMessage("Seu mapa"), diff --git a/mobile/lib/generated/intl/messages_pt_PT.dart b/mobile/lib/generated/intl/messages_pt_PT.dart index 5903aee8d9..3ae4693e24 100644 --- a/mobile/lib/generated/intl/messages_pt_PT.dart +++ b/mobile/lib/generated/intl/messages_pt_PT.dart @@ -20,13 +20,26 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'pt_PT'; + static String m0(title) => "${title} (Eu)"; + + static String m1(count) => + "${Intl.plural(count, zero: 'Adicionar colaborador', one: 'Adicionar colaborador', other: 'Adicionar colaboradores')}"; + + static String m2(count) => + "${Intl.plural(count, one: 'Adicionar item', other: 'Adicionar itens')}"; + static String m3(storageAmount, endDate) => "Seu addon ${storageAmount} é válido até o momento ${endDate}"; + static String m4(count) => + "${Intl.plural(count, zero: 'Adicionar visualizador', one: 'Adicionar visualizador', other: 'Adicionar vizualizadores')}"; + static String m5(emailOrName) => "Adicionado por ${emailOrName}"; static String m6(albumName) => "Adicionado com sucesso a ${albumName}"; + static String m7(name) => "A admirar ${name}"; + static String m8(count) => "${Intl.plural(count, zero: 'Nenhum participante', one: '1 participante', other: '${count} participantes')}"; @@ -35,6 +48,8 @@ class MessageLookup extends MessageLookupByLibrary { static String m10(freeAmount, storageUnit) => "${freeAmount} ${storageUnit} grátis"; + static String m11(name) => "Vistas deslumbrantes com ${name}"; + static String m12(paymentProvider) => "Por favor, cancele primeiro a sua subscrição existente de ${paymentProvider}"; @@ -53,6 +68,9 @@ class MessageLookup extends MessageLookupByLibrary { static String m16(count) => "${Intl.plural(count, zero: 'Adicionado 0 colaboradores', one: 'Adicionado 1 colaborador', other: 'Adicionado ${count} colaboradores')}"; + static String m17(email, numOfDays) => + "Está prestes a adicionar ${email} como contacto de confiança. Eles poderão recuperar a sua conta caso esteja inativo por ${numOfDays} dias."; + static String m18(familyAdminEmail) => "Contacte ${familyAdminEmail} para gerir a sua subscrição"; @@ -64,151 +82,249 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'Apagar ${count} item', other: 'Apagar ${count} itens')}"; - static String m22(currentlyDeleting, totalCount) => + static String m22(count) => + "Também eliminar fotos (e vídeos) presentes em ${count} álbuns e de todos os outros álbuns que fazem parte?"; + + static String m23(currentlyDeleting, totalCount) => "Apagar ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "Isto removerá o link público para acessar \"${albumName}\"."; - static String m24(supportEmail) => + static String m25(supportEmail) => "Envie um e-mail para ${supportEmail} a partir do seu endereço de e-mail registado"; - static String m25(count, storageSaved) => + static String m26(count, storageSaved) => "Você limpou ${Intl.plural(count, one: '${count} arquivo duplicado', other: '${count} arquivos duplicados')}, guardando (${storageSaved}!)"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} arquivos, ${formattedSize} cada"; - static String m28(newEmail) => "Email alterado para ${newEmail}"; + static String m28(name) => "Este e-mail já está ligado a ${name}."; - static String m30(email) => + static String m29(newEmail) => "Email alterado para ${newEmail}"; + + static String m30(email) => "${email} não há uma conta no Ente."; + + static String m31(email) => "${email} não possui uma conta Ente.\n\nEnvie um convite para compartilhar fotos."; - static String m32(text) => "Fotos extras encontradas para ${text}"; + static String m32(name) => "A abraçar ${name}"; - static String m34(count, formattedNumber) => - "${Intl.plural(count, one: '1 arquivo', other: '${formattedNumber} arquivos')} neste dispositivo teve um backup seguro"; + static String m33(text) => "Fotos extras encontradas para ${text}"; + + static String m34(name) => "A comer com ${name}"; static String m35(count, formattedNumber) => + "${Intl.plural(count, one: '1 arquivo', other: '${formattedNumber} arquivos')} neste dispositivo teve um backup seguro"; + + static String m36(count, formattedNumber) => "${Intl.plural(count, one: '1 arquivo', other: '${formattedNumber} arquivos')} neste álbum teve um backup seguro"; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "${storageAmountInGB} GB sempre que alguém se inscreve num plano pago e aplica o seu código"; - static String m37(endDate) => "Teste gratuito válido até ${endDate}"; + static String m38(endDate) => "Teste gratuito válido até ${endDate}"; - static String m39(sizeInMBorGB) => "Libertar ${sizeInMBorGB}"; + static String m39(count) => + "Ainda pode acessá${Intl.plural(count, one: '-lo', other: '-los')} no Ente contanto que tenha uma subscrição ativa"; - static String m41(currentlyProcessing, totalCount) => + static String m40(sizeInMBorGB) => "Libertar ${sizeInMBorGB}"; + + static String m41(count, formattedSize) => + "${Intl.plural(count, one: 'Pode eliminá-lo do aparelho para esvaziar ${formattedSize}', other: 'Pode eliminá-los do aparelho para esvaziar ${formattedSize}')}"; + + static String m42(currentlyProcessing, totalCount) => "Processando ${currentlyProcessing} / ${totalCount}"; - static String m43(count) => + static String m43(name) => "Passeando com ${name}"; + + static String m44(count) => "${Intl.plural(count, one: '${count} item', other: '${count} itens')}"; - static String m46(expiryTime) => "O link expirará em ${expiryTime}"; + static String m45(name) => "Últimos momentos com ${name}"; - static String m51(albumName) => "Movido com sucesso para ${albumName}"; + static String m46(email) => + "${email} convidou-lhe a ser um contacto de confiança"; - static String m53(name) => "Não é ${name}?"; + static String m47(expiryTime) => "O link expirará em ${expiryTime}"; - static String m54(familyAdminEmail) => + static String m48(email) => "Ligar pessoa a ${email}"; + + static String m49(personName, email) => + "Isto ligará ${personName} a ${email}"; + + static String m50(count, formattedCount) => + "${Intl.plural(count, zero: 'não há memórias', one: '${formattedCount} memória', other: '${formattedCount} memórias')}"; + + static String m51(count) => + "${Intl.plural(count, one: 'Mover item', other: 'Mover itens')}"; + + static String m52(albumName) => "Movido com sucesso para ${albumName}"; + + static String m53(personName) => "Sem sugestões para ${personName}"; + + static String m54(name) => "Não é ${name}?"; + + static String m55(familyAdminEmail) => "Entre em contato com ${familyAdminEmail} para alterar o seu código."; - static String m56(passwordStrengthValue) => + static String m56(name) => "Tendo uma festa com ${name}"; + + static String m57(passwordStrengthValue) => "Força da palavra-passe: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "Por favor, fale com o suporte ${providerName} se você foi cobrado"; - static String m62(endDate) => + static String m59(name, age) => "${name} tem ${age} anos!"; + + static String m60(name, age) => "${name} fará ${age} anos em breve"; + + static String m61(count) => + "${Intl.plural(count, zero: 'Sem fotos', one: '1 foto', other: '${count} fotos')}"; + + static String m62(count) => + "${Intl.plural(count, zero: '0 fotos', one: '1 foto', other: '${count} fotos')}"; + + static String m63(endDate) => "Teste gratuito válido até ${endDate}.\nVocê pode escolher um plano pago depois."; - static String m63(toEmail) => + static String m64(toEmail) => "Por favor, envie-nos um e-mail para ${toEmail}"; - static String m64(toEmail) => "Por favor, envie os logs para \n${toEmail}"; + static String m65(toEmail) => "Por favor, envie os logs para \n${toEmail}"; - static String m66(folderName) => "Processando ${folderName}..."; + static String m66(name) => "A posicionar com ${name}"; - static String m67(storeName) => "Avalie-nos em ${storeName}"; + static String m67(folderName) => "Processando ${folderName}..."; - static String m72(storageInGB) => "3. Ambos ganham ${storageInGB} GB* grátis"; + static String m68(storeName) => "Avalie-nos em ${storeName}"; - static String m73(userEmail) => + static String m69(name) => "Retribuiu tu a ${name}"; + + static String m70(days, email) => + "Pode acessar a conta após ${days} dias. Uma notificação será enviada para ${email}."; + + static String m71(email) => + "Agora pode recuperar a conta de ${email} definindo uma nova palavra-passe."; + + static String m72(email) => "${email} está a tentar recuperar a sua conta."; + + static String m73(storageInGB) => "3. Ambos ganham ${storageInGB} GB* grátis"; + + static String m74(userEmail) => "${userEmail} será removido deste álbum compartilhado\n\nQuaisquer fotos adicionadas por elas também serão removidas do álbum"; - static String m74(endDate) => "A subscrição é renovada em ${endDate}"; + static String m75(endDate) => "A subscrição é renovada em ${endDate}"; - static String m76(count) => + static String m76(name) => "A viajar na rua com ${name}"; + + static String m77(count) => "${Intl.plural(count, one: '${count} ano atrás', other: '${count} anos atrás')}"; - static String m78(count) => "${count} selecionado(s)"; + static String m78(snapshotLength, searchLength) => + "Desigualdade de Largura entre Seções: ${snapshotLength} != ${searchLength}"; - static String m79(count, yourCount) => + static String m79(count) => "${count} selecionado(s)"; + + static String m80(count) => "${count} selecionado(s)"; + + static String m81(count, yourCount) => "${count} selecionado(s) (${yourCount} seus)"; - static String m81(verificationID) => + static String m82(name) => "A captar selfies com ${name}"; + + static String m83(verificationID) => "Aqui está o meu ID de verificação: ${verificationID} para ente.io."; - static String m82(verificationID) => + static String m84(verificationID) => "Ei, você pode confirmar que este é seu ID de verificação do ente.io: ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Insira o código de referência: ${referralCode} \n\nAplique-o em Configurações → Geral → Indicações para obter ${referralStorageInGB} GB gratuitamente após a sua inscrição para um plano pago\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Compartilhe com pessoas específicas', one: 'Compartilhado com 1 pessoa', other: 'Compartilhado com ${numberOfPeople} pessoas')}"; - static String m85(emailIDs) => "Partilhado com ${emailIDs}"; + static String m87(emailIDs) => "Partilhado com ${emailIDs}"; - static String m86(fileType) => + static String m88(fileType) => "Este ${fileType} será eliminado do seu dispositivo."; - static String m87(fileType) => + static String m89(fileType) => "Este ${fileType} encontra-se tanto no Ente como no seu dispositivo."; - static String m88(fileType) => "Este ${fileType} será eliminado do Ente."; + static String m90(fileType) => "Este ${fileType} será eliminado do Ente."; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m91(name) => "A praticar esportes com ${name}"; - static String m92( + static String m92(name) => "A dar destaque em ${name}"; + + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; + + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} de ${totalAmount} ${totalStorageUnit} usado"; - static String m93(id) => + static String m95(id) => "Seu ${id} já está vinculado a outra conta Ente.\nSe você gostaria de usar seu ${id} com esta conta, por favor contate nosso suporte\'\'"; - static String m94(endDate) => "A sua subscrição será cancelada em ${endDate}"; + static String m96(endDate) => "A sua subscrição será cancelada em ${endDate}"; - static String m95(completed, total) => + static String m97(completed, total) => "${completed}/${total} memórias preservadas"; - static String m97(storageAmountInGB) => + static String m98(ignoreReason) => + "Clique para enviar, o envio foi ignorado devido a ${ignoreReason}"; + + static String m99(storageAmountInGB) => "Eles também recebem ${storageAmountInGB} GB"; - static String m98(email) => "Este é o ID de verificação de ${email}"; + static String m100(email) => "Este é o ID de verificação de ${email}"; static String m101(count) => + "${Intl.plural(count, one: 'Esta semana, ${count} ano atrás', other: 'Esta semana, ${count} anos atrás')}"; + + static String m102(dateFormat) => "${dateFormat} com o avanço dos anos"; + + static String m103(count) => "${Intl.plural(count, zero: 'Brevemente', one: '1 dia', other: '${count} dias')}"; - static String m105(galleryType) => + static String m104(year) => "Viajem em ${year}"; + + static String m105(location) => "Viagem para ${location}"; + + static String m106(email) => + "Foste convidado para ser um contacto revivido de ${email}."; + + static String m107(galleryType) => "Tipo de galeria ${galleryType} não é permitido para renomear"; - static String m106(ignoreReason) => "Envio ignorado devido à ${ignoreReason}"; + static String m108(ignoreReason) => "Envio ignorado devido à ${ignoreReason}"; - static String m107(count) => "Preservar ${count} memórias..."; + static String m109(count) => "Preservar ${count} memórias..."; - static String m108(endDate) => "Válido até ${endDate}"; + static String m110(endDate) => "Válido até ${endDate}"; - static String m109(email) => "Verificar e-mail"; + static String m111(email) => "Verificar e-mail"; - static String m112(email) => - "Enviamos um e-mail para ${email}"; + static String m112(name) => "Ver ${name} para desligar"; static String m113(count) => + "${Intl.plural(count, zero: 'Adicionado 0 vizualizadores', one: 'Adicionado 1 visualizador', other: 'Adicionado ${count} visualizadores')}"; + + static String m114(email) => + "Enviamos um e-mail para ${email}"; + + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + + static String m116(count) => "${Intl.plural(count, one: '${count} ano atrás', other: '${count} anos atrás')}"; - static String m115(storageSaved) => + static String m117(name) => "Tu e ${name}"; + + static String m118(storageSaved) => "Você liberou ${storageSaved} com sucesso!"; final messages = _notInlinedMessages(_notInlinedMessages); @@ -216,26 +332,39 @@ class MessageLookup extends MessageLookupByLibrary { "aNewVersionOfEnteIsAvailable": MessageLookupByLibrary.simpleMessage( "Está disponível uma nova versão do Ente."), "about": MessageLookupByLibrary.simpleMessage("Sobre"), + "acceptTrustInvite": + MessageLookupByLibrary.simpleMessage("Aceite o Convite"), "account": MessageLookupByLibrary.simpleMessage("Conta"), "accountIsAlreadyConfigured": MessageLookupByLibrary.simpleMessage("A conta já está ajustada."), + "accountOwnerPersonAppbarTitle": m0, "accountWelcomeBack": MessageLookupByLibrary.simpleMessage("Bem-vindo de volta!"), "ackPasswordLostWarning": MessageLookupByLibrary.simpleMessage( "Eu entendo que se eu perder a minha palavra-passe, posso perder os meus dados já que esses dados são encriptados de ponta a ponta."), + "actionNotSupportedOnFavouritesAlbum": + MessageLookupByLibrary.simpleMessage( + "Ação não suportada no álbum de Preferidos"), "activeSessions": MessageLookupByLibrary.simpleMessage("Sessões ativas"), "add": MessageLookupByLibrary.simpleMessage("Adicionar"), "addAName": MessageLookupByLibrary.simpleMessage("Adiciona um nome"), "addANewEmail": MessageLookupByLibrary.simpleMessage("Adicionar um novo e-mail"), + "addAlbumWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Adiciona um widget de álbum no seu ecrã inicial e volte aqui para personalizar."), "addCollaborator": MessageLookupByLibrary.simpleMessage("Adicionar colaborador"), + "addCollaborators": m1, + "addFiles": MessageLookupByLibrary.simpleMessage("Adicionar Ficheiros"), "addFromDevice": MessageLookupByLibrary.simpleMessage( "Adicionar a partir do dispositivo"), + "addItem": m2, "addLocation": MessageLookupByLibrary.simpleMessage("Adicionar localização"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Adicionar"), + "addMemoriesWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Adiciona um widget de memórias no seu ecrã inicial e volte aqui para personalizar."), "addMore": MessageLookupByLibrary.simpleMessage("Adicionar mais"), "addName": MessageLookupByLibrary.simpleMessage("Adicionar pessoa"), "addNameOrMerge": @@ -247,6 +376,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Detalhes dos addons"), "addOnValidTill": m3, "addOns": MessageLookupByLibrary.simpleMessage("addons"), + "addParticipants": + MessageLookupByLibrary.simpleMessage("Adicionar participante"), + "addPeopleWidgetPrompt": MessageLookupByLibrary.simpleMessage( + "Adiciona um widget de pessoas no seu ecrã inicial e volte aqui para personalizar."), "addPhotos": MessageLookupByLibrary.simpleMessage("Adicionar fotos"), "addSelected": MessageLookupByLibrary.simpleMessage("Adicionar selecionados"), @@ -255,8 +388,11 @@ class MessageLookup extends MessageLookupByLibrary { "addToEnte": MessageLookupByLibrary.simpleMessage("Adicionar ao Ente"), "addToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Adicionar a álbum oculto"), + "addTrustedContact": MessageLookupByLibrary.simpleMessage( + "Adicionar Contacto de Confiança"), "addViewer": MessageLookupByLibrary.simpleMessage("Adicionar visualizador"), + "addViewers": m4, "addYourPhotosNow": MessageLookupByLibrary.simpleMessage("Adicione suas fotos agora"), "addedAs": MessageLookupByLibrary.simpleMessage("Adicionado como"), @@ -264,6 +400,7 @@ class MessageLookup extends MessageLookupByLibrary { "addedSuccessfullyTo": m6, "addingToFavorites": MessageLookupByLibrary.simpleMessage( "Adicionando aos favoritos..."), + "admiringThem": m7, "advanced": MessageLookupByLibrary.simpleMessage("Avançado"), "advancedSettings": MessageLookupByLibrary.simpleMessage("Definições avançadas"), @@ -279,19 +416,30 @@ class MessageLookup extends MessageLookupByLibrary { "albumUpdated": MessageLookupByLibrary.simpleMessage("Álbum atualizado"), "albums": MessageLookupByLibrary.simpleMessage("Álbuns"), + "albumsWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Seleciona os álbuns que adoraria ver no seu ecrã inicial."), "allClear": MessageLookupByLibrary.simpleMessage("✨ Tudo limpo"), "allMemoriesPreserved": MessageLookupByLibrary.simpleMessage( "Todas as memórias preservadas"), "allPersonGroupingWillReset": MessageLookupByLibrary.simpleMessage( "Todos os agrupamentos para esta pessoa serão reiniciados e perderá todas as sugestões feitas para esta pessoa"), + "allWillShiftRangeBasedOnFirst": MessageLookupByLibrary.simpleMessage( + "Este é o primeiro neste grupo. Outras fotos selecionadas serão automaticamente alteradas para a nova data"), + "allow": MessageLookupByLibrary.simpleMessage("Permitir"), "allowAddPhotosDescription": MessageLookupByLibrary.simpleMessage( "Permitir que pessoas com o link também adicionem fotos ao álbum compartilhado."), "allowAddingPhotos": MessageLookupByLibrary.simpleMessage("Permitir adicionar fotos"), + "allowAppToOpenSharedAlbumLinks": MessageLookupByLibrary.simpleMessage( + "Permitir Aplicação Abrir Ligações Partilhadas"), "allowDownloads": MessageLookupByLibrary.simpleMessage("Permitir downloads"), "allowPeopleToAddPhotos": MessageLookupByLibrary.simpleMessage( "Permitir que as pessoas adicionem fotos"), + "allowPermBody": MessageLookupByLibrary.simpleMessage( + "Por favor, permita o acesso às suas fotos para que Ente possa mostrá-las e fazer backup na Fototeca."), + "allowPermTitle": + MessageLookupByLibrary.simpleMessage("Garanta acesso às fotos"), "androidBiometricHint": MessageLookupByLibrary.simpleMessage("Verificar identidade"), "androidBiometricNotRecognized": MessageLookupByLibrary.simpleMessage( @@ -313,6 +461,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Android, iOS, Web, Desktop"), "androidSignInTitle": MessageLookupByLibrary.simpleMessage("Autenticação necessária"), + "appIcon": MessageLookupByLibrary.simpleMessage("Ícone da Aplicação"), "appLock": MessageLookupByLibrary.simpleMessage("Bloqueio de app"), "appLockDescriptions": MessageLookupByLibrary.simpleMessage( "Escolha entre o ecrã de bloqueio predefinido do seu dispositivo e um ecrã de bloqueio personalizado com um PIN ou uma palavra-passe."), @@ -365,8 +514,12 @@ class MessageLookup extends MessageLookupByLibrary { "Por favor, autentique para configurar a autenticação de dois fatores"), "authToInitiateAccountDeletion": MessageLookupByLibrary.simpleMessage( "Autentique-se para iniciar a eliminação da conta"), + "authToManageLegacy": MessageLookupByLibrary.simpleMessage( + "Autentica-se para gerir os seus contactos de confiança"), "authToViewPasskey": MessageLookupByLibrary.simpleMessage( "Autentique-se para ver a sua chave de acesso"), + "authToViewTrashedFiles": MessageLookupByLibrary.simpleMessage( + "Autentica-se para visualizar os ficheiros na lata de lixo"), "authToViewYourActiveSessions": MessageLookupByLibrary.simpleMessage( "Por favor, autentique-se para ver as suas sessões ativas"), "authToViewYourHiddenFiles": MessageLookupByLibrary.simpleMessage( @@ -399,8 +552,11 @@ class MessageLookup extends MessageLookupByLibrary { "availableStorageSpace": m10, "backedUpFolders": MessageLookupByLibrary.simpleMessage( "Pastas com cópia de segurança"), + "backgroundWithThem": m11, "backup": MessageLookupByLibrary.simpleMessage("Cópia de segurança"), "backupFailed": MessageLookupByLibrary.simpleMessage("Backup falhou"), + "backupFile": + MessageLookupByLibrary.simpleMessage("Backup de Ficheiro"), "backupOverMobileData": MessageLookupByLibrary.simpleMessage( "Cópia de segurança através dos dados móveis"), "backupSettings": MessageLookupByLibrary.simpleMessage( @@ -411,12 +567,44 @@ class MessageLookup extends MessageLookupByLibrary { "Os itens que foram salvos com segurança aparecerão aqui"), "backupVideos": MessageLookupByLibrary.simpleMessage( "Cópia de segurança de vídeos"), + "beach": MessageLookupByLibrary.simpleMessage("A areia e o mar"), "birthday": MessageLookupByLibrary.simpleMessage("Aniversário"), + "birthdayNotifications": + MessageLookupByLibrary.simpleMessage("Notificações de felicidades"), + "birthdays": MessageLookupByLibrary.simpleMessage("Aniversários"), "blackFridaySale": MessageLookupByLibrary.simpleMessage("Promoção Black Friday"), "blog": MessageLookupByLibrary.simpleMessage("Blog"), + "cLDesc1": MessageLookupByLibrary.simpleMessage( + "Na sequência da versão beta de transmissão de vídeo e do trabalho em envios e transferências retomáveis, agora aumentámos o limite de envio de ficheiros para 10GB. Isto está agora disponível tanto nas aplicações de computador como móveis."), + "cLDesc2": MessageLookupByLibrary.simpleMessage( + "Os envios em segundo plano agora também são suportados no iOS, além dos dispositivos Android. Não é necessário abrir a aplicação para fazer uma cópia de segurança das suas fotografias e vídeos mais recentes."), + "cLDesc3": MessageLookupByLibrary.simpleMessage( + "Fizemos melhorias significativas na nossa experiência de memórias, incluindo reprodução automática, deslizar para a próxima memória e muito mais."), + "cLDesc4": MessageLookupByLibrary.simpleMessage( + "Juntamente com várias melhorias internas, agora é muito mais fácil ver todas as faces detectadas, fornecer comentários sobre faces similares e adicionar/remover faces de uma única fotografia."), + "cLDesc5": MessageLookupByLibrary.simpleMessage( + "Agora receberá uma notificação opcional para todos os aniversários que guardou no Ente, juntamente com uma colecção das suas melhores fotografias."), + "cLDesc6": MessageLookupByLibrary.simpleMessage( + "Já não é necessário esperar que os envios/transferências sejam concluídos antes de poder fechar a aplicação. Todos os envios e transferências têm agora a capacidade de serem pausados a meio e retomados de onde parou."), + "cLTitle1": MessageLookupByLibrary.simpleMessage( + "Envio de ficheiros de vídeo grandes"), + "cLTitle2": + MessageLookupByLibrary.simpleMessage("Envio em segundo plano"), + "cLTitle3": MessageLookupByLibrary.simpleMessage( + "Reprodução automática de memórias"), + "cLTitle4": MessageLookupByLibrary.simpleMessage( + "Reconhecimento facial melhorado"), + "cLTitle5": + MessageLookupByLibrary.simpleMessage("Notificações de aniversário"), + "cLTitle6": MessageLookupByLibrary.simpleMessage( + "Envios e transferências retomáveis"), "cachedData": MessageLookupByLibrary.simpleMessage("Dados em cache"), "calculating": MessageLookupByLibrary.simpleMessage("Calcular..."), + "canNotOpenBody": MessageLookupByLibrary.simpleMessage( + "Perdão, portanto o álbum não pode ser aberto na aplicação."), + "canNotOpenTitle": + MessageLookupByLibrary.simpleMessage("Não pôde abrir este álbum"), "canNotUploadToAlbumsOwnedByOthers": MessageLookupByLibrary.simpleMessage( "Não é possível fazer upload para álbuns pertencentes a outros"), @@ -426,12 +614,17 @@ class MessageLookup extends MessageLookupByLibrary { "canOnlyRemoveFilesOwnedByYou": MessageLookupByLibrary.simpleMessage(""), "cancel": MessageLookupByLibrary.simpleMessage("Cancelar"), + "cancelAccountRecovery": + MessageLookupByLibrary.simpleMessage("Cancelar recuperação"), + "cancelAccountRecoveryBody": MessageLookupByLibrary.simpleMessage( + "Quer mesmo cancelar a recuperação?"), "cancelOtherSubscription": m12, "cancelSubscription": MessageLookupByLibrary.simpleMessage("Cancelar subscrição"), "cannotAddMorePhotosAfterBecomingViewer": m13, "cannotDeleteSharedFiles": MessageLookupByLibrary.simpleMessage( "Não é possível eliminar ficheiros partilhados"), + "castAlbum": MessageLookupByLibrary.simpleMessage("Transfere Álbum"), "castIPMismatchBody": MessageLookupByLibrary.simpleMessage( "Certifique-se de estar na mesma rede que a TV."), "castIPMismatchTitle": @@ -459,6 +652,7 @@ class MessageLookup extends MessageLookupByLibrary { "checking": MessageLookupByLibrary.simpleMessage("A verificar..."), "checkingModels": MessageLookupByLibrary.simpleMessage("A verificar modelos..."), + "city": MessageLookupByLibrary.simpleMessage("Na cidade"), "claimFreeStorage": MessageLookupByLibrary.simpleMessage( "Solicitar armazenamento gratuito"), "claimMore": MessageLookupByLibrary.simpleMessage("Reclamar mais!"), @@ -474,7 +668,7 @@ class MessageLookup extends MessageLookupByLibrary { "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage("• Clique no menu adicional"), "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), + "Clica para transferir a melhor versão"), "close": MessageLookupByLibrary.simpleMessage("Fechar"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage( "Agrupar por tempo de captura"), @@ -516,6 +710,7 @@ class MessageLookup extends MessageLookupByLibrary { "Tem a certeza de que pretende desativar a autenticação de dois fatores?"), "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage( "Confirmar eliminação de conta"), + "confirmAddingTrustedContact": m17, "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( "Sim, pretendo apagar permanentemente esta conta e os respetivos dados em todas as aplicações."), "confirmPassword": @@ -571,13 +766,18 @@ class MessageLookup extends MessageLookupByLibrary { "criticalUpdateAvailable": MessageLookupByLibrary.simpleMessage( "Atualização crítica disponível"), "crop": MessageLookupByLibrary.simpleMessage("Recortar"), + "curatedMemories": + MessageLookupByLibrary.simpleMessage("Memórias curadas"), "currentUsageIs": MessageLookupByLibrary.simpleMessage("O uso atual é "), + "currentlyRunning": MessageLookupByLibrary.simpleMessage("em execução"), "custom": MessageLookupByLibrary.simpleMessage("Personalizado"), "customEndpoint": m20, "darkTheme": MessageLookupByLibrary.simpleMessage("Escuro"), "dayToday": MessageLookupByLibrary.simpleMessage("Hoje"), "dayYesterday": MessageLookupByLibrary.simpleMessage("Ontem"), + "declineTrustInvite": + MessageLookupByLibrary.simpleMessage("Dispense o Convite"), "decrypting": MessageLookupByLibrary.simpleMessage("A desencriptar…"), "decryptingVideo": MessageLookupByLibrary.simpleMessage("Descriptografando vídeo..."), @@ -612,8 +812,9 @@ class MessageLookup extends MessageLookupByLibrary { "deleteItemCount": m21, "deleteLocation": MessageLookupByLibrary.simpleMessage("Apagar localização"), + "deleteMultipleAlbumDialog": m22, "deletePhotos": MessageLookupByLibrary.simpleMessage("Apagar fotos"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Falta uma funcionalidade-chave de que eu necessito"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -653,7 +854,7 @@ class MessageLookup extends MessageLookupByLibrary { "Visualizadores ainda podem fazer capturas de tela ou salvar uma cópia das suas fotos usando ferramentas externas"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Por favor, observe"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Desativar autenticação de dois fatores"), "disablingTwofactorAuthentication": @@ -691,33 +892,44 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Pretende eliminar as edições que efectuou?"), "done": MessageLookupByLibrary.simpleMessage("Concluído"), + "dontSave": MessageLookupByLibrary.simpleMessage("Não guarde"), "doubleYourStorage": MessageLookupByLibrary.simpleMessage( "Duplicar o seu armazenamento"), "download": MessageLookupByLibrary.simpleMessage("Download"), "downloadFailed": MessageLookupByLibrary.simpleMessage("Falha no download"), "downloading": MessageLookupByLibrary.simpleMessage("A transferir..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("Editar"), + "editEmailAlreadyLinked": m28, "editLocation": MessageLookupByLibrary.simpleMessage("Editar localização"), "editLocationTagTitle": MessageLookupByLibrary.simpleMessage("Editar localização"), "editPerson": MessageLookupByLibrary.simpleMessage("Editar pessoa"), + "editTime": MessageLookupByLibrary.simpleMessage("Editar tempo"), "editsSaved": MessageLookupByLibrary.simpleMessage("Edição guardada"), "editsToLocationWillOnlyBeSeenWithinEnte": MessageLookupByLibrary.simpleMessage( "Edições para localização só serão vistas dentro do Ente"), "eligible": MessageLookupByLibrary.simpleMessage("elegível"), "email": MessageLookupByLibrary.simpleMessage("Email"), - "emailChangedTo": m28, - "emailNoEnteAccount": m30, + "emailAlreadyRegistered": + MessageLookupByLibrary.simpleMessage("E-mail já em utilização."), + "emailChangedTo": m29, + "emailDoesNotHaveEnteAccount": m30, + "emailNoEnteAccount": m31, + "emailNotRegistered": + MessageLookupByLibrary.simpleMessage("E-mail não em utilização."), "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("Verificação por e-mail"), "emailYourLogs": MessageLookupByLibrary.simpleMessage("Enviar logs por e-mail"), + "embracingThem": m32, + "emergencyContacts": + MessageLookupByLibrary.simpleMessage("Contactos de Emergência"), "empty": MessageLookupByLibrary.simpleMessage("Esvaziar"), "emptyTrash": MessageLookupByLibrary.simpleMessage("Esvaziar lixo?"), "enable": MessageLookupByLibrary.simpleMessage("Ativar"), @@ -774,8 +986,10 @@ class MessageLookup extends MessageLookupByLibrary { "Introduzir o código de 6 dígitos da\nsua aplicação de autenticação"), "enterValidEmail": MessageLookupByLibrary.simpleMessage( "Por favor, insira um endereço de email válido."), - "enterYourEmailAddress": MessageLookupByLibrary.simpleMessage( - "Insira o seu endereço de email"), + "enterYourEmailAddress": + MessageLookupByLibrary.simpleMessage("Introduza o seu e-mail"), + "enterYourNewEmailAddress": + MessageLookupByLibrary.simpleMessage("Introduza o seu novo e-mail"), "enterYourPassword": MessageLookupByLibrary.simpleMessage( "Introduza a sua palavra-passe"), "enterYourRecoveryKey": MessageLookupByLibrary.simpleMessage( @@ -792,10 +1006,13 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Exportar os seus dados"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage( "Fotos adicionais encontradas"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, + "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage( + "Rosto não aglomerado ainda, retome mais tarde"), "faceRecognition": MessageLookupByLibrary.simpleMessage("Reconhecimento facial"), "faces": MessageLookupByLibrary.simpleMessage("Rostos"), + "failed": MessageLookupByLibrary.simpleMessage("Falha"), "failedToApplyCode": MessageLookupByLibrary.simpleMessage("Falha ao aplicar código"), "failedToCancel": @@ -828,18 +1045,22 @@ class MessageLookup extends MessageLookupByLibrary { "faq": MessageLookupByLibrary.simpleMessage("Perguntas Frequentes"), "faqs": MessageLookupByLibrary.simpleMessage("Perguntas frequentes"), "favorite": MessageLookupByLibrary.simpleMessage("Favorito"), + "feastingWithThem": m34, "feedback": MessageLookupByLibrary.simpleMessage("Opinião"), + "file": MessageLookupByLibrary.simpleMessage("Ficheiro"), "fileFailedToSaveToGallery": MessageLookupByLibrary.simpleMessage( "Falha ao guardar o ficheiro na galeria"), "fileInfoAddDescHint": MessageLookupByLibrary.simpleMessage("Acrescente uma descrição..."), + "fileNotUploadedYet": + MessageLookupByLibrary.simpleMessage("Ficheiro não enviado ainda"), "fileSavedToGallery": MessageLookupByLibrary.simpleMessage("Arquivo guardado na galeria"), "fileTypes": MessageLookupByLibrary.simpleMessage("Tipos de arquivo"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Tipos de arquivo e nomes"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("Arquivos apagados"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage( @@ -849,6 +1070,7 @@ class MessageLookup extends MessageLookupByLibrary { "findThemQuickly": MessageLookupByLibrary.simpleMessage("Ache-os rapidamente"), "flip": MessageLookupByLibrary.simpleMessage("Inverter"), + "food": MessageLookupByLibrary.simpleMessage("Culinária saborosa"), "forYourMemories": MessageLookupByLibrary.simpleMessage("para suas memórias"), "forgotPassword": MessageLookupByLibrary.simpleMessage( @@ -857,23 +1079,26 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Rostos encontrados"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage( "Armazenamento gratuito reclamado"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage( "Armazenamento livre utilizável"), "freeTrial": MessageLookupByLibrary.simpleMessage("Teste grátis"), - "freeTrialValidTill": m37, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAccessPostDelete": m39, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage( "Libertar espaço no dispositivo"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Poupe espaço no seu dispositivo limpando ficheiros dos quais já foi feita uma cópia de segurança."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Libertar espaço"), + "freeUpSpaceSaving": m41, + "gallery": MessageLookupByLibrary.simpleMessage("Galeria"), "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Até 1000 memórias mostradas na galeria"), "general": MessageLookupByLibrary.simpleMessage("Geral"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Gerando chaves de encriptação..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("Ir para as definições"), "googlePlayId": @@ -882,11 +1107,14 @@ class MessageLookup extends MessageLookupByLibrary { "Por favor, permita o acesso a todas as fotos nas definições do aplicativo"), "grantPermission": MessageLookupByLibrary.simpleMessage("Conceder permissão"), + "greenery": MessageLookupByLibrary.simpleMessage("A vida esverdeada"), "groupNearbyPhotos": MessageLookupByLibrary.simpleMessage("Agrupar fotos próximas"), "guestView": MessageLookupByLibrary.simpleMessage("Visão de convidado"), "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( "Para ativar a vista de convidado, configure o código de acesso do dispositivo ou o bloqueio do ecrã nas definições do sistema."), + "happyBirthday": + MessageLookupByLibrary.simpleMessage("Felicidades! 🥳"), "hearUsExplanation": MessageLookupByLibrary.simpleMessage( "Não monitorizamos as instalações de aplicações. Ajudaria se nos dissesse onde nos encontrou!"), "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( @@ -899,7 +1127,10 @@ class MessageLookup extends MessageLookupByLibrary { "Oculta o conteúdo da aplicação no alternador de aplicações e desactiva as capturas de ecrã"), "hideContentDescriptionIos": MessageLookupByLibrary.simpleMessage( "Oculta o conteúdo da aplicação no alternador de aplicações"), + "hideSharedItemsFromHomeGallery": MessageLookupByLibrary.simpleMessage( + "Esconder Itens Partilhados da Galeria Inicial"), "hiding": MessageLookupByLibrary.simpleMessage("Ocultando..."), + "hikingWithThem": m43, "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("Hospedado na OSM France"), "howItWorks": MessageLookupByLibrary.simpleMessage("Como funciona"), @@ -911,8 +1142,11 @@ class MessageLookup extends MessageLookupByLibrary { "A autenticação biométrica está desativada. Por favor, bloqueie e desbloqueie o ecrã para ativá-la."), "iOSOkButton": MessageLookupByLibrary.simpleMessage("OK"), "ignoreUpdate": MessageLookupByLibrary.simpleMessage("Ignorar"), + "ignored": MessageLookupByLibrary.simpleMessage("ignorado"), "ignoredFolderUploadReason": MessageLookupByLibrary.simpleMessage( "Alguns ficheiros deste álbum não podem ser carregados porque foram anteriormente eliminados do Ente."), + "imageNotAnalyzed": + MessageLookupByLibrary.simpleMessage("Imagem sem análise"), "immediately": MessageLookupByLibrary.simpleMessage("Imediatamente"), "importing": MessageLookupByLibrary.simpleMessage("A importar..."), "incorrectCode": @@ -928,6 +1162,8 @@ class MessageLookup extends MessageLookupByLibrary { "indexedItems": MessageLookupByLibrary.simpleMessage("Itens indexados"), "indexingIsPaused": MessageLookupByLibrary.simpleMessage( "A indexação está pausada, será retomada automaticamente quando o dispositivo estiver pronto."), + "ineligible": MessageLookupByLibrary.simpleMessage("Inelegível"), + "info": MessageLookupByLibrary.simpleMessage("Info"), "insecureDevice": MessageLookupByLibrary.simpleMessage("Dispositivo inseguro"), "installManually": @@ -951,12 +1187,20 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Parece que algo correu mal. Por favor, tente novamente após algum tempo. Se o erro persistir, contacte a nossa equipa de apoio."), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Os itens mostram o número de dias restantes antes da eliminação permanente"), "itemsWillBeRemovedFromAlbum": MessageLookupByLibrary.simpleMessage( "Os itens selecionados serão removidos deste álbum"), + "join": MessageLookupByLibrary.simpleMessage("Aderir"), + "joinAlbum": MessageLookupByLibrary.simpleMessage("Aderir ao Álbum"), + "joinAlbumConfirmationDialogBody": MessageLookupByLibrary.simpleMessage( + "Aderir a um álbum fará o seu e-mail visível aos participantes."), + "joinAlbumSubtext": MessageLookupByLibrary.simpleMessage( + "para ver e adicionar as suas fotos"), + "joinAlbumSubtextViewer": MessageLookupByLibrary.simpleMessage( + "para adicionar isto aos álbuns partilhados"), "joinDiscord": MessageLookupByLibrary.simpleMessage("Juntar-se ao Discord"), "keepPhotos": MessageLookupByLibrary.simpleMessage("Manter fotos"), @@ -964,8 +1208,11 @@ class MessageLookup extends MessageLookupByLibrary { "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( "Por favor, ajude-nos com esta informação"), "language": MessageLookupByLibrary.simpleMessage("Idioma"), + "lastTimeWithThem": m45, "lastUpdated": MessageLookupByLibrary.simpleMessage("Última atualização"), + "lastYearsTrip": + MessageLookupByLibrary.simpleMessage("Viagem do ano passado"), "leave": MessageLookupByLibrary.simpleMessage("Sair"), "leaveAlbum": MessageLookupByLibrary.simpleMessage("Sair do álbum"), "leaveFamily": @@ -973,23 +1220,42 @@ class MessageLookup extends MessageLookupByLibrary { "leaveSharedAlbum": MessageLookupByLibrary.simpleMessage( "Sair do álbum compartilhado?"), "left": MessageLookupByLibrary.simpleMessage("Esquerda"), + "legacy": MessageLookupByLibrary.simpleMessage("Revivência"), + "legacyAccounts": + MessageLookupByLibrary.simpleMessage("Contas revividas"), + "legacyInvite": m46, + "legacyPageDesc": MessageLookupByLibrary.simpleMessage( + "A Revivência permite que contactos de confiança acessem a sua conta na sua inatividade."), + "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( + "Contactos de confiança podem restaurar a sua conta, e se não lhes impedir em 30 dias, redefine a sua palavra-passe e acesse a sua conta."), "light": MessageLookupByLibrary.simpleMessage("Claro"), "lightTheme": MessageLookupByLibrary.simpleMessage("Claro"), + "link": MessageLookupByLibrary.simpleMessage("Ligar"), "linkCopiedToClipboard": MessageLookupByLibrary.simpleMessage( "Link copiado para a área de transferência"), "linkDeviceLimit": MessageLookupByLibrary.simpleMessage("Limite de dispositivo"), + "linkEmail": MessageLookupByLibrary.simpleMessage("Ligar e-mail"), + "linkEmailToContactBannerCaption": + MessageLookupByLibrary.simpleMessage("para partilha ágil"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Ativado"), "linkExpired": MessageLookupByLibrary.simpleMessage("Expirado"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Link expirado"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("O link expirou"), "linkNeverExpires": MessageLookupByLibrary.simpleMessage("Nunca"), + "linkPerson": MessageLookupByLibrary.simpleMessage("Ligar pessoa"), + "linkPersonCaption": MessageLookupByLibrary.simpleMessage( + "para melhor experiência de partilha"), + "linkPersonToEmail": m48, + "linkPersonToEmailConfirmation": m49, "livePhotos": MessageLookupByLibrary.simpleMessage("Fotos Em Tempo Real"), "loadMessage1": MessageLookupByLibrary.simpleMessage( "Pode partilhar a sua subscrição com a sua família"), + "loadMessage2": MessageLookupByLibrary.simpleMessage( + "Já contivemos 200 milhões de memórias até o momento"), "loadMessage3": MessageLookupByLibrary.simpleMessage( "Mantemos 3 cópias dos seus dados, uma em um abrigo subterrâneo"), "loadMessage4": MessageLookupByLibrary.simpleMessage( @@ -1047,8 +1313,8 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Pressione e segure em um item para ver em tela cheia"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), + "lookBackOnYourMemories": + MessageLookupByLibrary.simpleMessage("Revê as suas memórias 🌄"), "loopVideoOff": MessageLookupByLibrary.simpleMessage("Repetir vídeo desligado"), "loopVideoOn": @@ -1061,6 +1327,8 @@ class MessageLookup extends MessageLookupByLibrary { "magicSearchHint": MessageLookupByLibrary.simpleMessage( "A pesquisa mágica permite pesquisar fotos por seu conteúdo, por exemplo, \'flor\', \'carro vermelho\', \'documentos de identidade\'"), "manage": MessageLookupByLibrary.simpleMessage("Gerir"), + "manageDeviceStorage": + MessageLookupByLibrary.simpleMessage("Gerir cache do aparelho"), "manageDeviceStorageDesc": MessageLookupByLibrary.simpleMessage( "Reveja e limpe o armazenamento de cache local."), "manageFamily": MessageLookupByLibrary.simpleMessage("Gerir família"), @@ -1074,6 +1342,11 @@ class MessageLookup extends MessageLookupByLibrary { "maps": MessageLookupByLibrary.simpleMessage("Mapas"), "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), + "me": MessageLookupByLibrary.simpleMessage("Eu"), + "memories": MessageLookupByLibrary.simpleMessage("Memórias"), + "memoriesWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Seleciona os tipos de memórias que adoraria ver no seu ecrã inicial."), + "memoryCount": m50, "merchandise": MessageLookupByLibrary.simpleMessage("Produtos"), "mergeWithExisting": MessageLookupByLibrary.simpleMessage("Juntar com o existente"), @@ -1098,14 +1371,20 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Modifique a sua consulta ou tente pesquisar por"), "moments": MessageLookupByLibrary.simpleMessage("Momentos"), + "month": MessageLookupByLibrary.simpleMessage("mês"), "monthly": MessageLookupByLibrary.simpleMessage("Mensal"), + "moon": MessageLookupByLibrary.simpleMessage("Na luz da lua"), "moreDetails": MessageLookupByLibrary.simpleMessage("Mais detalhes"), "mostRecent": MessageLookupByLibrary.simpleMessage("Mais recente"), "mostRelevant": MessageLookupByLibrary.simpleMessage("Mais relevante"), + "mountains": MessageLookupByLibrary.simpleMessage("Sobre as colinas"), + "moveItem": m51, + "moveSelectedPhotosToOneDate": MessageLookupByLibrary.simpleMessage( + "Alterar datas de Fotos ao Selecionado"), "moveToAlbum": MessageLookupByLibrary.simpleMessage("Mover para álbum"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Mover para álbum oculto"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("Mover para o lixo"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1118,8 +1397,10 @@ class MessageLookup extends MessageLookupByLibrary { "Não foi possível estabelecer ligação ao Ente. Verifique as definições de rede e contacte o serviço de apoio se o erro persistir."), "never": MessageLookupByLibrary.simpleMessage("Nunca"), "newAlbum": MessageLookupByLibrary.simpleMessage("Novo álbum"), + "newLocation": MessageLookupByLibrary.simpleMessage("Novo Lugar"), "newPerson": MessageLookupByLibrary.simpleMessage("Nova pessoa"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), + "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" novo 📸"), + "newRange": MessageLookupByLibrary.simpleMessage("Novo intervalo"), "newToEnte": MessageLookupByLibrary.simpleMessage("Novo no Ente"), "newest": MessageLookupByLibrary.simpleMessage("Recentes"), "next": MessageLookupByLibrary.simpleMessage("Seguinte"), @@ -1133,7 +1414,11 @@ class MessageLookup extends MessageLookupByLibrary { "Você não tem arquivos neste dispositivo que possam ser apagados"), "noDuplicates": MessageLookupByLibrary.simpleMessage("✨ Sem duplicados"), + "noEnteAccountExclamation": + MessageLookupByLibrary.simpleMessage("Nenhuma conta do Ente!"), "noExifData": MessageLookupByLibrary.simpleMessage("Sem dados EXIF"), + "noFacesFound": + MessageLookupByLibrary.simpleMessage("Nenhum rosto foi detetado"), "noHiddenPhotosOrVideos": MessageLookupByLibrary.simpleMessage("Sem fotos ou vídeos ocultos"), "noImagesWithLocation": MessageLookupByLibrary.simpleMessage( @@ -1154,9 +1439,12 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Nenhum resultado"), "noResultsFound": MessageLookupByLibrary.simpleMessage( "Não foram encontrados resultados"), + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage( "Nenhum bloqueio de sistema encontrado"), - "notPersonLabel": m53, + "notPersonLabel": m54, + "notThisPerson": + MessageLookupByLibrary.simpleMessage("Não é esta pessoa?"), "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( "Ainda nada partilhado consigo"), "nothingToSeeHere": @@ -1166,16 +1454,25 @@ class MessageLookup extends MessageLookupByLibrary { "onDevice": MessageLookupByLibrary.simpleMessage("No dispositivo"), "onEnte": MessageLookupByLibrary.simpleMessage( "Em ente"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "onTheRoad": MessageLookupByLibrary.simpleMessage("Na rua de novo"), + "onThisDay": MessageLookupByLibrary.simpleMessage("Neste dia"), + "onThisDayMemories": + MessageLookupByLibrary.simpleMessage("Memórias deste dia"), + "onThisDayNotificationExplanation": + MessageLookupByLibrary.simpleMessage( + "Obtém lembretes de memórias deste dia em anos passados."), + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("Apenas eles"), "oops": MessageLookupByLibrary.simpleMessage("Oops"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( "Oops, não foi possível guardar as edições"), "oopsSomethingWentWrong": MessageLookupByLibrary.simpleMessage("Ops, algo deu errado"), + "openAlbumInBrowser": + MessageLookupByLibrary.simpleMessage("Abrir o Álbum em Navegador"), + "openAlbumInBrowserTitle": MessageLookupByLibrary.simpleMessage( + "Utilize a Aplicação de Web Sítio para adicionar fotos ao álbum"), + "openFile": MessageLookupByLibrary.simpleMessage("Abrir o Ficheiro"), "openSettings": MessageLookupByLibrary.simpleMessage("Abrir Definições"), "openTheItem": MessageLookupByLibrary.simpleMessage("• Abra o item"), @@ -1187,12 +1484,15 @@ class MessageLookup extends MessageLookupByLibrary { "Ou combinar com já existente"), "orPickAnExistingOne": MessageLookupByLibrary.simpleMessage("Ou escolha um já existente"), + "orPickFromYourContacts": MessageLookupByLibrary.simpleMessage( + "ou selecione dos seus contactos"), "pair": MessageLookupByLibrary.simpleMessage("Emparelhar"), "pairWithPin": MessageLookupByLibrary.simpleMessage("Emparelhar com PIN"), "pairingComplete": MessageLookupByLibrary.simpleMessage("Emparelhamento concluído"), "panorama": MessageLookupByLibrary.simpleMessage("Panorama"), + "partyWithThem": m56, "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage( "A verificação ainda está pendente"), "passkey": MessageLookupByLibrary.simpleMessage("Chave de acesso"), @@ -1203,47 +1503,61 @@ class MessageLookup extends MessageLookupByLibrary { "Palavra-passe alterada com sucesso"), "passwordLock": MessageLookupByLibrary.simpleMessage("Bloqueio da palavra-passe"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "A força da palavra-passe é calculada tendo em conta o comprimento da palavra-passe, os caracteres utilizados e se a palavra-passe aparece ou não nas 10.000 palavras-passe mais utilizadas"), "passwordWarning": MessageLookupByLibrary.simpleMessage( "Não armazenamos esta palavra-passe, se você a esquecer, não podemos desencriptar os seus dados"), + "pastYearsMemories": + MessageLookupByLibrary.simpleMessage("Memórias de anos passados"), "paymentDetails": MessageLookupByLibrary.simpleMessage("Detalhes de pagamento"), "paymentFailed": MessageLookupByLibrary.simpleMessage("O pagamento falhou"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Infelizmente o seu pagamento falhou. Entre em contato com o suporte e nós ajudaremos você!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("Itens pendentes"), "pendingSync": MessageLookupByLibrary.simpleMessage("Sincronização pendente"), "people": MessageLookupByLibrary.simpleMessage("Pessoas"), "peopleUsingYourCode": MessageLookupByLibrary.simpleMessage( "Pessoas que utilizam seu código"), + "peopleWidgetDesc": MessageLookupByLibrary.simpleMessage( + "Seleciona as pessoas que adoraria ver no seu ecrã inicial."), "permDeleteWarning": MessageLookupByLibrary.simpleMessage( "Todos os itens no lixo serão permanentemente eliminados\n\n\nEsta ação não pode ser anulada"), "permanentlyDelete": MessageLookupByLibrary.simpleMessage("Eliminar permanentemente"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage( "Apagar permanentemente do dispositivo?"), + "personIsAge": m59, "personName": MessageLookupByLibrary.simpleMessage("Nome da pessoa"), + "personTurningAge": m60, + "pets": MessageLookupByLibrary.simpleMessage("Acompanhantes peludos"), "photoDescriptions": MessageLookupByLibrary.simpleMessage("Descrições das fotos"), "photoGridSize": MessageLookupByLibrary.simpleMessage("Tamanho da grelha de fotos"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("foto"), + "photocountPhotos": m61, "photos": MessageLookupByLibrary.simpleMessage("Fotos"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage( "As fotos adicionadas por si serão removidas do álbum"), + "photosCount": m62, + "photosKeepRelativeTimeDifference": + MessageLookupByLibrary.simpleMessage( + "As Fotos continuam com uma diferença de horário relativo"), "pickCenterPoint": MessageLookupByLibrary.simpleMessage("Escolha o ponto central"), "pinAlbum": MessageLookupByLibrary.simpleMessage("Fixar álbum"), "pinLock": MessageLookupByLibrary.simpleMessage("Bloqueio por PIN"), "playOnTv": MessageLookupByLibrary.simpleMessage("Reproduzir álbum na TV"), - "playStoreFreeTrialValidTill": m62, + "playOriginal": MessageLookupByLibrary.simpleMessage("Ver original"), + "playStoreFreeTrialValidTill": m63, + "playStream": MessageLookupByLibrary.simpleMessage("Ver em direto"), "playstoreSubscription": MessageLookupByLibrary.simpleMessage("Subscrição da PlayStore"), "pleaseCheckYourInternetConnectionAndTryAgain": @@ -1255,14 +1569,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Por favor, contate o suporte se o problema persistir"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage( "Por favor, conceda as permissões"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage( "Por favor, inicie sessão novamente"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Selecione links rápidos para remover"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Por favor, tente novamente"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1275,6 +1589,9 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseWaitForSometimeBeforeRetrying": MessageLookupByLibrary.simpleMessage( "Por favor, aguarde algum tempo antes de tentar novamente"), + "pleaseWaitThisWillTakeAWhile": MessageLookupByLibrary.simpleMessage( + "Espera um pouco, isto deve levar um tempo."), + "posingWithThem": m66, "preparingLogs": MessageLookupByLibrary.simpleMessage("Preparando logs..."), "preserveMore": MessageLookupByLibrary.simpleMessage("Preservar mais"), @@ -1282,6 +1599,7 @@ class MessageLookup extends MessageLookupByLibrary { "Pressione e segure para reproduzir o vídeo"), "pressAndHoldToPlayVideoDetailed": MessageLookupByLibrary.simpleMessage( "Pressione e segure na imagem para reproduzir o vídeo"), + "previous": MessageLookupByLibrary.simpleMessage("Anterior"), "privacy": MessageLookupByLibrary.simpleMessage("Privacidade"), "privacyPolicyTitle": MessageLookupByLibrary.simpleMessage("Política de privacidade"), @@ -1289,21 +1607,38 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Backups privados"), "privateSharing": MessageLookupByLibrary.simpleMessage("Partilha privada"), - "processingImport": m66, + "proceed": MessageLookupByLibrary.simpleMessage("Continuar"), + "processed": MessageLookupByLibrary.simpleMessage("Processado"), + "processing": MessageLookupByLibrary.simpleMessage("A processar"), + "processingImport": m67, + "processingVideos": + MessageLookupByLibrary.simpleMessage("A processar vídeos"), "publicLinkCreated": MessageLookupByLibrary.simpleMessage("Link público criado"), "publicLinkEnabled": MessageLookupByLibrary.simpleMessage("Link público ativado"), + "queued": MessageLookupByLibrary.simpleMessage("Em fila"), "quickLinks": MessageLookupByLibrary.simpleMessage("Links rápidos"), "radius": MessageLookupByLibrary.simpleMessage("Raio"), "raiseTicket": MessageLookupByLibrary.simpleMessage("Abrir ticket"), "rateTheApp": MessageLookupByLibrary.simpleMessage("Avaliar aplicação"), "rateUs": MessageLookupByLibrary.simpleMessage("Avalie-nos"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, + "reassignMe": MessageLookupByLibrary.simpleMessage("Retribua \"Mim\""), + "reassignedToName": m69, + "reassigningLoading": + MessageLookupByLibrary.simpleMessage("A retribuir..."), + "receiveRemindersOnBirthdays": MessageLookupByLibrary.simpleMessage( + "Obtém lembretes de quando é aniversário de alguém. Apertar na notificação o levará às fotos do aniversariante."), "recover": MessageLookupByLibrary.simpleMessage("Recuperar"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Recuperar conta"), "recoverButton": MessageLookupByLibrary.simpleMessage("Recuperar"), + "recoveryAccount": + MessageLookupByLibrary.simpleMessage("Recuperar Conta"), + "recoveryInitiated": + MessageLookupByLibrary.simpleMessage("Recuperação iniciada"), + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("Chave de recuperação"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( @@ -1318,8 +1653,12 @@ class MessageLookup extends MessageLookupByLibrary { "Chave de recuperação verificada"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "A sua chave de recuperação é a única forma de recuperar as suas fotografias se se esquecer da sua palavra-passe. Pode encontrar a sua chave de recuperação em Definições > Conta.\n\n\nIntroduza aqui a sua chave de recuperação para verificar se a guardou corretamente."), + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage("Recuperação bem sucedida!"), + "recoveryWarning": MessageLookupByLibrary.simpleMessage( + "Um contacto de confiança está a tentar acessar a sua conta"), + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "O dispositivo atual não é suficientemente poderoso para verificar a palavra-passe, mas podemos regenerar novamente de uma maneira que funcione no seu dispositivo.\n\nPor favor, iniciar sessão utilizando código de recuperação e gerar novamente a sua palavra-passe (pode utilizar a mesma se quiser)."), "recreatePasswordTitle": @@ -1335,10 +1674,12 @@ class MessageLookup extends MessageLookupByLibrary { "1. Envie este código aos seus amigos"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Eles se inscrevem em um plano pago"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("Referências"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "As referências estão atualmente em pausa"), + "rejectRecovery": + MessageLookupByLibrary.simpleMessage("Recusar recuperação"), "remindToEmptyDeviceTrash": MessageLookupByLibrary.simpleMessage( "Esvazie também a opção “Eliminados recentemente” em “Definições” -> “Armazenamento” para reclamar o espaço libertado"), "remindToEmptyEnteTrash": MessageLookupByLibrary.simpleMessage( @@ -1358,10 +1699,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Remover do álbum"), "removeFromFavorite": MessageLookupByLibrary.simpleMessage("Remover dos favoritos"), + "removeInvite": MessageLookupByLibrary.simpleMessage("Retirar convite"), "removeLink": MessageLookupByLibrary.simpleMessage("Remover link"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Remover participante"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Remover etiqueta da pessoa"), "removePublicLink": @@ -1372,6 +1714,8 @@ class MessageLookup extends MessageLookupByLibrary { "Alguns dos itens que você está removendo foram adicionados por outras pessoas, e você perderá o acesso a eles"), "removeWithQuestionMark": MessageLookupByLibrary.simpleMessage("Remover?"), + "removeYourselfAsTrustedContact": MessageLookupByLibrary.simpleMessage( + "Retirar convosco dos contactos de confiança"), "removingFromFavorites": MessageLookupByLibrary.simpleMessage("Removendo dos favoritos..."), "rename": MessageLookupByLibrary.simpleMessage("Renomear"), @@ -1379,7 +1723,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("Renomear arquivo"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Renovar subscrição"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Reporte um bug"), "reportBug": MessageLookupByLibrary.simpleMessage("Reportar bug"), "resendEmail": MessageLookupByLibrary.simpleMessage("Reenviar e-mail"), @@ -1404,6 +1748,7 @@ class MessageLookup extends MessageLookupByLibrary { "reviewSuggestions": MessageLookupByLibrary.simpleMessage("Revisar sugestões"), "right": MessageLookupByLibrary.simpleMessage("Direita"), + "roadtripWithThem": m76, "rotate": MessageLookupByLibrary.simpleMessage("Rodar"), "rotateLeft": MessageLookupByLibrary.simpleMessage("Rodar para a esquerda"), @@ -1412,6 +1757,9 @@ class MessageLookup extends MessageLookupByLibrary { "safelyStored": MessageLookupByLibrary.simpleMessage("Armazenado com segurança"), "save": MessageLookupByLibrary.simpleMessage("Guardar"), + "saveChangesBeforeLeavingQuestion": + MessageLookupByLibrary.simpleMessage( + "Guardar as alterações antes de sair?"), "saveCollage": MessageLookupByLibrary.simpleMessage("Guardar colagem"), "saveCopy": MessageLookupByLibrary.simpleMessage("Guardar cópia"), "saveKey": MessageLookupByLibrary.simpleMessage("Guardar chave"), @@ -1437,6 +1785,8 @@ class MessageLookup extends MessageLookupByLibrary { "Adicione descrições como \"#trip\" nas informações das fotos para encontrá-las aqui rapidamente"), "searchDatesEmptySection": MessageLookupByLibrary.simpleMessage( "Pesquisar por data, mês ou ano"), + "searchDiscoverEmptySection": MessageLookupByLibrary.simpleMessage( + "As imagens aparecerão aqui caso o processamento e sincronização for concluído"), "searchFaceEmptySection": MessageLookupByLibrary.simpleMessage( "As pessoas serão mostradas aqui quando a indexação estiver concluída"), "searchFileTypesAndNamesEmptySection": @@ -1454,26 +1804,49 @@ class MessageLookup extends MessageLookupByLibrary { "Fotos de grupo que estão sendo tiradas em algum raio da foto"), "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage( "Convide pessoas e verá todas as fotos partilhadas por elas aqui"), - "searchResultCount": m76, + "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage( + "As pessoas aparecerão aqui caso o processamento e sincronização for concluído"), + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("Segurança"), + "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage( + "Ver Ligações Públicas na Aplicação"), "selectALocation": MessageLookupByLibrary.simpleMessage("Selecione uma localização"), "selectALocationFirst": MessageLookupByLibrary.simpleMessage( "Selecione uma localização primeiro"), "selectAlbum": MessageLookupByLibrary.simpleMessage("Selecionar álbum"), "selectAll": MessageLookupByLibrary.simpleMessage("Selecionar tudo"), + "selectAllShort": MessageLookupByLibrary.simpleMessage("Tudo"), + "selectCoverPhoto": + MessageLookupByLibrary.simpleMessage("Selecione Foto para Capa"), + "selectDate": MessageLookupByLibrary.simpleMessage("Selecionar data"), "selectFoldersForBackup": MessageLookupByLibrary.simpleMessage( "Selecionar pastas para cópia de segurança"), "selectItemsToAdd": MessageLookupByLibrary.simpleMessage( "Selecionar itens para adicionar"), "selectLanguage": MessageLookupByLibrary.simpleMessage("Selecionar Idioma"), + "selectMailApp": MessageLookupByLibrary.simpleMessage( + "Selecione Aplicação de Correios"), "selectMorePhotos": MessageLookupByLibrary.simpleMessage("Selecionar mais fotos"), + "selectOneDateAndTime": + MessageLookupByLibrary.simpleMessage("Selecione uma Data e Hora"), + "selectOneDateAndTimeForAll": MessageLookupByLibrary.simpleMessage( + "Selecionar uma data e hora a todos"), + "selectPersonToLink": MessageLookupByLibrary.simpleMessage( + "Selecione uma pessoa para ligar-se"), "selectReason": MessageLookupByLibrary.simpleMessage("Selecionar motivo"), + "selectStartOfRange": MessageLookupByLibrary.simpleMessage( + "Selecionar início de intervalo"), + "selectTime": MessageLookupByLibrary.simpleMessage("Selecionar tempo"), + "selectYourFace": + MessageLookupByLibrary.simpleMessage("Selecionar o seu rosto"), "selectYourPlan": MessageLookupByLibrary.simpleMessage("Selecione o seu plano"), + "selectedAlbums": m79, "selectedFilesAreNotOnEnte": MessageLookupByLibrary.simpleMessage( "Os arquivos selecionados não estão no Ente"), "selectedFoldersWillBeEncryptedAndBackedUp": @@ -1482,8 +1855,12 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage( "Os itens selecionados serão eliminados de todos os álbuns e movidos para o lixo."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, + "selectedItemsWillBeRemovedFromThisPerson": + MessageLookupByLibrary.simpleMessage( + "Os itens em seleção serão removidos desta pessoa, mas não da sua biblioteca."), + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, + "selfiesWithThem": m82, "send": MessageLookupByLibrary.simpleMessage("Enviar"), "sendEmail": MessageLookupByLibrary.simpleMessage("Enviar email"), "sendInvite": MessageLookupByLibrary.simpleMessage("Enviar convite"), @@ -1514,16 +1891,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Partilhar um álbum"), "shareLink": MessageLookupByLibrary.simpleMessage("Partilhar link"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Partilhar apenas com as pessoas que deseja"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Descarregue o Ente para poder partilhar facilmente fotografias e vídeos de qualidade original\n\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Compartilhar com usuários que não usam Ente"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage( "Partilhe o seu primeiro álbum"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1536,12 +1913,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Novas fotos partilhadas"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "Receber notificações quando alguém adiciona uma foto a um álbum partilhado do qual faz parte"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Partilhado comigo"), "sharedWithYou": MessageLookupByLibrary.simpleMessage("Partilhado consigo"), "sharing": MessageLookupByLibrary.simpleMessage("Partilhar..."), + "shiftDatesAndTime": + MessageLookupByLibrary.simpleMessage("Mude as Datas e Horas"), "showMemories": MessageLookupByLibrary.simpleMessage("Mostrar memórias"), "showPerson": MessageLookupByLibrary.simpleMessage("Mostrar pessoa"), @@ -1553,12 +1932,14 @@ class MessageLookup extends MessageLookupByLibrary { "Terminar a sessão noutros dispositivos"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Eu concordo com os termos de serviço e política de privacidade"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "Será eliminado de todos os álbuns."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("Pular"), + "smartMemories": + MessageLookupByLibrary.simpleMessage("Memórias inteligentes"), "social": MessageLookupByLibrary.simpleMessage("Social"), "someItemsAreInBothEnteAndYourDevice": MessageLookupByLibrary.simpleMessage( @@ -1575,6 +1956,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Ocorreu um erro. Tente novamente"), "sorry": MessageLookupByLibrary.simpleMessage("Desculpe"), + "sorryBackupFailedDesc": MessageLookupByLibrary.simpleMessage( + "Perdão, mas não podemos fazer backup deste ficheiro agora, tentaremos mais tarde."), "sorryCouldNotAddToFavorites": MessageLookupByLibrary.simpleMessage( "Desculpe, não foi possível adicionar aos favoritos!"), "sorryCouldNotRemoveFromFavorites": @@ -1587,7 +1970,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Desculpe, não foi possível gerar chaves seguras neste dispositivo.\n\npor favor iniciar sessão com um dispositivo diferente."), "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), + "Perdão, precisamos parar seus backups"), "sort": MessageLookupByLibrary.simpleMessage("Ordenar"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Ordenar por"), "sortNewestFirst": @@ -1595,6 +1978,12 @@ class MessageLookup extends MessageLookupByLibrary { "sortOldestFirst": MessageLookupByLibrary.simpleMessage("Mais antigos primeiro"), "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ Sucesso"), + "sportsWithThem": m91, + "spotlightOnThem": m92, + "spotlightOnYourself": + MessageLookupByLibrary.simpleMessage("A dar destaque em vos"), + "startAccountRecoveryTitle": + MessageLookupByLibrary.simpleMessage("Começar Recuperação"), "startBackup": MessageLookupByLibrary.simpleMessage("Iniciar cópia de segurança"), "status": MessageLookupByLibrary.simpleMessage("Status"), @@ -1605,13 +1994,15 @@ class MessageLookup extends MessageLookupByLibrary { "storage": MessageLookupByLibrary.simpleMessage("Armazenamento"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Família"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Tu"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage( "Limite de armazenamento excedido"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, + "streamDetails": + MessageLookupByLibrary.simpleMessage("Detalhes do em direto"), "strongStrength": MessageLookupByLibrary.simpleMessage("Forte"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("Subscrever"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "Você precisa de uma assinatura paga ativa para ativar o compartilhamento."), @@ -1627,8 +2018,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Reexibido com sucesso"), "suggestFeatures": MessageLookupByLibrary.simpleMessage("Sugerir recursos"), + "sunrise": MessageLookupByLibrary.simpleMessage("No horizonte"), "support": MessageLookupByLibrary.simpleMessage("Suporte"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("Sincronização interrompida"), "syncing": MessageLookupByLibrary.simpleMessage("Sincronizando..."), @@ -1638,6 +2030,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Toque para inserir código"), "tapToUnlock": MessageLookupByLibrary.simpleMessage("Toque para desbloquear"), + "tapToUpload": + MessageLookupByLibrary.simpleMessage("Clique para enviar"), + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Parece que algo correu mal. Por favor, tente novamente mais tarde. Se o erro persistir, entre em contacto com a nossa equipa de suporte."), "terminate": MessageLookupByLibrary.simpleMessage("Terminar"), @@ -1650,6 +2045,9 @@ class MessageLookup extends MessageLookupByLibrary { "Obrigado pela sua subscrição!"), "theDownloadCouldNotBeCompleted": MessageLookupByLibrary.simpleMessage( "Não foi possível concluir o download."), + "theLinkYouAreTryingToAccessHasExpired": + MessageLookupByLibrary.simpleMessage( + "A ligação que está a tentar acessar já expirou."), "theRecoveryKeyYouEnteredIsIncorrect": MessageLookupByLibrary.simpleMessage( "A chave de recuperação inserida está incorreta"), @@ -1657,7 +2055,7 @@ class MessageLookup extends MessageLookupByLibrary { "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage( "Estes itens serão eliminados do seu dispositivo."), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage( "Serão eliminados de todos os álbuns."), "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( @@ -1673,17 +2071,26 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Este email já está em uso"), "thisImageHasNoExifData": MessageLookupByLibrary.simpleMessage( "Esta imagem não tem dados exif"), - "thisIsPersonVerificationId": m98, + "thisIsMeExclamation": + MessageLookupByLibrary.simpleMessage("Este sou eu!"), + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( "Este é o seu ID de verificação"), + "thisWeekThroughTheYears": MessageLookupByLibrary.simpleMessage( + "Esta semana com o avanço dos anos"), + "thisWeekXYearsAgo": m101, "thisWillLogYouOutOfTheFollowingDevice": MessageLookupByLibrary.simpleMessage( "Irá desconectar a sua conta do seguinte dispositivo:"), "thisWillLogYouOutOfThisDevice": MessageLookupByLibrary.simpleMessage( "Irá desconectar a sua conta do seu dispositivo!"), + "thisWillMakeTheDateAndTimeOfAllSelected": + MessageLookupByLibrary.simpleMessage( + "Isto fará a data e hora de todas as fotos o mesmo."), "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( "Isto removerá links públicos de todos os links rápidos selecionados."), + "throughTheYears": m102, "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": MessageLookupByLibrary.simpleMessage( "Para ativar o bloqueio de aplicações, configure o código de acesso do dispositivo ou o bloqueio de ecrã nas definições do sistema."), @@ -1697,8 +2104,13 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("total"), "totalSize": MessageLookupByLibrary.simpleMessage("Tamanho total"), "trash": MessageLookupByLibrary.simpleMessage("Lixo"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("Cortar"), + "tripInYear": m104, + "tripToLocation": m105, + "trustedContacts": + MessageLookupByLibrary.simpleMessage("Contactos de Confiança"), + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("Tente novamente"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "Ative o backup para enviar automaticamente arquivos adicionados a esta pasta do dispositivo para o Ente."), @@ -1717,7 +2129,7 @@ class MessageLookup extends MessageLookupByLibrary { "Autenticação de dois fatores redefinida com êxito"), "twofactorSetup": MessageLookupByLibrary.simpleMessage( "Configuração de dois fatores"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("Desarquivar"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("Desarquivar álbum"), @@ -1740,10 +2152,10 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage( "Atualizando seleção de pasta..."), "upgrade": MessageLookupByLibrary.simpleMessage("Atualizar"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Enviar ficheiros para o álbum..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage("Preservar 1 memória..."), "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( @@ -1751,6 +2163,8 @@ class MessageLookup extends MessageLookupByLibrary { "usableReferralStorageInfo": MessageLookupByLibrary.simpleMessage( "O armazenamento disponível é limitado pelo seu plano atual. O excesso de armazenamento reivindicado tornará automaticamente útil quando você atualizar seu plano."), "useAsCover": MessageLookupByLibrary.simpleMessage("Usar como capa"), + "useDifferentPlayerInfo": MessageLookupByLibrary.simpleMessage( + "A ter problemas reproduzindo este vídeo? Prima aqui para tentar outro reprodutor."), "usePublicLinksForPeopleNotOnEnte": MessageLookupByLibrary.simpleMessage( "Usar links públicos para pessoas que não estão no Ente"), @@ -1759,7 +2173,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("Utilizar foto selecionada"), "usedSpace": MessageLookupByLibrary.simpleMessage("Espaço utilizado"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Falha na verificação, por favor tente novamente"), @@ -1767,7 +2181,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("ID de Verificação"), "verify": MessageLookupByLibrary.simpleMessage("Verificar"), "verifyEmail": MessageLookupByLibrary.simpleMessage("Verificar email"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Verificar"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("Verificar chave de acesso"), @@ -1779,6 +2193,8 @@ class MessageLookup extends MessageLookupByLibrary { "videoInfo": MessageLookupByLibrary.simpleMessage("Informação de Vídeo"), "videoSmallCase": MessageLookupByLibrary.simpleMessage("vídeo"), + "videoStreaming": + MessageLookupByLibrary.simpleMessage("Vídeos transmissíveis"), "videos": MessageLookupByLibrary.simpleMessage("Vídeos"), "viewActiveSessions": MessageLookupByLibrary.simpleMessage("Ver sessões ativas"), @@ -1791,27 +2207,35 @@ class MessageLookup extends MessageLookupByLibrary { "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( "Ver os ficheiros que estão a consumir a maior quantidade de armazenamento."), "viewLogs": MessageLookupByLibrary.simpleMessage("Ver logs"), + "viewPersonToUnlink": m112, "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("Ver chave de recuperação"), "viewer": MessageLookupByLibrary.simpleMessage("Visualizador"), + "viewersSuccessfullyAdded": m113, "visitWebToManage": MessageLookupByLibrary.simpleMessage( "Visite web.ente.io para gerir a sua subscrição"), "waitingForVerification": MessageLookupByLibrary.simpleMessage("Aguardando verificação..."), "waitingForWifi": MessageLookupByLibrary.simpleMessage("Aguardando Wi-Fi..."), + "warning": MessageLookupByLibrary.simpleMessage("Alerta"), "weAreOpenSource": MessageLookupByLibrary.simpleMessage("Nós somos de código aberto!"), "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "Não suportamos a edição de fotos e álbuns que ainda não possui"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Fraca"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Bem-vindo(a) de volta!"), "whatsNew": MessageLookupByLibrary.simpleMessage("O que há de novo"), + "whyAddTrustContact": MessageLookupByLibrary.simpleMessage( + "O contacto de confiança pode ajudar na recuperação dos seus dados."), + "widgets": MessageLookupByLibrary.simpleMessage("Widgets"), + "wishThemAHappyBirthday": m115, + "yearShort": MessageLookupByLibrary.simpleMessage("ano"), "yearly": MessageLookupByLibrary.simpleMessage("Anual"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Sim"), "yesCancel": MessageLookupByLibrary.simpleMessage("Sim, cancelar"), "yesConvertToViewer": MessageLookupByLibrary.simpleMessage( @@ -1826,6 +2250,7 @@ class MessageLookup extends MessageLookupByLibrary { "yesResetPerson": MessageLookupByLibrary.simpleMessage("Sim, repor pessoa"), "you": MessageLookupByLibrary.simpleMessage("Tu"), + "youAndThem": m117, "youAreOnAFamilyPlan": MessageLookupByLibrary.simpleMessage( "Você está em um plano familiar!"), "youAreOnTheLatestVersion": MessageLookupByLibrary.simpleMessage( @@ -1844,7 +2269,7 @@ class MessageLookup extends MessageLookupByLibrary { "Não podes partilhar contigo mesmo"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( "Não tem nenhum item arquivado."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("A sua conta foi eliminada"), "yourMap": MessageLookupByLibrary.simpleMessage("Seu mapa"), @@ -1865,6 +2290,9 @@ class MessageLookup extends MessageLookupByLibrary { "A sua subscrição foi actualizada com sucesso"), "yourVerificationCodeHasExpired": MessageLookupByLibrary.simpleMessage( "O seu código de verificação expirou"), + "youveNoDuplicateFilesThatCanBeCleared": + MessageLookupByLibrary.simpleMessage( + "Não tem nenhum ficheiro duplicado que possa ser eliminado"), "youveNoFilesInThisAlbumThatCanBeDeleted": MessageLookupByLibrary.simpleMessage( "Não existem ficheiros neste álbum que possam ser eliminados"), diff --git a/mobile/lib/generated/intl/messages_ro.dart b/mobile/lib/generated/intl/messages_ro.dart index 85afbe510e..52aa5e1447 100644 --- a/mobile/lib/generated/intl/messages_ro.dart +++ b/mobile/lib/generated/intl/messages_ro.dart @@ -65,177 +65,179 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'Ștergeți ${count} articol', other: 'Ștergeți ${count} de articole')}"; - static String m22(currentlyDeleting, totalCount) => + static String m23(currentlyDeleting, totalCount) => "Se șterg ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "Urmează să eliminați linkul public pentru accesarea „${albumName}”."; - static String m24(supportEmail) => + static String m25(supportEmail) => "Vă rugăm să trimiteți un e-mail la ${supportEmail} de pe adresa de e-mail înregistrată"; - static String m25(count, storageSaved) => - "Ați curățat ${Intl.plural(count, one: '${count} dublură', few: '${count} dubluri', other: '${count} de dubluri')}, economisind (${storageSaved}!)"; + static String m26(count, storageSaved) => + "Ați curățat ${Intl.plural(count, one: '${count} dublură', other: '${count} de dubluri')}, economisind (${storageSaved}!)"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} fișiere, ${formattedSize} fiecare"; - static String m28(newEmail) => "E-mail modificat în ${newEmail}"; + static String m29(newEmail) => "E-mail modificat în ${newEmail}"; - static String m30(email) => + static String m31(email) => "${email} nu are un cont Ente.\n\nTrimiteți-le o invitație pentru a distribui fotografii."; - static String m32(text) => "S-au găsit fotografii extra pentru ${text}"; - - static String m34(count, formattedNumber) => - "${Intl.plural(count, one: 'Un fișier de pe acest dispozitiv a fost deja salvat în siguranță', few: '${formattedNumber} fișiere de pe acest dispozitiv au fost deja salvate în siguranță', other: '${formattedNumber} de fișiere de pe acest dispozitiv fost deja salvate în siguranță')}"; + static String m33(text) => "S-au găsit fotografii extra pentru ${text}"; static String m35(count, formattedNumber) => - "${Intl.plural(count, one: 'Un fișier din acest album a fost deja salvat în siguranță', few: '${formattedNumber} fișiere din acest album au fost deja salvate în siguranță', other: '${formattedNumber} de fișiere din acest album au fost deja salvate în siguranță')}"; + "${Intl.plural(count, one: 'Un fișier de pe acest dispozitiv a fost deja salvat în siguranță', other: '${formattedNumber} de fișiere de pe acest dispozitiv fost deja salvate în siguranță')}"; - static String m36(storageAmountInGB) => + static String m36(count, formattedNumber) => + "${Intl.plural(count, one: 'Un fișier din acest album a fost deja salvat în siguranță', other: '${formattedNumber} de fișiere din acest album au fost deja salvate în siguranță')}"; + + static String m37(storageAmountInGB) => "${storageAmountInGB} GB de fiecare dată când cineva se înscrie pentru un plan plătit și aplică codul dvs."; - static String m37(endDate) => + static String m38(endDate) => "Perioadă de încercare valabilă până pe ${endDate}"; - static String m39(sizeInMBorGB) => "Eliberați ${sizeInMBorGB}"; + static String m40(sizeInMBorGB) => "Eliberați ${sizeInMBorGB}"; - static String m41(currentlyProcessing, totalCount) => + static String m42(currentlyProcessing, totalCount) => "Se procesează ${currentlyProcessing} / ${totalCount}"; - static String m43(count) => - "${Intl.plural(count, one: '${count} articol', few: '${count} articole', other: '${count} de articole')}"; + static String m44(count) => + "${Intl.plural(count, one: '${count} articol', other: '${count} de articole')}"; - static String m45(email) => + static String m46(email) => "${email} v-a invitat să fiți un contact de încredere"; - static String m46(expiryTime) => "Linkul va expira pe ${expiryTime}"; + static String m47(expiryTime) => "Linkul va expira pe ${expiryTime}"; - static String m51(albumName) => "S-au mutat cu succes în ${albumName}"; + static String m52(albumName) => "S-au mutat cu succes în ${albumName}"; - static String m52(personName) => "Nicio sugestie pentru ${personName}"; + static String m53(personName) => "Nicio sugestie pentru ${personName}"; - static String m53(name) => "Nu este ${name}?"; + static String m54(name) => "Nu este ${name}?"; - static String m54(familyAdminEmail) => + static String m55(familyAdminEmail) => "Vă rugăm să contactați ${familyAdminEmail} pentru a vă schimba codul."; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Complexitatea parolei: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "Vă rugăm să vorbiți cu asistența ${providerName} dacă ați fost taxat"; - static String m62(endDate) => + static String m63(endDate) => "Perioada de încercare gratuită valabilă până pe ${endDate}.\nUlterior, puteți opta pentru un plan plătit."; - static String m63(toEmail) => + static String m64(toEmail) => "Vă rugăm să ne trimiteți un e-mail la ${toEmail}"; - static String m64(toEmail) => + static String m65(toEmail) => "Vă rugăm să trimiteți jurnalele la \n${toEmail}"; - static String m66(folderName) => "Se procesează ${folderName}..."; + static String m67(folderName) => "Se procesează ${folderName}..."; - static String m67(storeName) => "Evaluați-ne pe ${storeName}"; + static String m68(storeName) => "Evaluați-ne pe ${storeName}"; - static String m69(days, email) => + static String m70(days, email) => "Puteți accesa contul după ${days} zile. O notificare va fi trimisă la ${email}."; - static String m70(email) => + static String m71(email) => "Acum puteți recupera contul ${email} setând o nouă parolă."; - static String m71(email) => "${email} încearcă să vă recupereze contul."; + static String m72(email) => "${email} încearcă să vă recupereze contul."; - static String m72(storageInGB) => + static String m73(storageInGB) => "3. Amândoi primiți ${storageInGB} GB* gratuit"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} va fi eliminat din acest album distribuit\n\nOrice fotografii adăugate de acesta vor fi, de asemenea, eliminate din album"; - static String m74(endDate) => "Abonamentul se reînnoiește pe ${endDate}"; + static String m75(endDate) => "Abonamentul se reînnoiește pe ${endDate}"; - static String m76(count) => - "${Intl.plural(count, one: '${count} rezultat găsit', few: '${count} rezultate găsite', other: '${count} de rezultate găsite')}"; + static String m77(count) => + "${Intl.plural(count, one: '${count} rezultat găsit', other: '${count} de rezultate găsite')}"; - static String m77(snapshotLength, searchLength) => + static String m78(snapshotLength, searchLength) => "Lungimea secțiunilor nu se potrivesc: ${snapshotLength} != ${searchLength}"; - static String m78(count) => "${count} selectate"; + static String m80(count) => "${count} selectate"; - static String m79(count, yourCount) => + static String m81(count, yourCount) => "${count} selectate (${yourCount} ale dvs.)"; - static String m81(verificationID) => + static String m83(verificationID) => "Acesta este ID-ul meu de verificare: ${verificationID} pentru ente.io."; - static String m82(verificationID) => + static String m84(verificationID) => "Poți confirma că acesta este ID-ul tău de verificare ente.io: ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Codul de recomandare Ente: ${referralCode}\n\nAplică-l în Setări → General → Recomandări pentru a obține ${referralStorageInGB} GB gratuit după ce te înscrii pentru un plan plătit\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Distribuiți cu anumite persoane', one: 'Distribuit cu o persoană', other: 'Distribuit cu ${numberOfPeople} de persoane')}"; - static String m85(emailIDs) => "Distribuit cu ${emailIDs}"; - - static String m86(fileType) => - "Fișierul de tip ${fileType} va fi șters din dispozitivul dvs."; - - static String m87(fileType) => - "Fișierul de tip ${fileType} este atât în Ente, cât și în dispozitivul dvs."; + static String m87(emailIDs) => "Distribuit cu ${emailIDs}"; static String m88(fileType) => + "Fișierul de tip ${fileType} va fi șters din dispozitivul dvs."; + + static String m89(fileType) => + "Fișierul de tip ${fileType} este atât în Ente, cât și în dispozitivul dvs."; + + static String m90(fileType) => "Fișierul de tip ${fileType} va fi șters din Ente."; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} din ${totalAmount} ${totalStorageUnit} utilizat"; - static String m93(id) => + static String m95(id) => "${id} este deja legat la un alt cont Ente.\nDacă doriți să folosiți ${id} cu acest cont, vă rugăm să contactați asistența noastră"; - static String m94(endDate) => "Abonamentul dvs. va fi anulat pe ${endDate}"; + static String m96(endDate) => "Abonamentul dvs. va fi anulat pe ${endDate}"; - static String m95(completed, total) => + static String m97(completed, total) => "${completed}/${total} amintiri salvate"; - static String m96(ignoreReason) => + static String m98(ignoreReason) => "Atingeți pentru a încărca, încărcarea este ignorată în prezent datorită ${ignoreReason}"; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "De asemenea, va primii ${storageAmountInGB} GB"; - static String m98(email) => "Acesta este ID-ul de verificare al ${email}"; + static String m100(email) => "Acesta este ID-ul de verificare al ${email}"; - static String m101(count) => + static String m103(count) => "${Intl.plural(count, zero: 'Curând', one: 'O zi', other: '${count} de zile')}"; - static String m104(email) => + static String m106(email) => "Ați fost învitat să fiți un contact de moștenire de către ${email}."; - static String m105(galleryType) => + static String m107(galleryType) => "Tipul de galerie ${galleryType} nu este acceptat pentru redenumire"; - static String m106(ignoreReason) => + static String m108(ignoreReason) => "Încărcare ignorată din motivul ${ignoreReason}"; - static String m107(count) => "Se salvează ${count} amintiri..."; + static String m109(count) => "Se salvează ${count} amintiri..."; - static String m108(endDate) => "Valabil până pe ${endDate}"; + static String m110(endDate) => "Valabil până pe ${endDate}"; - static String m109(email) => "Verificare ${email}"; + static String m111(email) => "Verificare ${email}"; - static String m112(email) => "Am trimis un e-mail la ${email}"; + static String m114(email) => "Am trimis un e-mail la ${email}"; - static String m113(count) => - "${Intl.plural(count, one: 'acum ${count} an', few: 'acum ${count} ani', other: 'acum ${count} de ani')}"; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; - static String m115(storageSaved) => "Ați eliberat cu succes ${storageSaved}!"; + static String m116(count) => + "${Intl.plural(count, one: 'acum ${count} an', other: 'acum ${count} de ani')}"; + + static String m118(storageSaved) => "Ați eliberat cu succes ${storageSaved}!"; final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { @@ -528,8 +530,6 @@ class MessageLookup extends MessageLookupByLibrary { "click": MessageLookupByLibrary.simpleMessage("• Apăsați"), "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage( "• Apăsați pe meniul suplimentar"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "close": MessageLookupByLibrary.simpleMessage("Închidere"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage( "Grupare după timpul capturării"), @@ -675,7 +675,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ștergeți locația"), "deletePhotos": MessageLookupByLibrary.simpleMessage("Ștergeți fotografiile"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Lipsește o funcție cheie de care am nevoie"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -716,7 +716,7 @@ class MessageLookup extends MessageLookupByLibrary { "Observatorii pot să facă capturi de ecran sau să salveze o copie a fotografiilor dvs. folosind instrumente externe"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Rețineți"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Dezactivați al doilea factor"), "disablingTwofactorAuthentication": @@ -757,9 +757,9 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("Descărcarea nu a reușit"), "downloading": MessageLookupByLibrary.simpleMessage("Se descarcă..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("Editare"), "editLocation": MessageLookupByLibrary.simpleMessage("Editare locaţie"), "editLocationTagTitle": @@ -773,8 +773,8 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("E-mail"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage("E-mail deja înregistrat."), - "emailChangedTo": m28, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage( "E-mailul nu este înregistrat."), "emailVerificationToggle": MessageLookupByLibrary.simpleMessage( @@ -861,7 +861,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Export de date"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage("S-au găsit fotografii extra"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage( "Fața nu este încă grupată, vă rugăm să reveniți mai târziu"), "faceRecognition": @@ -912,8 +912,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Tipuri de fișiere"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage( "Tipuri de fișiere și denumiri"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("Fișiere șterse"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage("Fișiere salvate în galerie"), @@ -928,13 +928,13 @@ class MessageLookup extends MessageLookupByLibrary { "foundFaces": MessageLookupByLibrary.simpleMessage("S-au găsit fețe"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("Spațiu gratuit revendicat"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("Spațiu gratuit utilizabil"), "freeTrial": MessageLookupByLibrary.simpleMessage( "Perioadă de încercare gratuită"), - "freeTrialValidTill": m37, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage( "Eliberați spațiu pe dispozitiv"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( @@ -946,7 +946,7 @@ class MessageLookup extends MessageLookupByLibrary { "general": MessageLookupByLibrary.simpleMessage("General"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Se generează cheile de criptare..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("Mergeți la setări"), "googlePlayId": MessageLookupByLibrary.simpleMessage("ID Google Play"), @@ -1030,7 +1030,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Se pare că ceva nu a mers bine. Vă rugăm să încercați din nou după ceva timp. Dacă eroarea persistă, vă rugăm să contactați echipa noastră de asistență."), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Articolele afișează numărul de zile rămase până la ștergerea definitivă"), @@ -1062,7 +1062,7 @@ class MessageLookup extends MessageLookupByLibrary { "legacy": MessageLookupByLibrary.simpleMessage("Moștenire"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("Conturi de moștenire"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage( "Moștenirea permite contactelor de încredere să vă acceseze contul în absența dvs."), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( @@ -1075,7 +1075,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Limită de dispozitive"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Activat"), "linkExpired": MessageLookupByLibrary.simpleMessage("Expirat"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Expirarea linkului"), "linkHasExpired": @@ -1140,8 +1140,6 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Apăsați lung pe un articol pentru a-l vizualiza pe tot ecranul"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "loopVideoOff": MessageLookupByLibrary.simpleMessage("Repetare video dezactivată"), "loopVideoOn": @@ -1205,7 +1203,7 @@ class MessageLookup extends MessageLookupByLibrary { "moveToAlbum": MessageLookupByLibrary.simpleMessage("Mutare în album"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Mutați în albumul ascuns"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("S-a mutat în coșul de gunoi"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1221,7 +1219,6 @@ class MessageLookup extends MessageLookupByLibrary { "newAlbum": MessageLookupByLibrary.simpleMessage("Album nou"), "newLocation": MessageLookupByLibrary.simpleMessage("Locație nouă"), "newPerson": MessageLookupByLibrary.simpleMessage("Persoană nouă"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "newToEnte": MessageLookupByLibrary.simpleMessage("Nou la Ente"), "newest": MessageLookupByLibrary.simpleMessage("Cele mai noi"), "next": MessageLookupByLibrary.simpleMessage("Înainte"), @@ -1258,10 +1255,10 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Niciun rezultat"), "noResultsFound": MessageLookupByLibrary.simpleMessage("Nu s-au găsit rezultate"), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage( "Nu s-a găsit nicio blocare de sistem"), - "notPersonLabel": m53, + "notPersonLabel": m54, "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( "Nimic distribuit cu dvs. încă"), "nothingToSeeHere": @@ -1271,10 +1268,7 @@ class MessageLookup extends MessageLookupByLibrary { "onDevice": MessageLookupByLibrary.simpleMessage("Pe dispozitiv"), "onEnte": MessageLookupByLibrary.simpleMessage( "Pe ente"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("Numai el/ea"), "oops": MessageLookupByLibrary.simpleMessage("Ups"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( @@ -1313,7 +1307,7 @@ class MessageLookup extends MessageLookupByLibrary { "Parola a fost schimbată cu succes"), "passwordLock": MessageLookupByLibrary.simpleMessage("Blocare cu parolă"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "Puterea parolei este calculată luând în considerare lungimea parolei, caracterele utilizate și dacă parola apare sau nu în top 10.000 cele mai utilizate parole"), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -1324,7 +1318,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Plata nu a reușit"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Din păcate, plata dvs. nu a reușit. Vă rugăm să contactați asistență și vom fi bucuroși să vă ajutăm!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("Elemente în așteptare"), "pendingSync": @@ -1353,7 +1347,7 @@ class MessageLookup extends MessageLookupByLibrary { "pinAlbum": MessageLookupByLibrary.simpleMessage("Fixați albumul"), "pinLock": MessageLookupByLibrary.simpleMessage("Blocare PIN"), "playOnTv": MessageLookupByLibrary.simpleMessage("Redare album pe TV"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("Abonament PlayStore"), "pleaseCheckYourInternetConnectionAndTryAgain": @@ -1365,14 +1359,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Vă rugăm să contactați asistența dacă problema persistă"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage( "Vă rugăm să acordați permisiuni"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage( "Vă rugăm, autentificați-vă din nou"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Vă rugăm să selectați linkurile rapide de eliminat"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Vă rugăm să încercați din nou"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1402,7 +1396,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Distribuire privată"), "proceed": MessageLookupByLibrary.simpleMessage("Continuați"), "processed": MessageLookupByLibrary.simpleMessage("Procesate"), - "processingImport": m66, + "processingImport": m67, "publicLinkCreated": MessageLookupByLibrary.simpleMessage("Link public creat"), "publicLinkEnabled": @@ -1414,7 +1408,7 @@ class MessageLookup extends MessageLookupByLibrary { "rateTheApp": MessageLookupByLibrary.simpleMessage("Evaluați aplicația"), "rateUs": MessageLookupByLibrary.simpleMessage("Evaluați-ne"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "recover": MessageLookupByLibrary.simpleMessage("Recuperare"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Recuperare cont"), @@ -1423,7 +1417,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Recuperare cont"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage("Recuperare inițiată"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("Cheie de recuperare"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( @@ -1438,12 +1432,12 @@ class MessageLookup extends MessageLookupByLibrary { "Cheie de recuperare verificată"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "Cheia dvs. de recuperare este singura modalitate de a vă recupera fotografiile dacă uitați parola. Puteți găsi cheia dvs. de recuperare în Setări > Cont.\n\nVă rugăm să introduceți aici cheia de recuperare pentru a verifica dacă ați salvat-o corect."), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage("Recuperare reușită!"), "recoveryWarning": MessageLookupByLibrary.simpleMessage( "Un contact de încredere încearcă să vă acceseze contul"), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "Dispozitivul actual nu este suficient de puternic pentru a vă verifica parola, dar o putem regenera într-un mod care să funcționeze cu toate dispozitivele.\n\nVă rugăm să vă conectați utilizând cheia de recuperare și să vă regenerați parola (dacă doriți, o puteți utiliza din nou pe aceeași)."), "recreatePasswordTitle": @@ -1459,7 +1453,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Dați acest cod prietenilor"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Aceștia se înscriu la un plan cu plată"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("Recomandări"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Recomandările sunt momentan întrerupte"), @@ -1491,7 +1485,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Eliminați linkul"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Eliminați participantul"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage( "Eliminați eticheta persoanei"), "removePublicLink": @@ -1512,7 +1506,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Redenumiți fișierul"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Reînnoire abonament"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Raportați o eroare"), "reportBug": MessageLookupByLibrary.simpleMessage("Raportare eroare"), @@ -1593,8 +1587,8 @@ class MessageLookup extends MessageLookupByLibrary { "Invitați persoane și veți vedea aici toate fotografiile distribuite de acestea"), "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage( "Persoanele vor fi afișate aici odată ce procesarea și sincronizarea este completă"), - "searchResultCount": m76, - "searchSectionsLengthMismatch": m77, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("Securitate"), "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage( "Vedeți linkurile albumelor publice în aplicație"), @@ -1629,8 +1623,8 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage( "Articolele selectate vor fi șterse din toate albumele și mutate în coșul de gunoi."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, "send": MessageLookupByLibrary.simpleMessage("Trimitere"), "sendEmail": MessageLookupByLibrary.simpleMessage("Trimiteți e-mail"), "sendInvite": @@ -1663,16 +1657,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Distribuiți un album acum"), "shareLink": MessageLookupByLibrary.simpleMessage("Distribuiți linkul"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Distribuiți numai cu persoanele pe care le doriți"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Descarcă Ente pentru a putea distribui cu ușurință fotografii și videoclipuri în calitate originală\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Distribuiți cu utilizatori din afara Ente"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage("Distribuiți primul album"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1685,7 +1679,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Fotografii partajate noi"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "Primiți notificări atunci când cineva adaugă o fotografie la un album distribuit din care faceți parte"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Distribuit mie"), "sharedWithYou": MessageLookupByLibrary.simpleMessage("Distribuite cu dvs."), @@ -1701,11 +1695,11 @@ class MessageLookup extends MessageLookupByLibrary { "Deconectați alte dispozitive"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Sunt de acord cu termenii de prestare ai serviciului și politica de confidențialitate"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "Acesta va fi șters din toate albumele."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("Omiteți"), "social": MessageLookupByLibrary.simpleMessage("Rețele socializare"), "someItemsAreInBothEnteAndYourDevice": @@ -1734,8 +1728,6 @@ class MessageLookup extends MessageLookupByLibrary { "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "Ne pare rău, nu am putut genera chei securizate pe acest dispozitiv.\n\nvă rugăm să vă înregistrați de pe un alt dispozitiv."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "sort": MessageLookupByLibrary.simpleMessage("Sortare"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Sortare după"), "sortNewestFirst": @@ -1755,13 +1747,13 @@ class MessageLookup extends MessageLookupByLibrary { "storage": MessageLookupByLibrary.simpleMessage("Spațiu"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Familie"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Dvs."), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage("Limita de spațiu depășită"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "strongStrength": MessageLookupByLibrary.simpleMessage("Puternică"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("Abonare"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "Aveți nevoie de un abonament plătit activ pentru a activa distribuirea."), @@ -1778,7 +1770,7 @@ class MessageLookup extends MessageLookupByLibrary { "suggestFeatures": MessageLookupByLibrary.simpleMessage("Sugerați funcționalități"), "support": MessageLookupByLibrary.simpleMessage("Asistență"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("Sincronizare oprită"), "syncing": MessageLookupByLibrary.simpleMessage("Sincronizare..."), @@ -1791,7 +1783,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Atingeți pentru a debloca"), "tapToUpload": MessageLookupByLibrary.simpleMessage("Atingeți pentru a încărca"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Se pare că ceva nu a mers bine. Vă rugăm să încercați din nou după ceva timp. Dacă eroarea persistă, vă rugăm să contactați echipa noastră de asistență."), "terminate": MessageLookupByLibrary.simpleMessage("Terminare"), @@ -1814,7 +1806,7 @@ class MessageLookup extends MessageLookupByLibrary { "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage( "Aceste articole vor fi șterse din dispozitivul dvs."), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage( "Acestea vor fi șterse din toate albumele."), "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( @@ -1830,7 +1822,7 @@ class MessageLookup extends MessageLookupByLibrary { "Această adresă de e-mail este deja folosită"), "thisImageHasNoExifData": MessageLookupByLibrary.simpleMessage( "Această imagine nu are date exif"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( "Acesta este ID-ul dvs. de verificare"), "thisWillLogYouOutOfTheFollowingDevice": @@ -1855,11 +1847,11 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("total"), "totalSize": MessageLookupByLibrary.simpleMessage("Dimensiune totală"), "trash": MessageLookupByLibrary.simpleMessage("Coș de gunoi"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("Decupare"), "trustedContacts": MessageLookupByLibrary.simpleMessage("Contacte de încredere"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("Încercați din nou"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "Activați copia de rezervă pentru a încărca automat fișierele adăugate la acest dosar de pe dispozitiv în Ente."), @@ -1878,7 +1870,7 @@ class MessageLookup extends MessageLookupByLibrary { "Autentificarea cu doi factori a fost resetată cu succes"), "twofactorSetup": MessageLookupByLibrary.simpleMessage("Configurare doi factori"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("Dezarhivare"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("Dezarhivare album"), @@ -1904,10 +1896,10 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage( "Se actualizează selecția dosarelor..."), "upgrade": MessageLookupByLibrary.simpleMessage("Îmbunătățire"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Se încarcă fișiere în album..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage("Se salvează o amintire..."), "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( @@ -1925,7 +1917,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage( "Folosiți fotografia selectată"), "usedSpace": MessageLookupByLibrary.simpleMessage("Spațiu utilizat"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Verificare eșuată, încercați din nou"), @@ -1934,7 +1926,7 @@ class MessageLookup extends MessageLookupByLibrary { "verify": MessageLookupByLibrary.simpleMessage("Verificare"), "verifyEmail": MessageLookupByLibrary.simpleMessage("Verificare e-mail"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Verificare"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("Verificați cheia de acces"), @@ -1972,16 +1964,17 @@ class MessageLookup extends MessageLookupByLibrary { "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "Nu se acceptă editarea fotografiilor sau albumelor pe care nu le dețineți încă"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Slabă"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Bine ați revenit!"), "whatsNew": MessageLookupByLibrary.simpleMessage("Noutăți"), "whyAddTrustContact": MessageLookupByLibrary.simpleMessage( "Contactul de încredere vă poate ajuta la recuperarea datelor."), + "wishThemAHappyBirthday": m115, "yearShort": MessageLookupByLibrary.simpleMessage("an"), "yearly": MessageLookupByLibrary.simpleMessage("Anual"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Da"), "yesCancel": MessageLookupByLibrary.simpleMessage("Da, anulează"), "yesConvertToViewer": @@ -2013,7 +2006,7 @@ class MessageLookup extends MessageLookupByLibrary { "Nu poți distribui cu tine însuți"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage("Nu aveți articole arhivate."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("Contul dvs. a fost șters"), "yourMap": MessageLookupByLibrary.simpleMessage("Harta dvs."), diff --git a/mobile/lib/generated/intl/messages_ru.dart b/mobile/lib/generated/intl/messages_ru.dart index 22e07baaf7..1dcfc39b5f 100644 --- a/mobile/lib/generated/intl/messages_ru.dart +++ b/mobile/lib/generated/intl/messages_ru.dart @@ -83,238 +83,240 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'Удалить ${count} элемент', other: 'Удалить ${count} элементов')}"; - static String m22(currentlyDeleting, totalCount) => + static String m23(currentlyDeleting, totalCount) => "Удаление ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "Это удалит публичную ссылку для доступа к \"${albumName}\"."; - static String m24(supportEmail) => + static String m25(supportEmail) => "Пожалуйста, отправьте письмо на ${supportEmail} с вашего зарегистрированного адреса электронной почты"; - static String m25(count, storageSaved) => + static String m26(count, storageSaved) => "Вы удалили ${Intl.plural(count, one: '${count} дубликат', other: '${count} дубликатов')}, освободив (${storageSaved}!)"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} файлов, по ${formattedSize} каждый"; - static String m28(newEmail) => "Электронная почта изменена на ${newEmail}"; + static String m29(newEmail) => "Электронная почта изменена на ${newEmail}"; - static String m29(email) => "${email} не имеет аккаунта Ente."; + static String m30(email) => "${email} не имеет аккаунта Ente."; - static String m30(email) => + static String m31(email) => "У ${email} нет аккаунта Ente.\n\nОтправьте ему приглашение для обмена фото."; - static String m31(name) => "Обнимая ${name}"; + static String m32(name) => "Обнимая ${name}"; - static String m32(text) => "Дополнительные фото найдены для ${text}"; + static String m33(text) => "Дополнительные фото найдены для ${text}"; - static String m33(name) => "Пир с ${name}"; - - static String m34(count, formattedNumber) => - "${Intl.plural(count, one: '${formattedNumber} файл на этом устройстве был успешно сохранён', other: '${formattedNumber} файлов на этом устройстве были успешно сохранены')}"; + static String m34(name) => "Пир с ${name}"; static String m35(count, formattedNumber) => + "${Intl.plural(count, one: '${formattedNumber} файл на этом устройстве был успешно сохранён', other: '${formattedNumber} файлов на этом устройстве были успешно сохранены')}"; + + static String m36(count, formattedNumber) => "${Intl.plural(count, one: '${formattedNumber} файл в этом альбоме был успешно сохранён', other: '${formattedNumber} файлов в этом альбоме были успешно сохранены')}"; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "${storageAmountInGB} ГБ каждый раз, когда кто-то подписывается на платный тариф и применяет ваш код"; - static String m37(endDate) => + static String m38(endDate) => "Бесплатный пробный период действителен до ${endDate}"; - static String m38(count) => + static String m39(count) => "Вы всё ещё сможете получить доступ к ${Intl.plural(count, one: 'нему', other: 'ним')} в Ente, пока у вас активна подписка"; - static String m39(sizeInMBorGB) => "Освободить ${sizeInMBorGB}"; + static String m40(sizeInMBorGB) => "Освободить ${sizeInMBorGB}"; - static String m40(count, formattedSize) => + static String m41(count, formattedSize) => "${Intl.plural(count, one: 'Его можно удалить с устройства, чтобы освободить ${formattedSize}', other: 'Их можно удалить с устройства, чтобы освободить ${formattedSize}')}"; - static String m41(currentlyProcessing, totalCount) => + static String m42(currentlyProcessing, totalCount) => "Обработка ${currentlyProcessing} / ${totalCount}"; - static String m42(name) => "Поход с ${name}"; + static String m43(name) => "Поход с ${name}"; - static String m43(count) => + static String m44(count) => "${Intl.plural(count, one: '${count} элемент', other: '${count} элементов')}"; - static String m44(name) => "В последний раз с ${name}"; + static String m45(name) => "В последний раз с ${name}"; - static String m45(email) => + static String m46(email) => "${email} пригласил вас стать доверенным контактом"; - static String m46(expiryTime) => "Ссылка истечёт ${expiryTime}"; + static String m47(expiryTime) => "Ссылка истечёт ${expiryTime}"; - static String m47(email) => "Связать человека с ${email}"; + static String m48(email) => "Связать человека с ${email}"; - static String m48(personName, email) => "Это свяжет ${personName} с ${email}"; + static String m49(personName, email) => "Это свяжет ${personName} с ${email}"; - static String m49(count, formattedCount) => + static String m50(count, formattedCount) => "${Intl.plural(count, zero: 'нет воспоминаний', one: '${formattedCount} воспоминание', other: '${formattedCount} воспоминаний')}"; - static String m50(count) => + static String m51(count) => "${Intl.plural(count, one: 'Переместить элемент', other: 'Переместить элементы')}"; - static String m51(albumName) => "Успешно перемещено в ${albumName}"; + static String m52(albumName) => "Успешно перемещено в ${albumName}"; - static String m52(personName) => "Нет предложений для ${personName}"; + static String m53(personName) => "Нет предложений для ${personName}"; - static String m53(name) => "Не ${name}?"; + static String m54(name) => "Не ${name}?"; - static String m54(familyAdminEmail) => + static String m55(familyAdminEmail) => "Пожалуйста, свяжитесь с ${familyAdminEmail} для изменения кода."; - static String m55(name) => "Вечеринка с ${name}"; + static String m56(name) => "Вечеринка с ${name}"; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Надёжность пароля: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "Пожалуйста, обратитесь в поддержку ${providerName}, если с вас сняли деньги"; - static String m58(name, age) => "${name} исполнилось ${age}!"; + static String m59(name, age) => "${name} исполнилось ${age}!"; - static String m59(name, age) => "${name} скоро исполнится ${age}"; - - static String m60(count) => - "${Intl.plural(count, zero: 'Нет фото', one: '1 фото', other: '${count} фото')}"; + static String m60(name, age) => "${name} скоро исполнится ${age}"; static String m61(count) => + "${Intl.plural(count, zero: 'Нет фото', one: '1 фото', other: '${count} фото')}"; + + static String m62(count) => "${Intl.plural(count, zero: '0 фотографий', one: '1 фотография', other: '${count} фотографий')}"; - static String m62(endDate) => + static String m63(endDate) => "Бесплатный пробный период действителен до ${endDate}.\nПосле этого вы можете выбрать платный тариф."; - static String m63(toEmail) => "Пожалуйста, напишите нам на ${toEmail}"; + static String m64(toEmail) => "Пожалуйста, напишите нам на ${toEmail}"; - static String m64(toEmail) => "Пожалуйста, отправьте логи на \n${toEmail}"; + static String m65(toEmail) => "Пожалуйста, отправьте логи на \n${toEmail}"; - static String m65(name) => "Позируя с ${name}"; + static String m66(name) => "Позируя с ${name}"; - static String m66(folderName) => "Обработка ${folderName}..."; + static String m67(folderName) => "Обработка ${folderName}..."; - static String m67(storeName) => "Оцените нас в ${storeName}"; + static String m68(storeName) => "Оцените нас в ${storeName}"; - static String m68(name) => "Вы переназначены на ${name}"; + static String m69(name) => "Вы переназначены на ${name}"; - static String m69(days, email) => + static String m70(days, email) => "Вы сможете получить доступ к аккаунту через ${days} дней. Уведомление будет отправлено на ${email}."; - static String m70(email) => + static String m71(email) => "Теперь вы можете восстановить аккаунт ${email}, установив новый пароль."; - static String m71(email) => "${email} пытается восстановить ваш аккаунт."; + static String m72(email) => "${email} пытается восстановить ваш аккаунт."; - static String m72(storageInGB) => + static String m73(storageInGB) => "3. Вы оба получаете ${storageInGB} ГБ* бесплатно"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} будет удалён из этого общего альбома\n\nВсе фото, добавленные этим пользователем, также будут удалены из альбома"; - static String m74(endDate) => "Подписка будет продлена ${endDate}"; + static String m75(endDate) => "Подписка будет продлена ${endDate}"; - static String m75(name) => "Путешествие с ${name}"; + static String m76(name) => "Путешествие с ${name}"; - static String m76(count) => + static String m77(count) => "${Intl.plural(count, one: '${count} результат найден', other: '${count} результатов найдено')}"; - static String m77(snapshotLength, searchLength) => + static String m78(snapshotLength, searchLength) => "Несоответствие длины разделов: ${snapshotLength} != ${searchLength}"; - static String m78(count) => "${count} выбрано"; + static String m80(count) => "${count} выбрано"; - static String m79(count, yourCount) => + static String m81(count, yourCount) => "${count} выбрано (${yourCount} ваших)"; - static String m80(name) => "Селфи с ${name}"; + static String m82(name) => "Селфи с ${name}"; - static String m81(verificationID) => + static String m83(verificationID) => "Вот мой идентификатор подтверждения: ${verificationID} для ente.io."; - static String m82(verificationID) => + static String m84(verificationID) => "Привет, можешь подтвердить, что это твой идентификатор подтверждения ente.io: ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Реферальный код Ente: ${referralCode} \n\nПримените его в разделе «Настройки» → «Общие» → «Рефералы», чтобы получить ${referralStorageInGB} ГБ бесплатно после подписки на платный тариф\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Поделиться с конкретными людьми', one: 'Доступно 1 человеку', other: 'Доступно ${numberOfPeople} людям')}"; - static String m85(emailIDs) => "Доступен для ${emailIDs}"; + static String m87(emailIDs) => "Доступен для ${emailIDs}"; - static String m86(fileType) => + static String m88(fileType) => "Это ${fileType} будет удалено с вашего устройства."; - static String m87(fileType) => + static String m89(fileType) => "Это ${fileType} есть и в Ente, и на вашем устройстве."; - static String m88(fileType) => "Это ${fileType} будет удалено из Ente."; + static String m90(fileType) => "Это ${fileType} будет удалено из Ente."; - static String m89(name) => "Спорт с ${name}"; + static String m91(name) => "Спорт с ${name}"; - static String m90(name) => "В центре внимания ${name}"; + static String m92(name) => "В центре внимания ${name}"; - static String m91(storageAmountInGB) => "${storageAmountInGB} ГБ"; + static String m93(storageAmountInGB) => "${storageAmountInGB} ГБ"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "Использовано ${usedAmount} ${usedStorageUnit} из ${totalAmount} ${totalStorageUnit}"; - static String m93(id) => + static String m95(id) => "Ваш ${id} уже связан с другим аккаунтом Ente.\nЕсли вы хотите использовать ${id} с этим аккаунтом, пожалуйста, свяжитесь с нашей службой поддержки"; - static String m94(endDate) => "Ваша подписка будет отменена ${endDate}"; + static String m96(endDate) => "Ваша подписка будет отменена ${endDate}"; - static String m95(completed, total) => + static String m97(completed, total) => "${completed}/${total} воспоминаний сохранено"; - static String m96(ignoreReason) => + static String m98(ignoreReason) => "Нажмите для загрузки. Загрузка игнорируется из-за ${ignoreReason}"; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "Они тоже получат ${storageAmountInGB} ГБ"; - static String m98(email) => "Это идентификатор подтверждения ${email}"; - - static String m99(count) => - "${Intl.plural(count, one: 'Эта неделя, ${count} год назад', other: 'Эта неделя, ${count} лет назад')}"; - - static String m100(dateFormat) => "${dateFormat} сквозь годы"; + static String m100(email) => "Это идентификатор подтверждения ${email}"; static String m101(count) => + "${Intl.plural(count, one: 'Эта неделя, ${count} год назад', other: 'Эта неделя, ${count} лет назад')}"; + + static String m102(dateFormat) => "${dateFormat} сквозь годы"; + + static String m103(count) => "${Intl.plural(count, zero: 'Скоро', one: '1 день', other: '${count} дней')}"; - static String m102(year) => "Поездка в ${year}"; + static String m104(year) => "Поездка в ${year}"; - static String m103(location) => "Поездка в ${location}"; + static String m105(location) => "Поездка в ${location}"; - static String m104(email) => + static String m106(email) => "Вы приглашены стать доверенным контактом ${email}."; - static String m105(galleryType) => + static String m107(galleryType) => "Тип галереи ${galleryType} не поддерживает переименование"; - static String m106(ignoreReason) => + static String m108(ignoreReason) => "Загрузка игнорируется из-за ${ignoreReason}"; - static String m107(count) => "Сохранение ${count} воспоминаний..."; + static String m109(count) => "Сохранение ${count} воспоминаний..."; - static String m108(endDate) => "Действительно до ${endDate}"; + static String m110(endDate) => "Действительно до ${endDate}"; - static String m109(email) => "Подтвердить ${email}"; - - static String m111(count) => - "${Intl.plural(count, zero: 'Добавлено 0 зрителей', one: 'Добавлен 1 зритель', other: 'Добавлено ${count} зрителей')}"; - - static String m112(email) => "Мы отправили письмо на ${email}"; + static String m111(email) => "Подтвердить ${email}"; static String m113(count) => - "${Intl.plural(count, one: '${count} год назад', few: '${count} года назад', other: '${count} лет назад')}"; + "${Intl.plural(count, zero: 'Добавлено 0 зрителей', one: 'Добавлен 1 зритель', other: 'Добавлено ${count} зрителей')}"; - static String m114(name) => "Вы и ${name}"; + static String m114(email) => "Мы отправили письмо на ${email}"; - static String m115(storageSaved) => "Вы успешно освободили ${storageSaved}!"; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + + static String m116(count) => + "${Intl.plural(count, one: '${count} год назад', other: '${count} лет назад')}"; + + static String m117(name) => "Вы и ${name}"; + + static String m118(storageSaved) => "Вы успешно освободили ${storageSaved}!"; final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { @@ -543,6 +545,29 @@ class MessageLookup extends MessageLookupByLibrary { "blackFridaySale": MessageLookupByLibrary.simpleMessage( "Распродажа в \"Черную пятницу\""), "blog": MessageLookupByLibrary.simpleMessage("Блог"), + "cLDesc1": MessageLookupByLibrary.simpleMessage( + "Вслед за бета-версией потокового видео и работой над возобновляемыми загрузками и скачиваниями, мы увеличили лимит загрузки файлов до 10ГБ. Это теперь доступно как в настольных, так и в мобильных приложениях."), + "cLDesc2": MessageLookupByLibrary.simpleMessage( + "Фоновые загрузки теперь также поддерживаются на iOS, в дополнение к устройствам Android. Больше не нужно открывать приложение для резервного копирования ваших последних фото и видео."), + "cLDesc3": MessageLookupByLibrary.simpleMessage( + "Мы внесли значительные улучшения в наш опыт воспоминаний, включая автовоспроизведение, пролистывание к следующему воспоминанию и многое другое."), + "cLDesc4": MessageLookupByLibrary.simpleMessage( + "Наряду с множеством внутренних улучшений, теперь гораздо проще увидеть все обнаруженные лица, предоставить обратную связь о похожих лицах и добавить/удалить лица с одной фотографии."), + "cLDesc5": MessageLookupByLibrary.simpleMessage( + "Теперь вы будете получать опциональные уведомления обо всех днях рождения, которые вы сохранили в Ente, вместе с коллекцией их лучших фотографий."), + "cLDesc6": MessageLookupByLibrary.simpleMessage( + "Больше не нужно ждать завершения загрузок/скачиваний перед закрытием приложения. Все загрузки и скачивания теперь могут быть приостановлены на полпути и возобновлены с того места, где вы остановились."), + "cLTitle1": MessageLookupByLibrary.simpleMessage( + "Загрузка больших видеофайлов"), + "cLTitle2": MessageLookupByLibrary.simpleMessage("Фоновая загрузка"), + "cLTitle3": MessageLookupByLibrary.simpleMessage( + "Автовоспроизведение воспоминаний"), + "cLTitle4": MessageLookupByLibrary.simpleMessage( + "Улучшенное распознавание лиц"), + "cLTitle5": + MessageLookupByLibrary.simpleMessage("Уведомления о днях рождения"), + "cLTitle6": MessageLookupByLibrary.simpleMessage( + "Возобновляемые загрузки и скачивания"), "cachedData": MessageLookupByLibrary.simpleMessage("Кэшированные данные"), "calculating": MessageLookupByLibrary.simpleMessage("Подсчёт..."), @@ -615,8 +640,6 @@ class MessageLookup extends MessageLookupByLibrary { "click": MessageLookupByLibrary.simpleMessage("• Нажмите"), "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage( "• Нажмите на меню дополнительных действий"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "close": MessageLookupByLibrary.simpleMessage("Закрыть"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage( "Группировать по времени съёмки"), @@ -764,7 +787,7 @@ class MessageLookup extends MessageLookupByLibrary { "deleteLocation": MessageLookupByLibrary.simpleMessage("Удалить местоположение"), "deletePhotos": MessageLookupByLibrary.simpleMessage("Удалить фото"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Отсутствует необходимая функция"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -804,7 +827,7 @@ class MessageLookup extends MessageLookupByLibrary { "Зрители всё ещё могут делать скриншоты или сохранять копии ваших фото с помощью внешних инструментов"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Обратите внимание"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Отключить двухфакторную аутентификацию"), "disablingTwofactorAuthentication": @@ -846,9 +869,9 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("Скачивание не удалось"), "downloading": MessageLookupByLibrary.simpleMessage("Скачивание..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("Редактировать"), "editLocation": MessageLookupByLibrary.simpleMessage("Изменить местоположение"), @@ -866,16 +889,16 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("Электронная почта"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage( "Электронная почта уже зарегистрирована."), - "emailChangedTo": m28, - "emailDoesNotHaveEnteAccount": m29, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailDoesNotHaveEnteAccount": m30, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage( "Электронная почта не зарегистрирована."), "emailVerificationToggle": MessageLookupByLibrary.simpleMessage( "Подтверждение входа по почте"), "emailYourLogs": MessageLookupByLibrary.simpleMessage( "Отправить логи по электронной почте"), - "embracingThem": m31, + "embracingThem": m32, "emergencyContacts": MessageLookupByLibrary.simpleMessage("Экстренные контакты"), "empty": MessageLookupByLibrary.simpleMessage("Очистить"), @@ -953,7 +976,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Экспортировать ваши данные"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage("Найдены дополнительные фото"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage( "Лицо ещё не кластеризовано. Пожалуйста, попробуйте позже"), "faceRecognition": @@ -991,7 +1014,7 @@ class MessageLookup extends MessageLookupByLibrary { "faqs": MessageLookupByLibrary.simpleMessage("Часто задаваемые вопросы"), "favorite": MessageLookupByLibrary.simpleMessage("В избранное"), - "feastingWithThem": m33, + "feastingWithThem": m34, "feedback": MessageLookupByLibrary.simpleMessage("Обратная связь"), "file": MessageLookupByLibrary.simpleMessage("Файл"), "fileFailedToSaveToGallery": MessageLookupByLibrary.simpleMessage( @@ -1005,8 +1028,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Типы файлов"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Типы и названия файлов"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("Файлы удалены"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage("Файлы сохранены в галерею"), @@ -1022,27 +1045,27 @@ class MessageLookup extends MessageLookupByLibrary { "foundFaces": MessageLookupByLibrary.simpleMessage("Найденные лица"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage( "Полученное бесплатное хранилище"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage( "Доступное бесплатное хранилище"), "freeTrial": MessageLookupByLibrary.simpleMessage("Бесплатный пробный период"), - "freeTrialValidTill": m37, - "freeUpAccessPostDelete": m38, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAccessPostDelete": m39, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage( "Освободить место на устройстве"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Освободите место на устройстве, удалив файлы, которые уже сохранены в резервной копии."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Освободить место"), - "freeUpSpaceSaving": m40, + "freeUpSpaceSaving": m41, "gallery": MessageLookupByLibrary.simpleMessage("Галерея"), "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "В галерее отображается до 1000 воспоминаний"), "general": MessageLookupByLibrary.simpleMessage("Общие"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Генерация ключей шифрования..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("Перейти в настройки"), "googlePlayId": @@ -1073,7 +1096,7 @@ class MessageLookup extends MessageLookupByLibrary { "hideSharedItemsFromHomeGallery": MessageLookupByLibrary.simpleMessage( "Скрыть общие элементы из основной галереи"), "hiding": MessageLookupByLibrary.simpleMessage("Скрытие..."), - "hikingWithThem": m42, + "hikingWithThem": m43, "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("Размещено на OSM France"), "howItWorks": MessageLookupByLibrary.simpleMessage("Как это работает"), @@ -1131,7 +1154,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Похоже, что-то пошло не так. Пожалуйста, повторите попытку через некоторое время. Если ошибка сохраняется, обратитесь в нашу службу поддержки."), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "На элементах отображается количество дней, оставшихся до их безвозвратного удаления"), @@ -1153,7 +1176,7 @@ class MessageLookup extends MessageLookupByLibrary { "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( "Пожалуйста, помогите нам с этой информацией"), "language": MessageLookupByLibrary.simpleMessage("Язык"), - "lastTimeWithThem": m44, + "lastTimeWithThem": m45, "lastUpdated": MessageLookupByLibrary.simpleMessage("Последнее обновление"), "lastYearsTrip": @@ -1167,7 +1190,7 @@ class MessageLookup extends MessageLookupByLibrary { "legacy": MessageLookupByLibrary.simpleMessage("Наследие"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("Наследуемые аккаунты"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage( "Наследие позволяет доверенным контактам получить доступ к вашему аккаунту в ваше отсутствие."), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( @@ -1185,7 +1208,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("чтобы быстрее делиться"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Включена"), "linkExpired": MessageLookupByLibrary.simpleMessage("Истекла"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Срок действия ссылки"), "linkHasExpired": @@ -1194,8 +1217,8 @@ class MessageLookup extends MessageLookupByLibrary { "linkPerson": MessageLookupByLibrary.simpleMessage("Связать человека"), "linkPersonCaption": MessageLookupByLibrary.simpleMessage("чтобы было удобнее делиться"), - "linkPersonToEmail": m47, - "linkPersonToEmailConfirmation": m48, + "linkPersonToEmail": m48, + "linkPersonToEmailConfirmation": m49, "livePhotos": MessageLookupByLibrary.simpleMessage("Живые фото"), "loadMessage1": MessageLookupByLibrary.simpleMessage( "Вы можете поделиться подпиской с вашей семьёй"), @@ -1256,8 +1279,6 @@ class MessageLookup extends MessageLookupByLibrary { "Нажмите с удержанием на электронную почту для подтверждения сквозного шифрования."), "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Нажмите с удержанием на элемент для просмотра в полноэкранном режиме"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "loopVideoOff": MessageLookupByLibrary.simpleMessage("Видео не зациклено"), "loopVideoOn": MessageLookupByLibrary.simpleMessage("Видео зациклено"), @@ -1286,7 +1307,7 @@ class MessageLookup extends MessageLookupByLibrary { "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), "me": MessageLookupByLibrary.simpleMessage("Я"), - "memoryCount": m49, + "memoryCount": m50, "merchandise": MessageLookupByLibrary.simpleMessage("Мерч"), "mergeWithExisting": MessageLookupByLibrary.simpleMessage("Объединить с существующим"), @@ -1319,14 +1340,14 @@ class MessageLookup extends MessageLookupByLibrary { "mostRelevant": MessageLookupByLibrary.simpleMessage("Самые актуальные"), "mountains": MessageLookupByLibrary.simpleMessage("За холмами"), - "moveItem": m50, + "moveItem": m51, "moveSelectedPhotosToOneDate": MessageLookupByLibrary.simpleMessage( "Переместите выбранные фото на одну дату"), "moveToAlbum": MessageLookupByLibrary.simpleMessage("Переместить в альбом"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage( "Переместить в скрытый альбом"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("Перемещено в корзину"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1343,7 +1364,6 @@ class MessageLookup extends MessageLookupByLibrary { "newLocation": MessageLookupByLibrary.simpleMessage("Новое местоположение"), "newPerson": MessageLookupByLibrary.simpleMessage("Новый человек"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "newRange": MessageLookupByLibrary.simpleMessage("Новый диапазон"), "newToEnte": MessageLookupByLibrary.simpleMessage("Впервые в Ente"), "newest": MessageLookupByLibrary.simpleMessage("Недавние"), @@ -1382,10 +1402,10 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Нет результатов"), "noResultsFound": MessageLookupByLibrary.simpleMessage("Нет результатов"), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage( "Системная блокировка не найдена"), - "notPersonLabel": m53, + "notPersonLabel": m54, "notThisPerson": MessageLookupByLibrary.simpleMessage("Не этот человек?"), "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( @@ -1398,10 +1418,7 @@ class MessageLookup extends MessageLookupByLibrary { "onEnte": MessageLookupByLibrary.simpleMessage("В ente"), "onTheRoad": MessageLookupByLibrary.simpleMessage("Снова в пути"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("Только он(а)"), "oops": MessageLookupByLibrary.simpleMessage("Ой"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( @@ -1432,7 +1449,7 @@ class MessageLookup extends MessageLookupByLibrary { "pairingComplete": MessageLookupByLibrary.simpleMessage("Подключение завершено"), "panorama": MessageLookupByLibrary.simpleMessage("Панорама"), - "partyWithThem": m55, + "partyWithThem": m56, "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage("Проверка всё ещё ожидается"), "passkey": MessageLookupByLibrary.simpleMessage("Ключ доступа"), @@ -1442,7 +1459,7 @@ class MessageLookup extends MessageLookupByLibrary { "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage("Пароль успешно изменён"), "passwordLock": MessageLookupByLibrary.simpleMessage("Защита паролем"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "Надёжность пароля определяется его длиной, используемыми символами и присутствием среди 10000 самых популярных паролей"), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -1453,7 +1470,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Платёж не удался"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "К сожалению, ваш платёж не удался. Пожалуйста, свяжитесь с поддержкой, и мы вам поможем!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("Элементы в очереди"), "pendingSync": @@ -1467,21 +1484,21 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Удалить безвозвратно"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage( "Удалить с устройства безвозвратно?"), - "personIsAge": m58, + "personIsAge": m59, "personName": MessageLookupByLibrary.simpleMessage("Имя человека"), - "personTurningAge": m59, + "personTurningAge": m60, "pets": MessageLookupByLibrary.simpleMessage("Пушистые спутники"), "photoDescriptions": MessageLookupByLibrary.simpleMessage("Описания фото"), "photoGridSize": MessageLookupByLibrary.simpleMessage("Размер сетки фото"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("фото"), - "photocountPhotos": m60, + "photocountPhotos": m61, "photos": MessageLookupByLibrary.simpleMessage("Фото"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage( "Добавленные вами фото будут удалены из альбома"), - "photosCount": m61, + "photosCount": m62, "photosKeepRelativeTimeDifference": MessageLookupByLibrary.simpleMessage( "Фото сохранят относительную разницу во времени"), @@ -1493,7 +1510,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Воспроизвести альбом на ТВ"), "playOriginal": MessageLookupByLibrary.simpleMessage("Воспроизвести оригинал"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playStream": MessageLookupByLibrary.simpleMessage("Воспроизвести поток"), "playstoreSubscription": @@ -1507,14 +1524,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Пожалуйста, обратитесь в поддержку, если проблема сохраняется"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage( "Пожалуйста, предоставьте разрешения"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Пожалуйста, войдите снова"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Пожалуйста, выберите быстрые ссылки для удаления"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Пожалуйста, попробуйте снова"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1529,7 +1546,7 @@ class MessageLookup extends MessageLookupByLibrary { "Пожалуйста, подождите некоторое время перед повторной попыткой"), "pleaseWaitThisWillTakeAWhile": MessageLookupByLibrary.simpleMessage( "Пожалуйста, подождите, это займёт некоторое время."), - "posingWithThem": m65, + "posingWithThem": m66, "preparingLogs": MessageLookupByLibrary.simpleMessage("Подготовка логов..."), "preserveMore": @@ -1549,7 +1566,7 @@ class MessageLookup extends MessageLookupByLibrary { "proceed": MessageLookupByLibrary.simpleMessage("Продолжить"), "processed": MessageLookupByLibrary.simpleMessage("Обработано"), "processing": MessageLookupByLibrary.simpleMessage("Обработка"), - "processingImport": m66, + "processingImport": m67, "processingVideos": MessageLookupByLibrary.simpleMessage("Обработка видео"), "publicLinkCreated": @@ -1563,10 +1580,10 @@ class MessageLookup extends MessageLookupByLibrary { "rateTheApp": MessageLookupByLibrary.simpleMessage("Оценить приложение"), "rateUs": MessageLookupByLibrary.simpleMessage("Оцените нас"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "reassignMe": MessageLookupByLibrary.simpleMessage("Переназначить \"Меня\""), - "reassignedToName": m68, + "reassignedToName": m69, "reassigningLoading": MessageLookupByLibrary.simpleMessage("Переназначение..."), "recover": MessageLookupByLibrary.simpleMessage("Восстановить"), @@ -1577,7 +1594,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Восстановить аккаунт"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage("Восстановление начато"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("Ключ восстановления"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( @@ -1592,12 +1609,12 @@ class MessageLookup extends MessageLookupByLibrary { "Ключ восстановления подтверждён"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "Ваш ключ восстановления — единственный способ восстановить ваши фото, если вы забудете пароль. Вы можете найти ключ восстановления в разделе «Настройки» → «Аккаунт».\n\nПожалуйста, введите ваш ключ восстановления здесь, чтобы убедиться, что вы сохранили его правильно."), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage("Успешное восстановление!"), "recoveryWarning": MessageLookupByLibrary.simpleMessage( "Доверенный контакт пытается получить доступ к вашему аккаунту"), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "Текущее устройство недостаточно мощное для проверки вашего пароля, но мы можем сгенерировать его снова так, чтобы он работал на всех устройствах.\n\nПожалуйста, войдите, используя ваш ключ восстановления, и сгенерируйте пароль (при желании вы можете использовать тот же самый)."), "recreatePasswordTitle": @@ -1613,7 +1630,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Даёте этот код своим друзьям"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Они подписываются на платный тариф"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("Рефералы"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Реферальная программа временно приостановлена"), @@ -1645,7 +1662,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Удалить ссылку"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Удалить участника"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Удалить метку человека"), "removePublicLink": @@ -1667,7 +1684,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Переименовать файл"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Продлить подписку"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Сообщить об ошибке"), "reportBug": MessageLookupByLibrary.simpleMessage("Сообщить об ошибке"), @@ -1694,7 +1711,7 @@ class MessageLookup extends MessageLookupByLibrary { "reviewSuggestions": MessageLookupByLibrary.simpleMessage("Посмотреть предложения"), "right": MessageLookupByLibrary.simpleMessage("Вправо"), - "roadtripWithThem": m75, + "roadtripWithThem": m76, "rotate": MessageLookupByLibrary.simpleMessage("Повернуть"), "rotateLeft": MessageLookupByLibrary.simpleMessage("Повернуть влево"), "rotateRight": MessageLookupByLibrary.simpleMessage("Повернуть вправо"), @@ -1751,8 +1768,8 @@ class MessageLookup extends MessageLookupByLibrary { "Приглашайте людей, и здесь появятся все фото, которыми они поделились"), "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage( "Люди появятся здесь после завершения обработки и синхронизации"), - "searchResultCount": m76, - "searchSectionsLengthMismatch": m77, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("Безопасность"), "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage( "Просматривать публичные ссылки на альбомы в приложении"), @@ -1801,9 +1818,9 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeRemovedFromThisPerson": MessageLookupByLibrary.simpleMessage( "Выбранные элементы будут отвязаны от этого человека, но не удалены из вашей библиотеки."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, - "selfiesWithThem": m80, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, + "selfiesWithThem": m82, "send": MessageLookupByLibrary.simpleMessage("Отправить"), "sendEmail": MessageLookupByLibrary.simpleMessage( "Отправить электронное письмо"), @@ -1838,16 +1855,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Поделиться альбомом"), "shareLink": MessageLookupByLibrary.simpleMessage("Поделиться ссылкой"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Делитесь только с теми, с кем хотите"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Скачай Ente, чтобы мы могли легко делиться фото и видео в оригинальном качестве\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Поделиться с пользователями, не использующими Ente"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage( "Поделитесь своим первым альбомом"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1858,7 +1875,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Новые общие фото"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "Получать уведомления, когда кто-то добавляет фото в общий альбом, в котором вы состоите"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Со мной поделились"), "sharedWithYou": @@ -1877,11 +1894,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Выйти с других устройств"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Я согласен с условиями предоставления услуг и политикой конфиденциальности"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "Оно будет удалено из всех альбомов."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("Пропустить"), "social": MessageLookupByLibrary.simpleMessage("Социальные сети"), "someItemsAreInBothEnteAndYourDevice": MessageLookupByLibrary.simpleMessage( @@ -1909,8 +1926,6 @@ class MessageLookup extends MessageLookupByLibrary { "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "К сожалению, мы не смогли сгенерировать безопасные ключи на этом устройстве.\n\nПожалуйста, зарегистрируйтесь с другого устройства."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "sort": MessageLookupByLibrary.simpleMessage("Сортировать"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Сортировать по"), "sortNewestFirst": @@ -1918,8 +1933,8 @@ class MessageLookup extends MessageLookupByLibrary { "sortOldestFirst": MessageLookupByLibrary.simpleMessage("Сначала старые"), "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ Успех"), - "sportsWithThem": m89, - "spotlightOnThem": m90, + "sportsWithThem": m91, + "spotlightOnThem": m92, "spotlightOnYourself": MessageLookupByLibrary.simpleMessage("Вы в центре внимания"), "startAccountRecoveryTitle": @@ -1934,15 +1949,15 @@ class MessageLookup extends MessageLookupByLibrary { "storage": MessageLookupByLibrary.simpleMessage("Хранилище"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Семья"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Вы"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage("Превышен лимит хранилища"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "streamDetails": MessageLookupByLibrary.simpleMessage("Информация о потоке"), "strongStrength": MessageLookupByLibrary.simpleMessage("Высокая"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("Подписаться"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "Вам нужна активная платная подписка, чтобы включить общий доступ."), @@ -1960,7 +1975,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Предложить идею"), "sunrise": MessageLookupByLibrary.simpleMessage("На горизонте"), "support": MessageLookupByLibrary.simpleMessage("Поддержка"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("Синхронизация остановлена"), "syncing": MessageLookupByLibrary.simpleMessage("Синхронизация..."), @@ -1973,7 +1988,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Нажмите для разблокировки"), "tapToUpload": MessageLookupByLibrary.simpleMessage("Нажмите для загрузки"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Похоже, что-то пошло не так. Пожалуйста, повторите попытку через некоторое время. Если ошибка сохраняется, обратитесь в нашу службу поддержки."), "terminate": MessageLookupByLibrary.simpleMessage("Завершить"), @@ -1997,7 +2012,7 @@ class MessageLookup extends MessageLookupByLibrary { "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage( "Эти элементы будут удалены с вашего устройства."), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage( "Они будут удалены из всех альбомов."), "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( @@ -2014,12 +2029,12 @@ class MessageLookup extends MessageLookupByLibrary { "thisImageHasNoExifData": MessageLookupByLibrary.simpleMessage( "Это фото не имеет данных EXIF"), "thisIsMeExclamation": MessageLookupByLibrary.simpleMessage("Это я!"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( "Это ваш идентификатор подтверждения"), "thisWeekThroughTheYears": MessageLookupByLibrary.simpleMessage("Эта неделя сквозь годы"), - "thisWeekXYearsAgo": m99, + "thisWeekXYearsAgo": m101, "thisWillLogYouOutOfTheFollowingDevice": MessageLookupByLibrary.simpleMessage( "Это завершит ваш сеанс на следующем устройстве:"), @@ -2031,7 +2046,7 @@ class MessageLookup extends MessageLookupByLibrary { "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( "Это удалит публичные ссылки всех выбранных быстрых ссылок."), - "throughTheYears": m100, + "throughTheYears": m102, "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": MessageLookupByLibrary.simpleMessage( "Для блокировки приложения, пожалуйста, настройте код или экран блокировки в настройках устройства."), @@ -2045,13 +2060,13 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("всего"), "totalSize": MessageLookupByLibrary.simpleMessage("Общий размер"), "trash": MessageLookupByLibrary.simpleMessage("Корзина"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("Сократить"), - "tripInYear": m102, - "tripToLocation": m103, + "tripInYear": m104, + "tripToLocation": m105, "trustedContacts": MessageLookupByLibrary.simpleMessage("Доверенные контакты"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("Попробовать снова"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "Включите резервное копирование, чтобы автоматически загружать файлы из этой папки на устройстве в Ente."), @@ -2071,7 +2086,7 @@ class MessageLookup extends MessageLookupByLibrary { "Двухфакторная аутентификация успешно сброшена"), "twofactorSetup": MessageLookupByLibrary.simpleMessage( "Настройка двухфакторной аутентификации"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("Извлечь из архива"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("Извлечь альбом из архива"), @@ -2094,10 +2109,10 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage("Обновление выбора папок..."), "upgrade": MessageLookupByLibrary.simpleMessage("Улучшить"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage("Загрузка файлов в альбом..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage( "Сохранение 1 воспоминания..."), "upto50OffUntil4thDec": @@ -2116,7 +2131,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("Использовать выбранное фото"), "usedSpace": MessageLookupByLibrary.simpleMessage("Использовано места"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Проверка не удалась, пожалуйста, попробуйте снова"), @@ -2125,7 +2140,7 @@ class MessageLookup extends MessageLookupByLibrary { "verify": MessageLookupByLibrary.simpleMessage("Подтвердить"), "verifyEmail": MessageLookupByLibrary.simpleMessage( "Подтвердить электронную почту"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Подтвердить"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("Подтвердить ключ доступа"), @@ -2151,7 +2166,7 @@ class MessageLookup extends MessageLookupByLibrary { "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("Увидеть ключ восстановления"), "viewer": MessageLookupByLibrary.simpleMessage("Зритель"), - "viewersSuccessfullyAdded": m111, + "viewersSuccessfullyAdded": m113, "visitWebToManage": MessageLookupByLibrary.simpleMessage( "Пожалуйста, посетите web.ente.io для управления вашей подпиской"), "waitingForVerification": @@ -2164,15 +2179,16 @@ class MessageLookup extends MessageLookupByLibrary { "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "Мы не поддерживаем редактирование фото и альбомов, которые вам пока не принадлежат"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Низкая"), "welcomeBack": MessageLookupByLibrary.simpleMessage("С возвращением!"), "whatsNew": MessageLookupByLibrary.simpleMessage("Что нового"), "whyAddTrustContact": MessageLookupByLibrary.simpleMessage( "Доверенный контакт может помочь в восстановлении ваших данных."), + "wishThemAHappyBirthday": m115, "yearShort": MessageLookupByLibrary.simpleMessage("год"), "yearly": MessageLookupByLibrary.simpleMessage("Ежегодно"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Да"), "yesCancel": MessageLookupByLibrary.simpleMessage("Да, отменить"), "yesConvertToViewer": @@ -2186,7 +2202,7 @@ class MessageLookup extends MessageLookupByLibrary { "yesResetPerson": MessageLookupByLibrary.simpleMessage( "Да, сбросить данные человека"), "you": MessageLookupByLibrary.simpleMessage("Вы"), - "youAndThem": m114, + "youAndThem": m117, "youAreOnAFamilyPlan": MessageLookupByLibrary.simpleMessage("Вы на семейном тарифе!"), "youAreOnTheLatestVersion": MessageLookupByLibrary.simpleMessage( @@ -2205,7 +2221,7 @@ class MessageLookup extends MessageLookupByLibrary { "Вы не можете поделиться с самим собой"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( "У вас нет архивных элементов."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("Ваш аккаунт был удалён"), "yourMap": MessageLookupByLibrary.simpleMessage("Ваша карта"), diff --git a/mobile/lib/generated/intl/messages_sl.dart b/mobile/lib/generated/intl/messages_sl.dart index 7234775c48..c3c41dfa40 100644 --- a/mobile/lib/generated/intl/messages_sl.dart +++ b/mobile/lib/generated/intl/messages_sl.dart @@ -20,17 +20,9 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'sl'; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => { - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups") - }; + static Map _notInlinedMessages(_) => + {"wishThemAHappyBirthday": m115}; } diff --git a/mobile/lib/generated/intl/messages_sr.dart b/mobile/lib/generated/intl/messages_sr.dart new file mode 100644 index 0000000000..d4c1e9dc57 --- /dev/null +++ b/mobile/lib/generated/intl/messages_sr.dart @@ -0,0 +1,42 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a sr locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'sr'; + + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "areThey": MessageLookupByLibrary.simpleMessage("Are they "), + "areYouSureRemoveThisFaceFromPerson": + MessageLookupByLibrary.simpleMessage( + "Are you sure you want to remove this face from this person?"), + "otherDetectedFaces": + MessageLookupByLibrary.simpleMessage("Other detected faces"), + "questionmark": MessageLookupByLibrary.simpleMessage("?"), + "saveAsAnotherPerson": + MessageLookupByLibrary.simpleMessage("Save as another person"), + "showLessFaces": + MessageLookupByLibrary.simpleMessage("Show less faces"), + "showMoreFaces": + MessageLookupByLibrary.simpleMessage("Show more faces"), + "wishThemAHappyBirthday": m115 + }; +} diff --git a/mobile/lib/generated/intl/messages_sv.dart b/mobile/lib/generated/intl/messages_sv.dart index 0aaac88fcb..15748c8a64 100644 --- a/mobile/lib/generated/intl/messages_sv.dart +++ b/mobile/lib/generated/intl/messages_sv.dart @@ -41,69 +41,70 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'Radera ${count} objekt', other: 'Radera ${count} objekt')}"; - static String m24(supportEmail) => + static String m25(supportEmail) => "Vänligen skicka ett e-postmeddelande till ${supportEmail} från din registrerade e-postadress"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} filer, ${formattedSize} vardera"; - static String m30(email) => + static String m31(email) => "${email} har inte ett Ente-konto.\n\nSkicka dem en inbjudan för att dela bilder."; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "${storageAmountInGB} GB varje gång någon registrerar sig för en betalplan och tillämpar din kod"; - static String m43(count) => - "${Intl.plural(count, one: '${count} objekt', other: '${count} objekt')}"; + static String m44(count) => "${Intl.plural(count, other: '${count} objekt')}"; - static String m46(expiryTime) => "Länken upphör att gälla ${expiryTime}"; + static String m47(expiryTime) => "Länken upphör att gälla ${expiryTime}"; - static String m53(name) => "Inte ${name}?"; + static String m54(name) => "Inte ${name}?"; - static String m54(familyAdminEmail) => + static String m55(familyAdminEmail) => "Kontakta ${familyAdminEmail} för att ändra din kod."; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Lösenordsstyrka: ${passwordStrengthValue}"; - static String m67(storeName) => "Betygsätt oss på ${storeName}"; + static String m68(storeName) => "Betygsätt oss på ${storeName}"; - static String m72(storageInGB) => "3. Ni får båda ${storageInGB} GB* gratis"; + static String m73(storageInGB) => "3. Ni får båda ${storageInGB} GB* gratis"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} kommer att tas bort från detta delade album\n\nAlla bilder som lagts till av dem kommer också att tas bort från albumet"; - static String m76(count) => - "${Intl.plural(count, one: '${count} resultat hittades', other: '${count} resultat hittades')}"; + static String m77(count) => + "${Intl.plural(count, other: '${count} resultat hittades')}"; - static String m81(verificationID) => + static String m83(verificationID) => "Här är mitt verifierings-ID: ${verificationID} för ente.io."; - static String m82(verificationID) => + static String m84(verificationID) => "Hallå, kan du bekräfta att detta är ditt ente.io verifierings-ID: ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Ente värvningskod: ${referralCode} \n\nTillämpa den i Inställningar → Allmänt → Hänvisningar för att få ${referralStorageInGB} GB gratis när du registrerar dig för en betalplan\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Dela med specifika personer', one: 'Delad med en person', other: 'Delad med ${numberOfPeople} personer')}"; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "De får också ${storageAmountInGB} GB"; - static String m98(email) => "Detta är ${email}s verifierings-ID"; + static String m100(email) => "Detta är ${email}s verifierings-ID"; - static String m107(count) => "Bevarar ${count} minnen..."; + static String m109(count) => "Bevarar ${count} minnen..."; - static String m109(email) => "Bekräfta ${email}"; + static String m111(email) => "Bekräfta ${email}"; - static String m112(email) => + static String m114(email) => "Vi har skickat ett e-postmeddelande till ${email}"; - static String m113(count) => - "${Intl.plural(count, one: '${count} år sedan', other: '${count} år sedan')}"; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + + static String m116(count) => + "${Intl.plural(count, other: '${count} år sedan')}"; final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { @@ -152,6 +153,10 @@ class MessageLookup extends MessageLookupByLibrary { "appVersion": m9, "apply": MessageLookupByLibrary.simpleMessage("Verkställ"), "applyCodeTitle": MessageLookupByLibrary.simpleMessage("Använd kod"), + "areThey": MessageLookupByLibrary.simpleMessage("Are they "), + "areYouSureRemoveThisFaceFromPerson": + MessageLookupByLibrary.simpleMessage( + "Are you sure you want to remove this face from this person?"), "areYouSureYouWantToLogout": MessageLookupByLibrary.simpleMessage( "Är du säker på att du vill logga ut?"), "askDeleteReason": MessageLookupByLibrary.simpleMessage( @@ -192,8 +197,6 @@ class MessageLookup extends MessageLookupByLibrary { "claimed": MessageLookupByLibrary.simpleMessage("Nyttjad"), "claimedStorageSoFar": m14, "clearIndexes": MessageLookupByLibrary.simpleMessage("Rensa index"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "close": MessageLookupByLibrary.simpleMessage("Stäng"), "codeAppliedPageTitle": MessageLookupByLibrary.simpleMessage("Kod tillämpad"), @@ -287,14 +290,14 @@ class MessageLookup extends MessageLookupByLibrary { "discover_receipts": MessageLookupByLibrary.simpleMessage("Kvitton"), "doThisLater": MessageLookupByLibrary.simpleMessage("Gör detta senare"), "done": MessageLookupByLibrary.simpleMessage("Klar"), - "dropSupportEmail": m24, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("Redigera"), "eligible": MessageLookupByLibrary.simpleMessage("berättigad"), "email": MessageLookupByLibrary.simpleMessage("E-post"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage( "E-postadress redan registrerad."), - "emailNoEnteAccount": m30, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage( "E-postadressen är inte registrerad."), "encryption": MessageLookupByLibrary.simpleMessage("Kryptering"), @@ -344,7 +347,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Glömt lösenord"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("Gratis lagring begärd"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage( "Gratis lagringsutrymme som kan användas"), "freeTrial": MessageLookupByLibrary.simpleMessage("Gratis provperiod"), @@ -381,7 +384,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Bjud in dina vänner"), "inviteYourFriendsToEnte": MessageLookupByLibrary.simpleMessage( "Bjud in dina vänner till Ente"), - "itemCount": m43, + "itemCount": m44, "itemsWillBeRemovedFromAlbum": MessageLookupByLibrary.simpleMessage( "Valda objekt kommer att tas bort från detta album"), "keepPhotos": MessageLookupByLibrary.simpleMessage("Behåll foton"), @@ -394,7 +397,7 @@ class MessageLookup extends MessageLookupByLibrary { "linkDeviceLimit": MessageLookupByLibrary.simpleMessage("Enhetsgräns"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Aktiverat"), "linkExpired": MessageLookupByLibrary.simpleMessage("Upphört"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Länken upphör"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("Länk har upphört att gälla"), @@ -406,8 +409,6 @@ class MessageLookup extends MessageLookupByLibrary { "loginTerms": MessageLookupByLibrary.simpleMessage( "Genom att klicka på logga in godkänner jag användarvillkoren och våran integritetspolicy"), "logout": MessageLookupByLibrary.simpleMessage("Logga ut"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "lostDevice": MessageLookupByLibrary.simpleMessage("Förlorad enhet?"), "machineLearning": MessageLookupByLibrary.simpleMessage("Maskininlärning"), @@ -431,7 +432,6 @@ class MessageLookup extends MessageLookupByLibrary { "never": MessageLookupByLibrary.simpleMessage("Aldrig"), "newAlbum": MessageLookupByLibrary.simpleMessage("Nytt album"), "newPerson": MessageLookupByLibrary.simpleMessage("Ny person"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "next": MessageLookupByLibrary.simpleMessage("Nästa"), "no": MessageLookupByLibrary.simpleMessage("Nej"), "noDeviceLimit": MessageLookupByLibrary.simpleMessage("Ingen"), @@ -445,23 +445,22 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Inga resultat"), "noResultsFound": MessageLookupByLibrary.simpleMessage("Inga resultat hittades"), - "notPersonLabel": m53, + "notPersonLabel": m54, "ok": MessageLookupByLibrary.simpleMessage("OK"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "onlyFamilyAdminCanChangeCode": m55, "oops": MessageLookupByLibrary.simpleMessage("Hoppsan"), "oopsSomethingWentWrong": MessageLookupByLibrary.simpleMessage("Oj, något gick fel"), "orPickAnExistingOne": MessageLookupByLibrary.simpleMessage("Eller välj en befintlig"), + "otherDetectedFaces": + MessageLookupByLibrary.simpleMessage("Other detected faces"), "passkey": MessageLookupByLibrary.simpleMessage("Nyckel"), "password": MessageLookupByLibrary.simpleMessage("Lösenord"), "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage("Lösenordet har ändrats"), "passwordLock": MessageLookupByLibrary.simpleMessage("Lösenordskydd"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordWarning": MessageLookupByLibrary.simpleMessage( "Vi lagrar inte detta lösenord, så om du glömmer bort det, kan vi inte dekryptera dina data"), "peopleUsingYourCode": MessageLookupByLibrary.simpleMessage( @@ -478,7 +477,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Integritetspolicy"), "publicLinkEnabled": MessageLookupByLibrary.simpleMessage("Offentlig länk aktiverad"), - "rateUsOnStore": m67, + "questionmark": MessageLookupByLibrary.simpleMessage("?"), + "rateUsOnStore": m68, "recover": MessageLookupByLibrary.simpleMessage("Återställ"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Återställ konto"), @@ -508,7 +508,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Ge denna kod till dina vänner"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. De registrerar sig för en betalplan"), - "referralStep3": m72, + "referralStep3": m73, "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Hänvisningar är för närvarande pausade"), "remove": MessageLookupByLibrary.simpleMessage("Ta bort"), @@ -519,7 +519,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Radera länk"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Ta bort användaren"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removeShareItemsWarning": MessageLookupByLibrary.simpleMessage( "Några av de objekt som du tar bort lades av andra personer, och du kommer att förlora tillgång till dem"), "removeWithQuestionMark": @@ -536,6 +536,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Återställ till standard"), "retry": MessageLookupByLibrary.simpleMessage("Försök igen"), "save": MessageLookupByLibrary.simpleMessage("Spara"), + "saveAsAnotherPerson": + MessageLookupByLibrary.simpleMessage("Save as another person"), "saveCopy": MessageLookupByLibrary.simpleMessage("Spara kopia"), "saveKey": MessageLookupByLibrary.simpleMessage("Spara nyckel"), "saveYourRecoveryKeyIfYouHaventAlready": @@ -552,7 +554,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Albumnamn"), "searchFileTypesAndNamesEmptySection": MessageLookupByLibrary.simpleMessage("Filtyper och namn"), - "searchResultCount": m76, + "searchResultCount": m77, "selectAlbum": MessageLookupByLibrary.simpleMessage("Välj album"), "selectAll": MessageLookupByLibrary.simpleMessage("Markera allt"), "selectFoldersForBackup": MessageLookupByLibrary.simpleMessage( @@ -575,19 +577,23 @@ class MessageLookup extends MessageLookupByLibrary { "share": MessageLookupByLibrary.simpleMessage("Dela"), "shareALink": MessageLookupByLibrary.simpleMessage("Dela en länk"), "shareLink": MessageLookupByLibrary.simpleMessage("Dela länk"), - "shareMyVerificationID": m81, - "shareTextConfirmOthersVerificationID": m82, + "shareMyVerificationID": m83, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Ladda ner Ente så att vi enkelt kan dela bilder och videor med originell kvalitet\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Dela med icke-Ente användare"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage("Dela ditt första album"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( "Skapa delade och samarbetande album med andra Ente användare, inklusive användare med gratisnivån."), + "showLessFaces": + MessageLookupByLibrary.simpleMessage("Show less faces"), "showMemories": MessageLookupByLibrary.simpleMessage("Visa minnen"), + "showMoreFaces": + MessageLookupByLibrary.simpleMessage("Show more faces"), "showPerson": MessageLookupByLibrary.simpleMessage("Visa person"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Jag samtycker till användarvillkoren och integritetspolicyn"), @@ -609,13 +615,11 @@ class MessageLookup extends MessageLookupByLibrary { "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "Tyvärr, vi kunde inte generera säkra nycklar på den här enheten.\n\nVänligen registrera dig från en annan enhet."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "sort": MessageLookupByLibrary.simpleMessage("Sortera"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Sortera efter"), "status": MessageLookupByLibrary.simpleMessage("Status"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Du"), - "storageInGB": m91, + "storageInGB": m93, "strongStrength": MessageLookupByLibrary.simpleMessage("Starkt"), "subscribe": MessageLookupByLibrary.simpleMessage("Prenumerera"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( @@ -635,12 +639,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Återställningsnyckeln du angav är felaktig"), "theme": MessageLookupByLibrary.simpleMessage("Tema"), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "thisCanBeUsedToRecoverYourAccountIfYou": MessageLookupByLibrary.simpleMessage( "Detta kan användas för att återställa ditt konto om du förlorar din andra faktor"), "thisDevice": MessageLookupByLibrary.simpleMessage("Den här enheten"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( "Detta är ditt verifierings-ID"), "thisWillLogYouOutOfTheFollowingDevice": @@ -668,7 +672,7 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage("Uppdaterar mappval..."), "upgrade": MessageLookupByLibrary.simpleMessage("Uppgradera"), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage("Bevarar 1 minne..."), "usableReferralStorageInfo": MessageLookupByLibrary.simpleMessage( @@ -681,7 +685,7 @@ class MessageLookup extends MessageLookupByLibrary { "verify": MessageLookupByLibrary.simpleMessage("Bekräfta"), "verifyEmail": MessageLookupByLibrary.simpleMessage("Bekräfta e-postadress"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyPasskey": MessageLookupByLibrary.simpleMessage("Verifiera nyckel"), "verifyPassword": @@ -697,12 +701,13 @@ class MessageLookup extends MessageLookupByLibrary { "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("Visa återställningsnyckel"), "viewer": MessageLookupByLibrary.simpleMessage("Bildvy"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Svagt"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Välkommen tillbaka!"), "whatsNew": MessageLookupByLibrary.simpleMessage("Nyheter"), - "yearsAgo": m113, + "wishThemAHappyBirthday": m115, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Ja"), "yesCancel": MessageLookupByLibrary.simpleMessage("Ja, avbryt"), "yesConvertToViewer": diff --git a/mobile/lib/generated/intl/messages_ta.dart b/mobile/lib/generated/intl/messages_ta.dart index cb54ab10f2..9fad77b2a9 100644 --- a/mobile/lib/generated/intl/messages_ta.dart +++ b/mobile/lib/generated/intl/messages_ta.dart @@ -20,6 +20,8 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'ta'; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { "accountWelcomeBack": @@ -27,8 +29,6 @@ class MessageLookup extends MessageLookupByLibrary { "askDeleteReason": MessageLookupByLibrary.simpleMessage( "உங்கள் கணக்கை நீக்குவதற்கான முக்கிய காரணம் என்ன?"), "cancel": MessageLookupByLibrary.simpleMessage("ரத்து செய்"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage( "கணக்கு நீக்குதலை உறுதிப்படுத்தவும்"), "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( @@ -54,17 +54,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("தவறான மின்னஞ்சல் முகவரி"), "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( "இந்த தகவலுடன் தயவுசெய்து எங்களுக்கு உதவுங்கள்"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), "selectReason": MessageLookupByLibrary.simpleMessage( "காரணத்தைத் தேர்ந்தெடுக்கவும்"), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "verify": MessageLookupByLibrary.simpleMessage("சரிபார்க்கவும்"), + "wishThemAHappyBirthday": m115, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("உங்கள் கணக்கு நீக்கப்பட்டது") }; diff --git a/mobile/lib/generated/intl/messages_te.dart b/mobile/lib/generated/intl/messages_te.dart index c9b95640ab..9648051033 100644 --- a/mobile/lib/generated/intl/messages_te.dart +++ b/mobile/lib/generated/intl/messages_te.dart @@ -20,17 +20,9 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'te'; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => { - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups") - }; + static Map _notInlinedMessages(_) => + {"wishThemAHappyBirthday": m115}; } diff --git a/mobile/lib/generated/intl/messages_th.dart b/mobile/lib/generated/intl/messages_th.dart index 544abcd1e5..7a86a39c80 100644 --- a/mobile/lib/generated/intl/messages_th.dart +++ b/mobile/lib/generated/intl/messages_th.dart @@ -25,25 +25,27 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'ลบ ${count} รายการ', other: 'ลบ ${count} รายการ')}"; - static String m22(currentlyDeleting, totalCount) => + static String m23(currentlyDeleting, totalCount) => "กำลังลบ ${currentlyDeleting} / ${totalCount}"; - static String m24(supportEmail) => + static String m25(supportEmail) => "กรุณาส่งอีเมลไปที่ ${supportEmail} จากที่อยู่อีเมลที่คุณลงทะเบียนไว้"; - static String m41(currentlyProcessing, totalCount) => + static String m42(currentlyProcessing, totalCount) => "กำลังประมวลผล ${currentlyProcessing} / ${totalCount}"; - static String m43(count) => "${Intl.plural(count, other: '${count} รายการ')}"; + static String m44(count) => "${Intl.plural(count, other: '${count} รายการ')}"; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "ความแข็งแรงของรหัสผ่าน: ${passwordStrengthValue}"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "ใช้ไป ${usedAmount} ${usedStorageUnit} จาก ${totalAmount} ${totalStorageUnit}"; - static String m112(email) => "เราได้ส่งจดหมายไปยัง ${email}"; + static String m114(email) => "เราได้ส่งจดหมายไปยัง ${email}"; + + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { @@ -87,8 +89,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("เปลี่ยนรหัสผ่าน"), "checkInboxAndSpamFolder": MessageLookupByLibrary.simpleMessage( "โปรดตรวจสอบกล่องจดหมาย (และสแปม) ของคุณ เพื่อยืนยันให้เสร็จสิ้น"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "codeCopiedToClipboard": MessageLookupByLibrary.simpleMessage( "คัดลอกรหัสไปยังคลิปบอร์ดแล้ว"), "collectPhotos": MessageLookupByLibrary.simpleMessage("รวบรวมรูปภาพ"), @@ -128,7 +128,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "ลบอัลบั้มที่ว่างเปล่าหรือไม่?"), "deleteItemCount": m21, - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "ขาดคุณสมบัติสำคัญที่ฉันต้องการ"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -140,7 +140,7 @@ class MessageLookup extends MessageLookupByLibrary { "deleteRequestSLAText": MessageLookupByLibrary.simpleMessage( "คำขอของคุณจะได้รับการดำเนินการภายใน 72 ชั่วโมง"), "doThisLater": MessageLookupByLibrary.simpleMessage("ทำในภายหลัง"), - "dropSupportEmail": m24, + "dropSupportEmail": m25, "edit": MessageLookupByLibrary.simpleMessage("แก้ไข"), "editLocationTagTitle": MessageLookupByLibrary.simpleMessage("แก้ไขตำแหน่ง"), @@ -169,7 +169,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("เพิ่มคำอธิบาย..."), "forgotPassword": MessageLookupByLibrary.simpleMessage("ลืมรหัสผ่าน"), "freeTrial": MessageLookupByLibrary.simpleMessage("ทดลองใช้ฟรี"), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("ไปที่การตั้งค่า"), "hide": MessageLookupByLibrary.simpleMessage("ซ่อน"), "hostedAtOsmFrance": @@ -192,7 +192,7 @@ class MessageLookup extends MessageLookupByLibrary { "invalidKey": MessageLookupByLibrary.simpleMessage("รหัสไม่ถูกต้อง"), "invalidRecoveryKey": MessageLookupByLibrary.simpleMessage( "คีย์การกู้คืนที่คุณป้อนไม่ถูกต้อง โปรดตรวจสอบให้แน่ใจว่ามี 24 คำ และตรวจสอบการสะกดของแต่ละคำ\n\nหากคุณป้อนรหัสกู้คืนที่เก่ากว่า ตรวจสอบให้แน่ใจว่ามีความยาว 64 ตัวอักษร และตรวจสอบแต่ละตัวอักษร"), - "itemCount": m43, + "itemCount": m44, "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage("กรุณาช่วยเราด้วยข้อมูลนี้"), "lastUpdated": MessageLookupByLibrary.simpleMessage("อัปเดตล่าสุด"), @@ -206,15 +206,12 @@ class MessageLookup extends MessageLookupByLibrary { "logInLabel": MessageLookupByLibrary.simpleMessage("เข้าสู่ระบบ"), "loginTerms": MessageLookupByLibrary.simpleMessage( "โดยการคลิกเข้าสู่ระบบ ฉันยอมรับเงื่อนไขการให้บริการและนโยบายความเป็นส่วนตัว"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "manageParticipants": MessageLookupByLibrary.simpleMessage("จัดการ"), "map": MessageLookupByLibrary.simpleMessage("แผนที่"), "maps": MessageLookupByLibrary.simpleMessage("แผนที่"), "moderateStrength": MessageLookupByLibrary.simpleMessage("ปานกลาง"), "moveToAlbum": MessageLookupByLibrary.simpleMessage("ย้ายไปยังอัลบั้ม"), "name": MessageLookupByLibrary.simpleMessage("ชื่อ"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "newest": MessageLookupByLibrary.simpleMessage("ใหม่สุด"), "noRecoveryKey": MessageLookupByLibrary.simpleMessage("ไม่มีคีย์การกู้คืน?"), @@ -223,9 +220,6 @@ class MessageLookup extends MessageLookupByLibrary { "ok": MessageLookupByLibrary.simpleMessage("ตกลง"), "onEnte": MessageLookupByLibrary.simpleMessage( "บน ente"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), "oops": MessageLookupByLibrary.simpleMessage("อ๊ะ"), "oopsSomethingWentWrong": MessageLookupByLibrary.simpleMessage("อ๊ะ มีบางอย่างผิดพลาด"), @@ -236,7 +230,7 @@ class MessageLookup extends MessageLookupByLibrary { "password": MessageLookupByLibrary.simpleMessage("รหัสผ่าน"), "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage("เปลี่ยนรหัสผ่านสำเร็จ"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordWarning": MessageLookupByLibrary.simpleMessage( "เราไม่จัดเก็บรหัสผ่านนี้ ดังนั้นหากคุณลืม เราจะไม่สามารถถอดรหัสข้อมูลของคุณ"), "peopleUsingYourCode": @@ -304,13 +298,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "มีบางอย่างผิดพลาด โปรดลองอีกครั้ง"), "sorry": MessageLookupByLibrary.simpleMessage("ขออภัย"), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "status": MessageLookupByLibrary.simpleMessage("สถานะ"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("ครอบครัว"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("คุณ"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "strongStrength": MessageLookupByLibrary.simpleMessage("แข็งแรง"), "syncStopped": MessageLookupByLibrary.simpleMessage("หยุดการซิงค์แล้ว"), "syncing": MessageLookupByLibrary.simpleMessage("กำลังซิงค์..."), @@ -351,10 +343,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("ดูคีย์การกู้คืน"), "waitingForWifi": MessageLookupByLibrary.simpleMessage("กำลังรอ WiFi..."), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("อ่อน"), "welcomeBack": MessageLookupByLibrary.simpleMessage("ยินดีต้อนรับกลับมา!"), + "wishThemAHappyBirthday": m115, "you": MessageLookupByLibrary.simpleMessage("คุณ"), "youCanManageYourLinksInTheShareTab": MessageLookupByLibrary.simpleMessage( diff --git a/mobile/lib/generated/intl/messages_ti.dart b/mobile/lib/generated/intl/messages_ti.dart index 149fc223fd..a93a2e5b99 100644 --- a/mobile/lib/generated/intl/messages_ti.dart +++ b/mobile/lib/generated/intl/messages_ti.dart @@ -20,17 +20,9 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'ti'; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => { - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups") - }; + static Map _notInlinedMessages(_) => + {"wishThemAHappyBirthday": m115}; } diff --git a/mobile/lib/generated/intl/messages_tr.dart b/mobile/lib/generated/intl/messages_tr.dart index 8d2895c065..6b9ace83c6 100644 --- a/mobile/lib/generated/intl/messages_tr.dart +++ b/mobile/lib/generated/intl/messages_tr.dart @@ -83,244 +83,251 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'Delete ${count} item', other: 'Delete ${count} items')}"; - static String m22(currentlyDeleting, totalCount) => + static String m22(count) => + "Ayrıca bu ${count} albümde bulunan fotoğrafları (ve videoları) parçası oldukları tüm diğer albümlerden silmek istiyor musunuz?"; + + static String m23(currentlyDeleting, totalCount) => "Siliniyor ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "Bu, \"${albumName}\"e erişim için olan genel bağlantıyı kaldıracaktır."; - static String m24(supportEmail) => + static String m25(supportEmail) => "Lütfen kayıtlı e-posta adresinizden ${supportEmail} adresine bir e-posta gönderin"; - static String m25(count, storageSaved) => + static String m26(count, storageSaved) => "You have cleaned up ${Intl.plural(count, one: '${count} duplicate file', other: '${count} duplicate files')}, saving (${storageSaved}!)"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} dosyalar, ${formattedSize} her biri"; - static String m27(name) => "Bu e-posta zaten ${name} kişisine bağlı."; + static String m28(name) => "Bu e-posta zaten ${name} kişisine bağlı."; - static String m28(newEmail) => "E-posta ${newEmail} olarak değiştirildi"; + static String m29(newEmail) => "E-posta ${newEmail} olarak değiştirildi"; - static String m29(email) => "${email} bir Ente hesabına sahip değil"; + static String m30(email) => "${email} bir Ente hesabına sahip değil"; - static String m30(email) => + static String m31(email) => "${email}, Ente hesabı bulunmamaktadır.\n\nOnlarla fotoğraf paylaşımı için bir davet gönder."; - static String m31(name) => "${name}\'e sarılmak"; + static String m32(name) => "${name}\'e sarılmak"; - static String m32(text) => "${text} için ekstra fotoğraflar bulundu"; + static String m33(text) => "${text} için ekstra fotoğraflar bulundu"; - static String m33(name) => "${name} ile ziyafet"; - - static String m34(count, formattedNumber) => - "Bu cihazdaki ${Intl.plural(count, one: '1 file', other: '${formattedNumber} dosya')} güvenli bir şekilde yedeklendi"; + static String m34(name) => "${name} ile ziyafet"; static String m35(count, formattedNumber) => + "Bu cihazdaki ${Intl.plural(count, one: '1 file', other: '${formattedNumber} dosya')} güvenli bir şekilde yedeklendi"; + + static String m36(count, formattedNumber) => "Bu albümdeki ${Intl.plural(count, one: '1 file', other: '${formattedNumber} dosya')} güvenli bir şekilde yedeklendi"; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "Birisinin davet kodunuzu uygulayıp ücretli hesap açtığı her seferede ${storageAmountInGB} GB"; - static String m37(endDate) => "Ücretsiz deneme ${endDate} sona erir"; + static String m38(endDate) => "Ücretsiz deneme ${endDate} sona erir"; - static String m38(count) => + static String m39(count) => "Aktif bir aboneliğiniz olduğu sürece Ente üzerinden ${Intl.plural(count, one: 'ona', other: 'onlara')} hâlâ erişebilirsiniz"; - static String m39(sizeInMBorGB) => "${sizeInMBorGB} yer açın"; + static String m40(sizeInMBorGB) => "${sizeInMBorGB} yer açın"; - static String m40(count, formattedSize) => + static String m41(count, formattedSize) => "${Intl.plural(count, one: 'Cihazdan silinerek ${formattedSize} boşaltılabilir', other: 'Cihazdan silinerek ${formattedSize} boşaltılabilirler')}"; - static String m41(currentlyProcessing, totalCount) => + static String m42(currentlyProcessing, totalCount) => "Siliniyor ${currentlyProcessing} / ${totalCount}"; - static String m42(name) => "${name} ile doğa yürüyüşü"; + static String m43(name) => "${name} ile doğa yürüyüşü"; - static String m43(count) => + static String m44(count) => "${Intl.plural(count, one: '${count} öğe', other: '${count} öğeler')}"; - static String m44(name) => "${name} ile son an"; + static String m45(name) => "${name} ile son an"; - static String m45(email) => + static String m46(email) => "${email} sizi güvenilir bir kişi olmaya davet etti"; - static String m46(expiryTime) => + static String m47(expiryTime) => "Bu bağlantı ${expiryTime} tarihinden itibaren geçersiz olacaktır"; - static String m47(email) => "Kişiyi ${email} adresine bağlayın"; + static String m48(email) => "Kişiyi ${email} adresine bağlayın"; - static String m48(personName, email) => + static String m49(personName, email) => "Bu, ${personName} ile ${email} arasında bağlantı kuracaktır."; - static String m49(count, formattedCount) => - "${Intl.plural(count, zero: 'hiç anı yok', one: '${formattedCount} anı', other: '${formattedCount} anı')}"; + static String m50(count, formattedCount) => + "${Intl.plural(count, zero: 'hiç anı yok', other: '${formattedCount} anı')}"; - static String m50(count) => + static String m51(count) => "${Intl.plural(count, one: 'Öğeyi taşı', other: 'Öğeleri taşı')}"; - static String m51(albumName) => "${albumName} adlı albüme başarıyla taşındı"; + static String m52(albumName) => "${albumName} adlı albüme başarıyla taşındı"; - static String m52(personName) => "${personName} için öneri yok"; + static String m53(personName) => "${personName} için öneri yok"; - static String m53(name) => "${name} değil mi?"; + static String m54(name) => "${name} değil mi?"; - static String m54(familyAdminEmail) => + static String m55(familyAdminEmail) => "Kodunuzu değiştirmek için lütfen ${familyAdminEmail} ile iletişime geçin."; - static String m55(name) => "${name} ile parti"; + static String m56(name) => "${name} ile parti"; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Şifrenin güçlülük seviyesi: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "Sizden ücret alındıysa lütfen ${providerName} destek ekibiyle görüşün"; - static String m58(name, age) => "${name} ${age} yaşında!"; + static String m59(name, age) => "${name} ${age} yaşında!"; - static String m59(name, age) => "${name} yakında ${age} yaşına giriyor"; - - static String m60(count) => - "${Intl.plural(count, zero: 'Fotoğraf yok', one: '1 fotoğraf', other: '${count} fotoğraf')}"; + static String m60(name, age) => "${name} yakında ${age} yaşına giriyor"; static String m61(count) => + "${Intl.plural(count, zero: 'Fotoğraf yok', one: '1 fotoğraf', other: '${count} fotoğraf')}"; + + static String m62(count) => "${Intl.plural(count, zero: '0 fotoğraf', one: '1 fotoğraf', other: '${count} fotoğraf')}"; - static String m62(endDate) => + static String m63(endDate) => "Ücretsiz deneme süresi ${endDate} tarihine kadar geçerlidir.\nDaha sonra ücretli bir plan seçebilirsiniz."; - static String m63(toEmail) => "Lütfen bize ${toEmail} adresinden ulaşın"; + static String m64(toEmail) => "Lütfen bize ${toEmail} adresinden ulaşın"; - static String m64(toEmail) => + static String m65(toEmail) => "Lütfen kayıtları şu adrese gönderin\n${toEmail}"; - static String m65(name) => "${name} ile poz verme"; + static String m66(name) => "${name} ile poz verme"; - static String m66(folderName) => "İşleniyor ${folderName}..."; + static String m67(folderName) => "İşleniyor ${folderName}..."; - static String m67(storeName) => "Bizi ${storeName} üzerinden değerlendirin"; + static String m68(storeName) => "Bizi ${storeName} üzerinden değerlendirin"; - static String m68(name) => "Sizi ${name}\'e yeniden atadı"; + static String m69(name) => "Sizi ${name}\'e yeniden atadı"; - static String m69(days, email) => + static String m70(days, email) => "Hesabınıza ${days} gün sonra erişebilirsiniz. ${email} adresine bir bildirim gönderilecektir."; - static String m70(email) => + static String m71(email) => "Artık yeni bir parola belirleyerek ${email} hesabını kurtarabilirsiniz."; - static String m71(email) => "${email} hesabınızı kurtarmaya çalışıyor."; + static String m72(email) => "${email} hesabınızı kurtarmaya çalışıyor."; - static String m72(storageInGB) => "3. İkinizde bedava ${storageInGB} GB alın"; + static String m73(storageInGB) => "3. İkinizde bedava ${storageInGB} GB alın"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} bu paylaşılan albümden kaldırılacaktır\n\nOnlar tarafından eklenen tüm fotoğraflar da albümden kaldırılacaktır"; - static String m74(endDate) => "Abonelik ${endDate} tarihinde yenilenir"; + static String m75(endDate) => "Abonelik ${endDate} tarihinde yenilenir"; - static String m75(name) => "${name} ile yolculuk"; + static String m76(name) => "${name} ile yolculuk"; - static String m76(count) => - "${Intl.plural(count, one: '${count} yıl önce', other: '${count} yıl önce')}"; + static String m77(count) => + "${Intl.plural(count, other: '${count} yıl önce')}"; - static String m77(snapshotLength, searchLength) => + static String m78(snapshotLength, searchLength) => "Bölüm uzunluğu uyuşmazlığı: ${snapshotLength} != ${searchLength}"; - static String m78(count) => "${count} seçildi"; + static String m79(count) => "${count} seçildi"; - static String m79(count, yourCount) => + static String m80(count) => "${count} seçildi"; + + static String m81(count, yourCount) => "Seçilenler: ${count} (${yourCount} sizin seçiminiz)"; - static String m80(name) => "${name} ile selfieler"; + static String m82(name) => "${name} ile selfieler"; - static String m81(verificationID) => + static String m83(verificationID) => "İşte ente.io için doğrulama kimliğim: ${verificationID}."; - static String m82(verificationID) => + static String m84(verificationID) => "Merhaba, bu ente.io doğrulama kimliğinizin doğruluğunu onaylayabilir misiniz: ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Ente davet kodu: ${referralCode} \n\nÜcretli hesaba başvurduktan sonra ${referralStorageInGB} GB bedava almak için \nAyarlar → Genel → Davetlerde bu kodu girin\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Belirli kişilerle paylaş', one: '1 kişiyle paylaşıldı', other: '${numberOfPeople} kişiyle paylaşıldı')}"; - static String m85(emailIDs) => "${emailIDs} ile paylaşıldı"; + static String m87(emailIDs) => "${emailIDs} ile paylaşıldı"; - static String m86(fileType) => "Bu ${fileType}, cihazınızdan silinecek."; + static String m88(fileType) => "Bu ${fileType}, cihazınızdan silinecek."; - static String m87(fileType) => + static String m89(fileType) => "${fileType} Ente ve cihazınızdan silinecektir."; - static String m88(fileType) => "${fileType} Ente\'den silinecektir."; + static String m90(fileType) => "${fileType} Ente\'den silinecektir."; - static String m89(name) => "${name} ile spor"; + static String m91(name) => "${name} ile spor"; - static String m90(name) => "Sahne ${name}\'in"; + static String m92(name) => "Sahne ${name}\'in"; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} / ${totalAmount} ${totalStorageUnit} kullanıldı"; - static String m93(id) => + static String m95(id) => "${id}\'niz zaten başka bir ente hesabına bağlı.\n${id} numaranızı bu hesapla kullanmak istiyorsanız lütfen desteğimizle iletişime geçin\'\'"; - static String m94(endDate) => + static String m96(endDate) => "Aboneliğiniz ${endDate} tarihinde iptal edilecektir"; - static String m95(completed, total) => "${completed}/${total} anı korundu"; + static String m97(completed, total) => "${completed}/${total} anı korundu"; - static String m96(ignoreReason) => + static String m98(ignoreReason) => "Yüklemek için dokunun, yükleme şu anda ${ignoreReason} nedeniyle yok sayılıyor"; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "Aynı zamanda ${storageAmountInGB} GB alıyorlar"; - static String m98(email) => "Bu, ${email}\'in Doğrulama Kimliği"; - - static String m99(count) => - "${Intl.plural(count, one: 'Bu hafta, ${count} yıl önce', other: 'Bu hafta, ${count} yıl önce')}"; - - static String m100(dateFormat) => "${dateFormat} yıllar boyunca"; + static String m100(email) => "Bu, ${email}\'in Doğrulama Kimliği"; static String m101(count) => + "${Intl.plural(count, one: 'Bu hafta, ${count} yıl önce', other: 'Bu hafta, ${count} yıl önce')}"; + + static String m102(dateFormat) => "${dateFormat} yıllar boyunca"; + + static String m103(count) => "${Intl.plural(count, zero: 'Yakında', one: '1 gün', other: '${count} gün')}"; - static String m102(year) => "${year} yılındaki gezi"; + static String m104(year) => "${year} yılındaki gezi"; - static String m103(location) => "${location}\'a gezi"; + static String m105(location) => "${location}\'a gezi"; - static String m104(email) => + static String m106(email) => "${email} ile eski bir irtibat kişisi olmaya davet edildiniz."; - static String m105(galleryType) => + static String m107(galleryType) => "Galeri türü ${galleryType} yeniden adlandırma için desteklenmiyor"; - static String m106(ignoreReason) => + static String m108(ignoreReason) => "Yükleme ${ignoreReason} nedeniyle yok sayıldı"; - static String m107(count) => "${count} anı korunuyor..."; + static String m109(count) => "${count} anı korunuyor..."; - static String m108(endDate) => "${endDate} tarihine kadar geçerli"; + static String m110(endDate) => "${endDate} tarihine kadar geçerli"; - static String m109(email) => "${email} doğrula"; + static String m111(email) => "${email} doğrula"; - static String m110(name) => + static String m112(name) => "Bağlantıyı kaldırmak için ${name} kişisini görüntüle"; - static String m111(count) => + static String m113(count) => "${Intl.plural(count, zero: '0 izleyici eklendi', one: '1 izleyici eklendi', other: '${count} izleyici eklendi')}"; - static String m112(email) => + static String m114(email) => "E-postayı ${email} adresine gönderdik"; - static String m113(count) => - "${Intl.plural(count, one: '${count} yıl önce', other: '${count} yıl önce')}"; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; - static String m114(name) => "Sen ve ${name}"; + static String m116(count) => + "${Intl.plural(count, other: '${count} yıl önce')}"; - static String m115(storageSaved) => + static String m117(name) => "Sen ve ${name}"; + + static String m118(storageSaved) => "Başarılı bir şekilde ${storageSaved} alanını boşalttınız!"; final messages = _notInlinedMessages(_notInlinedMessages); @@ -338,6 +345,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Tekrar hoş geldiniz!"), "ackPasswordLostWarning": MessageLookupByLibrary.simpleMessage( "Şifremi kaybedersem, verilerim uçtan uca şifrelendiği için verilerimi kaybedebileceğimi farkındayım."), + "actionNotSupportedOnFavouritesAlbum": + MessageLookupByLibrary.simpleMessage( + "Favoriler albümünde eylem desteklenmiyor"), "activeSessions": MessageLookupByLibrary.simpleMessage("Aktif oturumlar"), "add": MessageLookupByLibrary.simpleMessage("Ekle"), @@ -362,6 +372,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Eklentilerin ayrıntıları"), "addOnValidTill": m3, "addOns": MessageLookupByLibrary.simpleMessage("Eklentiler"), + "addParticipants": + MessageLookupByLibrary.simpleMessage("Katılımcı ekle"), "addPhotos": MessageLookupByLibrary.simpleMessage("Fotoğraf ekle"), "addSelected": MessageLookupByLibrary.simpleMessage("Seçileni ekle"), "addToAlbum": MessageLookupByLibrary.simpleMessage("Albüme ekle"), @@ -618,8 +630,6 @@ class MessageLookup extends MessageLookupByLibrary { "click": MessageLookupByLibrary.simpleMessage("• Tıklamak"), "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage("• Taşma menüsüne tıklayın"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "close": MessageLookupByLibrary.simpleMessage("Kapat"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage( "Yakalama zamanına göre kulüp"), @@ -765,9 +775,10 @@ class MessageLookup extends MessageLookupByLibrary { "deleteFromEnte": MessageLookupByLibrary.simpleMessage("Ente\'den Sil"), "deleteItemCount": m21, "deleteLocation": MessageLookupByLibrary.simpleMessage("Konumu sil"), + "deleteMultipleAlbumDialog": m22, "deletePhotos": MessageLookupByLibrary.simpleMessage("Fotoğrafları sil"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "İhtiyacım olan önemli bir özellik eksik"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -806,7 +817,7 @@ class MessageLookup extends MessageLookupByLibrary { "Görüntüleyiciler, hala harici araçlar kullanarak ekran görüntüsü alabilir veya fotoğraflarınızın bir kopyasını kaydedebilir. Lütfen bunu göz önünde bulundurunuz"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Lütfen dikkate alın"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "İki Aşamalı Doğrulamayı Devre Dışı Bırak"), "disablingTwofactorAuthentication": @@ -849,11 +860,11 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("İndirme başarısız"), "downloading": MessageLookupByLibrary.simpleMessage("İndiriliyor..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("Düzenle"), - "editEmailAlreadyLinked": m27, + "editEmailAlreadyLinked": m28, "editLocation": MessageLookupByLibrary.simpleMessage("Konumu düzenle"), "editLocationTagTitle": MessageLookupByLibrary.simpleMessage("Konumu düzenle"), @@ -868,16 +879,16 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("E-Posta"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage( "Bu e-posta adresi zaten kayıtlı."), - "emailChangedTo": m28, - "emailDoesNotHaveEnteAccount": m29, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailDoesNotHaveEnteAccount": m30, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage( "Bu e-posta adresi sistemde kayıtlı değil."), "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("E-posta doğrulama"), "emailYourLogs": MessageLookupByLibrary.simpleMessage( "Kayıtlarınızı e-postayla gönderin"), - "embracingThem": m31, + "embracingThem": m32, "emergencyContacts": MessageLookupByLibrary.simpleMessage( "Acil Durum İletişim Bilgileri"), "empty": MessageLookupByLibrary.simpleMessage("Boşalt"), @@ -941,6 +952,8 @@ class MessageLookup extends MessageLookupByLibrary { "Lütfen geçerli bir E-posta adresi girin."), "enterYourEmailAddress": MessageLookupByLibrary.simpleMessage("E-posta adresinizi girin"), + "enterYourNewEmailAddress": MessageLookupByLibrary.simpleMessage( + "Yeni e-posta adresinizi girin"), "enterYourPassword": MessageLookupByLibrary.simpleMessage("Lütfen şifrenizi giriniz"), "enterYourRecoveryKey": @@ -958,7 +971,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Veriyi dışarı aktar"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage("Ekstra fotoğraflar bulundu"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage( "Yüz henüz kümelenmedi, lütfen daha sonra tekrar gelin"), "faceRecognition": MessageLookupByLibrary.simpleMessage("Yüz Tanıma"), @@ -993,7 +1006,7 @@ class MessageLookup extends MessageLookupByLibrary { "faq": MessageLookupByLibrary.simpleMessage("Sık sorulan sorular"), "faqs": MessageLookupByLibrary.simpleMessage("Sık Sorulan Sorular"), "favorite": MessageLookupByLibrary.simpleMessage("Favori"), - "feastingWithThem": m33, + "feastingWithThem": m34, "feedback": MessageLookupByLibrary.simpleMessage("Geri Bildirim"), "file": MessageLookupByLibrary.simpleMessage("Dosya"), "fileFailedToSaveToGallery": MessageLookupByLibrary.simpleMessage( @@ -1007,8 +1020,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Dosya türü"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Dosya türleri ve adları"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("Dosyalar silinmiş"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage( @@ -1020,32 +1033,32 @@ class MessageLookup extends MessageLookupByLibrary { "flip": MessageLookupByLibrary.simpleMessage("Çevir"), "food": MessageLookupByLibrary.simpleMessage("Yemek keyfi"), "forYourMemories": - MessageLookupByLibrary.simpleMessage("anıların için"), + MessageLookupByLibrary.simpleMessage("anılarınız için"), "forgotPassword": MessageLookupByLibrary.simpleMessage("Şifremi unuttum"), "foundFaces": MessageLookupByLibrary.simpleMessage("Yüzler bulundu"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("Alınan bedava alan"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("Kullanılabilir bedava alan"), "freeTrial": MessageLookupByLibrary.simpleMessage("Ücretsiz deneme"), - "freeTrialValidTill": m37, - "freeUpAccessPostDelete": m38, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAccessPostDelete": m39, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("Cihaz alanını boşaltın"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Zaten yedeklenmiş dosyaları temizleyerek cihazınızda yer kazanın."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Boş alan"), - "freeUpSpaceSaving": m40, + "freeUpSpaceSaving": m41, "gallery": MessageLookupByLibrary.simpleMessage("Galeri"), "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Galeride 1000\'e kadar anı gösterilir"), "general": MessageLookupByLibrary.simpleMessage("Genel"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Şifreleme anahtarı oluşturuluyor..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("Ayarlara git"), "googlePlayId": MessageLookupByLibrary.simpleMessage("Google Play ID"), "grantFullAccessPrompt": MessageLookupByLibrary.simpleMessage( @@ -1073,7 +1086,7 @@ class MessageLookup extends MessageLookupByLibrary { "hideSharedItemsFromHomeGallery": MessageLookupByLibrary.simpleMessage( "Paylaşılan öğeleri ana galeriden gizle"), "hiding": MessageLookupByLibrary.simpleMessage("Gizleniyor..."), - "hikingWithThem": m42, + "hikingWithThem": m43, "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("OSM Fransa\'da ağırlandı"), "howItWorks": MessageLookupByLibrary.simpleMessage("Nasıl çalışır"), @@ -1131,7 +1144,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Bir şeyler ters gitmiş gibi görünüyor. Lütfen bir süre sonra tekrar deneyin. Hata devam ederse, lütfen destek ekibimizle iletişime geçin."), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Öğeler kalıcı olarak silinmeden önce kalan gün sayısını gösterir"), @@ -1152,7 +1165,7 @@ class MessageLookup extends MessageLookupByLibrary { "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( "Lütfen bu bilgilerle bize yardımcı olun"), "language": MessageLookupByLibrary.simpleMessage("Dil"), - "lastTimeWithThem": m44, + "lastTimeWithThem": m45, "lastUpdated": MessageLookupByLibrary.simpleMessage("En son güncellenen"), "lastYearsTrip": @@ -1168,7 +1181,7 @@ class MessageLookup extends MessageLookupByLibrary { "legacy": MessageLookupByLibrary.simpleMessage("Geleneksel"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("Geleneksel hesaplar"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage( "Geleneksel yol, güvendiğiniz kişilerin yokluğunuzda hesabınıza erişmesine olanak tanır."), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( @@ -1184,7 +1197,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("daha hızlı paylaşım için"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Geçerli"), "linkExpired": MessageLookupByLibrary.simpleMessage("Süresi dolmuş"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Bağlantı geçerliliği"), "linkHasExpired": @@ -1193,8 +1206,8 @@ class MessageLookup extends MessageLookupByLibrary { "linkPerson": MessageLookupByLibrary.simpleMessage("Kişiyi bağla"), "linkPersonCaption": MessageLookupByLibrary.simpleMessage( "daha iyi paylaşım deneyimi için"), - "linkPersonToEmail": m47, - "linkPersonToEmailConfirmation": m48, + "linkPersonToEmail": m48, + "linkPersonToEmailConfirmation": m49, "livePhotos": MessageLookupByLibrary.simpleMessage("Canlı Fotoğraf"), "loadMessage1": MessageLookupByLibrary.simpleMessage( "Aboneliğinizi ailenizle paylaşabilirsiniz"), @@ -1256,8 +1269,6 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Tam ekranda görüntülemek için bir öğeye uzun basın"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "loopVideoOff": MessageLookupByLibrary.simpleMessage("Video Döngüsü Kapalı"), "loopVideoOn": @@ -1286,7 +1297,7 @@ class MessageLookup extends MessageLookupByLibrary { "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), "me": MessageLookupByLibrary.simpleMessage("Ben"), - "memoryCount": m49, + "memoryCount": m50, "merchandise": MessageLookupByLibrary.simpleMessage("Ürünler"), "mergeWithExisting": MessageLookupByLibrary.simpleMessage("Var olan ile birleştir."), @@ -1318,13 +1329,13 @@ class MessageLookup extends MessageLookupByLibrary { "mostRecent": MessageLookupByLibrary.simpleMessage("En son"), "mostRelevant": MessageLookupByLibrary.simpleMessage("En alakalı"), "mountains": MessageLookupByLibrary.simpleMessage("Tepelerin ötesinde"), - "moveItem": m50, + "moveItem": m51, "moveSelectedPhotosToOneDate": MessageLookupByLibrary.simpleMessage( "Seçilen fotoğrafları bir tarihe taşıma"), "moveToAlbum": MessageLookupByLibrary.simpleMessage("Albüme taşı"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Gizli albüme ekle"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("Cöp kutusuna taşı"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1339,7 +1350,6 @@ class MessageLookup extends MessageLookupByLibrary { "newAlbum": MessageLookupByLibrary.simpleMessage("Yeni albüm"), "newLocation": MessageLookupByLibrary.simpleMessage("Yeni konum"), "newPerson": MessageLookupByLibrary.simpleMessage("Yeni Kişi"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "newRange": MessageLookupByLibrary.simpleMessage("Yeni aralık"), "newToEnte": MessageLookupByLibrary.simpleMessage("Ente\'de yeniyim"), "newest": MessageLookupByLibrary.simpleMessage("En yeni"), @@ -1378,10 +1388,10 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Sonuç bulunamadı"), "noResultsFound": MessageLookupByLibrary.simpleMessage("Hiçbir sonuç bulunamadı"), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage("Sistem kilidi bulunamadı"), - "notPersonLabel": m53, + "notPersonLabel": m54, "notThisPerson": MessageLookupByLibrary.simpleMessage("Bu kişi değil mi?"), "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( @@ -1394,10 +1404,8 @@ class MessageLookup extends MessageLookupByLibrary { "onEnte": MessageLookupByLibrary.simpleMessage( "ente üzerinde"), "onTheRoad": MessageLookupByLibrary.simpleMessage("Yeniden yollarda"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "onThisDay": MessageLookupByLibrary.simpleMessage("Bu günde"), + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("Sadece onlar"), "oops": MessageLookupByLibrary.simpleMessage("Hay aksi"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( @@ -1427,7 +1435,7 @@ class MessageLookup extends MessageLookupByLibrary { "pairingComplete": MessageLookupByLibrary.simpleMessage("Eşleştirme tamamlandı"), "panorama": MessageLookupByLibrary.simpleMessage("Panorama"), - "partyWithThem": m55, + "partyWithThem": m56, "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage("Doğrulama hala bekliyor"), "passkey": MessageLookupByLibrary.simpleMessage("Geçiş anahtarı"), @@ -1437,7 +1445,7 @@ class MessageLookup extends MessageLookupByLibrary { "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage( "Şifreniz başarılı bir şekilde değiştirildi"), "passwordLock": MessageLookupByLibrary.simpleMessage("Şifre kilidi"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "Parola gücü, parolanın uzunluğu, kullanılan karakterler ve parolanın en çok kullanılan ilk 10.000 parola arasında yer alıp almadığı dikkate alınarak hesaplanır"), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -1448,7 +1456,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ödeme başarısız oldu"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Maalesef ödemeniz başarısız oldu. Lütfen destekle iletişime geçin, size yardımcı olacağız!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("Bekleyen Öğeler"), "pendingSync": MessageLookupByLibrary.simpleMessage("Bekleyen Senkronizasyonlar"), @@ -1461,20 +1469,20 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Kalıcı olarak sil"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage( "Cihazdan kalıcı olarak silinsin mi?"), - "personIsAge": m58, + "personIsAge": m59, "personName": MessageLookupByLibrary.simpleMessage("Kişi Adı"), - "personTurningAge": m59, + "personTurningAge": m60, "pets": MessageLookupByLibrary.simpleMessage("Tüylü dostlar"), "photoDescriptions": MessageLookupByLibrary.simpleMessage("Fotoğraf Açıklaması"), "photoGridSize": MessageLookupByLibrary.simpleMessage("Izgara boyutu"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("fotoğraf"), - "photocountPhotos": m60, + "photocountPhotos": m61, "photos": MessageLookupByLibrary.simpleMessage("Fotoğraflar"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage( "Eklediğiniz fotoğraflar albümden kaldırılacak"), - "photosCount": m61, + "photosCount": m62, "photosKeepRelativeTimeDifference": MessageLookupByLibrary.simpleMessage( "Fotoğraflar göreli zaman farkını korur"), @@ -1484,7 +1492,7 @@ class MessageLookup extends MessageLookupByLibrary { "pinLock": MessageLookupByLibrary.simpleMessage("Pin kilidi"), "playOnTv": MessageLookupByLibrary.simpleMessage("Albümü TV\'de oynat"), "playOriginal": MessageLookupByLibrary.simpleMessage("Orijinali oynat"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playStream": MessageLookupByLibrary.simpleMessage("Akışı oynat"), "playstoreSubscription": MessageLookupByLibrary.simpleMessage("PlayStore aboneliği"), @@ -1497,14 +1505,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Bu hata devam ederse lütfen desteğe başvurun"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage("Lütfen izin ver"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Lütfen tekrar giriş yapın"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Lütfen kaldırmak için hızlı bağlantıları seçin"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Lütfen tekrar deneyiniz"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1519,7 +1527,7 @@ class MessageLookup extends MessageLookupByLibrary { "Tekrar denemeden önce lütfen bir süre bekleyin"), "pleaseWaitThisWillTakeAWhile": MessageLookupByLibrary.simpleMessage( "Lütfen bekleyin, bu biraz zaman alabilir."), - "posingWithThem": m65, + "posingWithThem": m66, "preparingLogs": MessageLookupByLibrary.simpleMessage("Kayıtlar hazırlanıyor..."), "preserveMore": @@ -1538,7 +1546,7 @@ class MessageLookup extends MessageLookupByLibrary { "proceed": MessageLookupByLibrary.simpleMessage("Devam edin"), "processed": MessageLookupByLibrary.simpleMessage("İşlenen"), "processing": MessageLookupByLibrary.simpleMessage("İşleniyor"), - "processingImport": m66, + "processingImport": m67, "processingVideos": MessageLookupByLibrary.simpleMessage("Videolar işleniyor"), "publicLinkCreated": MessageLookupByLibrary.simpleMessage( @@ -1552,10 +1560,10 @@ class MessageLookup extends MessageLookupByLibrary { "rateTheApp": MessageLookupByLibrary.simpleMessage("Uygulamayı puanlayın"), "rateUs": MessageLookupByLibrary.simpleMessage("Bizi değerlendirin"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "reassignMe": MessageLookupByLibrary.simpleMessage("\"Ben\"i yeniden atayın"), - "reassignedToName": m68, + "reassignedToName": m69, "reassigningLoading": MessageLookupByLibrary.simpleMessage("Yeniden atanıyor..."), "recover": MessageLookupByLibrary.simpleMessage("Kurtarma"), @@ -1565,7 +1573,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Hesabı kurtar"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage("Kurtarma başlatıldı"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("Kurtarma anahtarı"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( @@ -1580,12 +1588,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Kurtarma kodu doğrulandı"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "Kurtarma anahtarınız, şifrenizi unutmanız durumunda fotoğraflarınızı kurtarmanın tek yoludur. Kurtarma anahtarınızı Ayarlar > Hesap bölümünde bulabilirsiniz.\n\nDoğru kaydettiğinizi doğrulamak için lütfen kurtarma anahtarınızı buraya girin."), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage("Kurtarma başarılı!"), "recoveryWarning": MessageLookupByLibrary.simpleMessage( "Güvenilir bir kişi hesabınıza erişmeye çalışıyor"), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "Cihazınız, şifrenizi doğrulamak için yeterli güce sahip değil, ancak tüm cihazlarda çalışacak şekilde yeniden oluşturabiliriz.\n\nLütfen kurtarma anahtarınızı kullanarak giriş yapın ve şifrenizi yeniden oluşturun (istediğiniz takdirde aynı şifreyi tekrar kullanabilirsiniz)."), "recreatePasswordTitle": MessageLookupByLibrary.simpleMessage( @@ -1601,7 +1609,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Bu kodu arkadaşlarınıza verin"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Ücretli bir plan için kaydolsunlar"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("Arkadaşını davet et"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( @@ -1632,7 +1640,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Bağlantıyı kaldır"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Katılımcıyı kaldır"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Kişi etiketini kaldırın"), "removePublicLink": MessageLookupByLibrary.simpleMessage( @@ -1642,7 +1650,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeShareItemsWarning": MessageLookupByLibrary.simpleMessage( "Kaldırdığınız öğelerden bazıları başkaları tarafından eklenmiştir ve bunlara erişiminizi kaybedeceksiniz"), "removeWithQuestionMark": - MessageLookupByLibrary.simpleMessage("Kaldır?"), + MessageLookupByLibrary.simpleMessage("Kaldırılsın mı?"), "removeYourselfAsTrustedContact": MessageLookupByLibrary.simpleMessage( "Kendinizi güvenilir kişi olarak kaldırın"), "removingFromFavorites": @@ -1654,7 +1662,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Dosyayı yeniden adlandır"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Abonelik yenileme"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Hata bildir"), "reportBug": MessageLookupByLibrary.simpleMessage("Hata bildir"), "resendEmail": @@ -1679,7 +1687,7 @@ class MessageLookup extends MessageLookupByLibrary { "reviewSuggestions": MessageLookupByLibrary.simpleMessage("Önerileri inceleyin"), "right": MessageLookupByLibrary.simpleMessage("Sağ"), - "roadtripWithThem": m75, + "roadtripWithThem": m76, "rotate": MessageLookupByLibrary.simpleMessage("Döndür"), "rotateLeft": MessageLookupByLibrary.simpleMessage("Sola döndür"), "rotateRight": MessageLookupByLibrary.simpleMessage("Sağa döndür"), @@ -1735,8 +1743,8 @@ class MessageLookup extends MessageLookupByLibrary { "İnsanları davet ettiğinizde onların paylaştığı tüm fotoğrafları burada göreceksiniz"), "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage( "İşleme ve senkronizasyon tamamlandığında kişiler burada gösterilecektir"), - "searchResultCount": m76, - "searchSectionsLengthMismatch": m77, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("Güvenlik"), "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage( "Uygulamadaki herkese açık albüm bağlantılarını görün"), @@ -1774,6 +1782,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Yüzünüzü seçin"), "selectYourPlan": MessageLookupByLibrary.simpleMessage("Planınızı seçin"), + "selectedAlbums": m79, "selectedFilesAreNotOnEnte": MessageLookupByLibrary.simpleMessage( "Seçilen dosyalar Ente\'de değil"), "selectedFoldersWillBeEncryptedAndBackedUp": @@ -1785,9 +1794,9 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeRemovedFromThisPerson": MessageLookupByLibrary.simpleMessage( "Seçili öğeler bu kişiden silinir, ancak kitaplığınızdan silinmez."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, - "selfiesWithThem": m80, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, + "selfiesWithThem": m82, "send": MessageLookupByLibrary.simpleMessage("Gönder"), "sendEmail": MessageLookupByLibrary.simpleMessage("E-posta gönder"), "sendInvite": MessageLookupByLibrary.simpleMessage("Davet kodu gönder"), @@ -1819,16 +1828,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Şimdi bir albüm paylaşın"), "shareLink": MessageLookupByLibrary.simpleMessage("Bağlantıyı paylaş"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Yalnızca istediğiniz kişilerle paylaşın"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Orijinal kalitede fotoğraf ve videoları kolayca paylaşabilmemiz için Ente\'yi indirin\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Ente kullanıcısı olmayanlar için paylaş"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage("İlk albümünüzü paylaşın"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1840,7 +1849,7 @@ class MessageLookup extends MessageLookupByLibrary { "Paylaşılan fotoğrafları ekle"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "Birisi parçası olduğunuz paylaşılan bir albüme fotoğraf eklediğinde bildirim alın"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Benimle paylaşılan"), "sharedWithYou": @@ -1858,11 +1867,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Diğer cihazlardan çıkış yap"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Hizmet Şartları\'nı ve Gizlilik Politikası\'nı kabul ediyorum"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage("Tüm albümlerden silinecek."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("Geç"), "social": MessageLookupByLibrary.simpleMessage("Sosyal Medya"), "someItemsAreInBothEnteAndYourDevice": @@ -1893,16 +1902,14 @@ class MessageLookup extends MessageLookupByLibrary { "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "Üzgünüm, bu cihazda güvenli anahtarlarını oluşturamadık.\n\nLütfen başka bir cihazdan giriş yapmayı deneyiniz."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "sort": MessageLookupByLibrary.simpleMessage("Sırala"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Sırala"), "sortNewestFirst": MessageLookupByLibrary.simpleMessage("Yeniden eskiye"), "sortOldestFirst": MessageLookupByLibrary.simpleMessage("Önce en eski"), "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ Başarılı"), - "sportsWithThem": m89, - "spotlightOnThem": m90, + "sportsWithThem": m91, + "spotlightOnThem": m92, "spotlightOnYourself": MessageLookupByLibrary.simpleMessage("Sahne senin"), "startAccountRecoveryTitle": @@ -1917,14 +1924,14 @@ class MessageLookup extends MessageLookupByLibrary { "storage": MessageLookupByLibrary.simpleMessage("Depolama"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Aile"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Sen"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage("Depolama sınırı aşıldı"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "streamDetails": MessageLookupByLibrary.simpleMessage("Akış detayları"), "strongStrength": MessageLookupByLibrary.simpleMessage("Güçlü"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("Abone ol"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "Paylaşımı etkinleştirmek için aktif bir ücretli aboneliğe ihtiyacınız var."), @@ -1942,7 +1949,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Özellik önerin"), "sunrise": MessageLookupByLibrary.simpleMessage("Ufukta"), "support": MessageLookupByLibrary.simpleMessage("Destek"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("Senkronizasyon durduruldu"), "syncing": MessageLookupByLibrary.simpleMessage("Eşitleniyor..."), @@ -1954,7 +1961,7 @@ class MessageLookup extends MessageLookupByLibrary { "tapToUnlock": MessageLookupByLibrary.simpleMessage("Açmak için dokun"), "tapToUpload": MessageLookupByLibrary.simpleMessage("Yüklemek için tıklayın"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Bir şeyler ters gitmiş gibi görünüyor. Lütfen bir süre sonra tekrar deneyin. Hata devam ederse, lütfen destek ekibimizle iletişime geçin."), "terminate": MessageLookupByLibrary.simpleMessage("Sonlandır"), @@ -1977,7 +1984,7 @@ class MessageLookup extends MessageLookupByLibrary { "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage( "Bu öğeler cihazınızdan silinecektir."), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage("Tüm albümlerden silinecek."), "thisActionCannotBeUndone": @@ -1995,12 +2002,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Bu görselde exif verisi yok"), "thisIsMeExclamation": MessageLookupByLibrary.simpleMessage("Bu benim!"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage("Doğrulama kimliğiniz"), "thisWeekThroughTheYears": MessageLookupByLibrary.simpleMessage("Yıllar boyunca bu hafta"), - "thisWeekXYearsAgo": m99, + "thisWeekXYearsAgo": m101, "thisWillLogYouOutOfTheFollowingDevice": MessageLookupByLibrary.simpleMessage( "Bu, sizi aşağıdaki cihazdan çıkış yapacak:"), @@ -2012,7 +2019,7 @@ class MessageLookup extends MessageLookupByLibrary { "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( "Bu, seçilen tüm hızlı bağlantıların genel bağlantılarını kaldıracaktır."), - "throughTheYears": m100, + "throughTheYears": m102, "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": MessageLookupByLibrary.simpleMessage( "Uygulama kilidini etkinleştirmek için lütfen sistem ayarlarınızda cihaz şifresi veya ekran kilidi ayarlayın."), @@ -2026,13 +2033,13 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("total"), "totalSize": MessageLookupByLibrary.simpleMessage("Toplam boyut"), "trash": MessageLookupByLibrary.simpleMessage("Cöp kutusu"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("Kes"), - "tripInYear": m102, - "tripToLocation": m103, + "tripInYear": m104, + "tripToLocation": m105, "trustedContacts": MessageLookupByLibrary.simpleMessage("Güvenilir kişiler"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("Tekrar deneyiniz"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "Bu cihaz klasörüne eklenen dosyaları otomatik olarak ente\'ye yüklemek için yedeklemeyi açın."), @@ -2051,7 +2058,7 @@ class MessageLookup extends MessageLookupByLibrary { "İki faktörlü kimlik doğrulama başarıyla sıfırlandı"), "twofactorSetup": MessageLookupByLibrary.simpleMessage("İki faktörlü kurulum"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("Arşivden cıkar"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("Arşivden Çıkar"), @@ -2076,10 +2083,10 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage( "Klasör seçimi güncelleniyor..."), "upgrade": MessageLookupByLibrary.simpleMessage("Yükselt"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Dosyalar albüme taşınıyor..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage("1 anı korunuyor..."), "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( @@ -2098,7 +2105,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("Seçilen fotoğrafı kullan"), "usedSpace": MessageLookupByLibrary.simpleMessage("Kullanılan alan"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Doğrulama başarısız oldu, lütfen tekrar deneyin"), @@ -2107,7 +2114,7 @@ class MessageLookup extends MessageLookupByLibrary { "verify": MessageLookupByLibrary.simpleMessage("Doğrula"), "verifyEmail": MessageLookupByLibrary.simpleMessage("E-posta adresini doğrulayın"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Doğrula"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("Şifrenizi doğrulayın"), @@ -2133,11 +2140,11 @@ class MessageLookup extends MessageLookupByLibrary { "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( "En fazla depolama alanı kullanan dosyaları görüntüleyin."), "viewLogs": MessageLookupByLibrary.simpleMessage("Kayıtları görüntüle"), - "viewPersonToUnlink": m110, + "viewPersonToUnlink": m112, "viewRecoveryKey": MessageLookupByLibrary.simpleMessage( "Kurtarma anahtarını görüntüle"), "viewer": MessageLookupByLibrary.simpleMessage("Görüntüleyici"), - "viewersSuccessfullyAdded": m111, + "viewersSuccessfullyAdded": m113, "visitWebToManage": MessageLookupByLibrary.simpleMessage( "Aboneliğinizi yönetmek için lütfen web.ente.io adresini ziyaret edin"), "waitingForVerification": @@ -2150,15 +2157,16 @@ class MessageLookup extends MessageLookupByLibrary { "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "Henüz sahibi olmadığınız fotoğraf ve albümlerin düzenlenmesini desteklemiyoruz"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Zayıf"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Tekrardan hoşgeldin!"), "whatsNew": MessageLookupByLibrary.simpleMessage("Yenilikler"), "whyAddTrustContact": MessageLookupByLibrary.simpleMessage("."), + "wishThemAHappyBirthday": m115, "yearShort": MessageLookupByLibrary.simpleMessage("yıl"), "yearly": MessageLookupByLibrary.simpleMessage("Yıllık"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Evet"), "yesCancel": MessageLookupByLibrary.simpleMessage("Evet, iptal et"), "yesConvertToViewer": MessageLookupByLibrary.simpleMessage( @@ -2173,7 +2181,7 @@ class MessageLookup extends MessageLookupByLibrary { "yesResetPerson": MessageLookupByLibrary.simpleMessage("Evet, kişiyi sıfırla"), "you": MessageLookupByLibrary.simpleMessage("Sen"), - "youAndThem": m114, + "youAndThem": m117, "youAreOnAFamilyPlan": MessageLookupByLibrary.simpleMessage("Aile planı kullanıyorsunuz!"), "youAreOnTheLatestVersion": @@ -2192,7 +2200,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Kendinizle paylaşamazsınız"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage("Arşivlenmiş öğeniz yok."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("Hesabınız silindi"), "yourMap": MessageLookupByLibrary.simpleMessage("Haritalarınız"), @@ -2200,7 +2208,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Planınız başarıyla düşürüldü"), "yourPlanWasSuccessfullyUpgraded": MessageLookupByLibrary.simpleMessage( - "Planınız başarılı şekilde yükseltildi"), + "Planınız başarıyla yükseltildi"), "yourPurchaseWasSuccessful": MessageLookupByLibrary.simpleMessage("Satın alım başarılı"), "yourStorageDetailsCouldNotBeFetched": diff --git a/mobile/lib/generated/intl/messages_uk.dart b/mobile/lib/generated/intl/messages_uk.dart index 7309bf269b..e306a5aadc 100644 --- a/mobile/lib/generated/intl/messages_uk.dart +++ b/mobile/lib/generated/intl/messages_uk.dart @@ -65,171 +65,173 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'Видалено ${count} елемент', other: 'Видалено ${count} елементів')}"; - static String m22(currentlyDeleting, totalCount) => + static String m23(currentlyDeleting, totalCount) => "Видалення ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "Це видалить публічне посилання для доступу до «${albumName}»."; - static String m24(supportEmail) => + static String m25(supportEmail) => "Надішліть листа на ${supportEmail} з вашої зареєстрованої поштової адреси"; - static String m25(count, storageSaved) => + static String m26(count, storageSaved) => "Ви очистили ${Intl.plural(count, one: '${count} дублікат файлу', other: '${count} дублікатів файлів')}, збережено (${storageSaved}!)"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} файлів, кожен по ${formattedSize}"; - static String m28(newEmail) => "Поштову адресу змінено на ${newEmail}"; + static String m29(newEmail) => "Поштову адресу змінено на ${newEmail}"; - static String m30(email) => + static String m31(email) => "У ${email} немає облікового запису Ente.\n\nНадішліть їм запрошення для обміну фотографіями."; - static String m32(text) => "Знайдено додаткові фотографії для ${text}"; - - static String m34(count, formattedNumber) => - "${Intl.plural(count, one: 'Для 1 файлу', other: 'Для ${formattedNumber} файлів')} на цьому пристрої було створено резервну копію"; + static String m33(text) => "Знайдено додаткові фотографії для ${text}"; static String m35(count, formattedNumber) => + "${Intl.plural(count, one: 'Для 1 файлу', other: 'Для ${formattedNumber} файлів')} на цьому пристрої було створено резервну копію"; + + static String m36(count, formattedNumber) => "${Intl.plural(count, one: 'Для 1 файлу', other: 'Для ${formattedNumber} файлів')} у цьому альбомі було створено резервну копію"; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "${storageAmountInGB} ГБ щоразу, коли хтось оформлює передплату і застосовує ваш код"; - static String m37(endDate) => "Безплатна пробна версія діє до ${endDate}"; + static String m38(endDate) => "Безплатна пробна версія діє до ${endDate}"; - static String m39(sizeInMBorGB) => "Звільніть ${sizeInMBorGB}"; + static String m40(sizeInMBorGB) => "Звільніть ${sizeInMBorGB}"; - static String m41(currentlyProcessing, totalCount) => + static String m42(currentlyProcessing, totalCount) => "Обробка ${currentlyProcessing} / ${totalCount}"; - static String m43(count) => - "${Intl.plural(count, one: '${count} елемент', few: '${count} елементи', many: '${count} елементів', other: '${count} елементів')}"; + static String m44(count) => + "${Intl.plural(count, one: '${count} елемент', other: '${count} елементів')}"; - static String m45(email) => "${email} запросив вас стати довіреною особою"; + static String m46(email) => "${email} запросив вас стати довіреною особою"; - static String m46(expiryTime) => "Посилання закінчується через ${expiryTime}"; + static String m47(expiryTime) => "Посилання закінчується через ${expiryTime}"; - static String m51(albumName) => "Успішно перенесено до «${albumName}»"; + static String m52(albumName) => "Успішно перенесено до «${albumName}»"; - static String m52(personName) => "Немає пропозицій для ${personName}"; + static String m53(personName) => "Немає пропозицій для ${personName}"; - static String m53(name) => "Не ${name}?"; + static String m54(name) => "Не ${name}?"; - static String m54(familyAdminEmail) => + static String m55(familyAdminEmail) => "Зв\'яжіться з ${familyAdminEmail}, щоб змінити код."; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Надійність пароля: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "Зверніться до ${providerName}, якщо було знято платіж"; - static String m62(endDate) => + static String m63(endDate) => "Безплатна пробна версія діє до ${endDate}.\nПісля цього ви можете обрати платний план."; - static String m63(toEmail) => "Напишіть нам на ${toEmail}"; + static String m64(toEmail) => "Напишіть нам на ${toEmail}"; - static String m64(toEmail) => "Надішліть журнали на \n${toEmail}"; + static String m65(toEmail) => "Надішліть журнали на \n${toEmail}"; - static String m66(folderName) => "Оброблюємо «${folderName}»..."; + static String m67(folderName) => "Оброблюємо «${folderName}»..."; - static String m67(storeName) => "Оцініть нас в ${storeName}"; + static String m68(storeName) => "Оцініть нас в ${storeName}"; - static String m69(days, email) => + static String m70(days, email) => "Ви зможете отримати доступ до облікового запису через ${days} днів. Повідомлення буде надіслано на ${email}."; - static String m70(email) => + static String m71(email) => "Тепер ви можете відновити обліковий запис ${email}, встановивши новий пароль."; - static String m71(email) => + static String m72(email) => "${email} намагається відновити ваш обліковий запис."; - static String m72(storageInGB) => + static String m73(storageInGB) => "3. Ви обоє отримуєте ${storageInGB} ГБ* безплатно"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} буде видалено з цього спільного альбому\n\nБудь-які додані вами фото, будуть також видалені з альбому"; - static String m74(endDate) => "Передплата поновиться ${endDate}"; + static String m75(endDate) => "Передплата поновиться ${endDate}"; - static String m76(count) => - "${Intl.plural(count, one: 'Знайдено ${count} результат', few: 'Знайдено ${count} результати', many: 'Знайдено ${count} результатів', other: 'Знайдено ${count} результати')}"; + static String m77(count) => + "${Intl.plural(count, one: 'Знайдено ${count} результат', other: 'Знайдено ${count} результати')}"; - static String m77(snapshotLength, searchLength) => + static String m78(snapshotLength, searchLength) => "Невідповідність довжини розділів: ${snapshotLength} != ${searchLength}"; - static String m78(count) => "${count} вибрано"; + static String m80(count) => "${count} вибрано"; - static String m79(count, yourCount) => "${count} вибрано (${yourCount} ваші)"; + static String m81(count, yourCount) => "${count} вибрано (${yourCount} ваші)"; - static String m81(verificationID) => + static String m83(verificationID) => "Ось мій ідентифікатор підтвердження: ${verificationID} для ente.io."; - static String m82(verificationID) => + static String m84(verificationID) => "Гей, ви можете підтвердити, що це ваш ідентифікатор підтвердження: ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Реферальний код Ente: ${referralCode} \n\nЗастосуйте його в «Налаштування» → «Загальні» → «Реферали», щоб отримати ${referralStorageInGB} ГБ безплатно після переходу на платний тариф\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Поділитися з конкретними людьми', one: 'Поділитися з 1 особою', other: 'Поділитися з ${numberOfPeople} людьми')}"; - static String m85(emailIDs) => "Поділилися з ${emailIDs}"; + static String m87(emailIDs) => "Поділилися з ${emailIDs}"; - static String m86(fileType) => "Цей ${fileType} буде видалено з пристрою."; + static String m88(fileType) => "Цей ${fileType} буде видалено з пристрою."; - static String m87(fileType) => + static String m89(fileType) => "Цей ${fileType} знаходиться і в Ente, і на вашому пристрої."; - static String m88(fileType) => "Цей ${fileType} буде видалено з Ente."; + static String m90(fileType) => "Цей ${fileType} буде видалено з Ente."; - static String m91(storageAmountInGB) => "${storageAmountInGB} ГБ"; + static String m93(storageAmountInGB) => "${storageAmountInGB} ГБ"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} з ${totalAmount} ${totalStorageUnit} використано"; - static String m93(id) => + static String m95(id) => "Ваш ${id} вже пов\'язаний з іншим обліковим записом Ente.\nЯкщо ви хочете використовувати свій ${id} з цим обліковим записом, зверніться до нашої служби підтримки"; - static String m94(endDate) => "Вашу передплату буде скасовано ${endDate}"; + static String m96(endDate) => "Вашу передплату буде скасовано ${endDate}"; - static String m95(completed, total) => + static String m97(completed, total) => "${completed} / ${total} спогадів збережено"; - static String m96(ignoreReason) => + static String m98(ignoreReason) => "Натисніть, щоб завантажити; завантаження наразі ігнорується через: ${ignoreReason}"; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "Вони також отримують ${storageAmountInGB} ГБ"; - static String m98(email) => "Це ідентифікатор підтвердження пошти ${email}"; + static String m100(email) => "Це ідентифікатор підтвердження пошти ${email}"; - static String m101(count) => + static String m103(count) => "${Intl.plural(count, zero: 'Незабаром', one: '1 день', other: '${count} днів')}"; - static String m104(email) => + static String m106(email) => "Ви отримали запрошення стати спадковим контактом від ${email}."; - static String m105(galleryType) => + static String m107(galleryType) => "Тип галереї «${galleryType}» не підтримується для перейменування"; - static String m106(ignoreReason) => + static String m108(ignoreReason) => "Завантаження проігноровано через: ${ignoreReason}"; - static String m107(count) => "Збереження ${count} спогадів..."; + static String m109(count) => "Збереження ${count} спогадів..."; - static String m108(endDate) => "Діє до ${endDate}"; + static String m110(endDate) => "Діє до ${endDate}"; - static String m109(email) => "Підтвердити ${email}"; + static String m111(email) => "Підтвердити ${email}"; - static String m112(email) => "Ми надіслали листа на ${email}"; + static String m114(email) => "Ми надіслали листа на ${email}"; - static String m113(count) => + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + + static String m116(count) => "${Intl.plural(count, one: '${count} рік тому', other: '${count} років тому')}"; - static String m115(storageSaved) => "Ви успішно звільнили ${storageSaved}!"; + static String m118(storageSaved) => "Ви успішно звільнили ${storageSaved}!"; final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { @@ -514,8 +516,6 @@ class MessageLookup extends MessageLookupByLibrary { "click": MessageLookupByLibrary.simpleMessage("• Натисніть"), "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage( "• Натисніть на меню переповнення"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "close": MessageLookupByLibrary.simpleMessage("Закрити"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage("Клуб за часом захоплення"), @@ -662,7 +662,7 @@ class MessageLookup extends MessageLookupByLibrary { "deleteLocation": MessageLookupByLibrary.simpleMessage("Видалити розташування"), "deletePhotos": MessageLookupByLibrary.simpleMessage("Видалити фото"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Мені бракує ключової функції"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -701,7 +701,7 @@ class MessageLookup extends MessageLookupByLibrary { "Переглядачі все ще можуть робити знімки екрана або зберігати копію ваших фотографій за допомогою зовнішніх інструментів"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Зверніть увагу"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Вимкнути двоетапну перевірку"), "disablingTwofactorAuthentication": @@ -744,9 +744,9 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("Не вдалося завантажити"), "downloading": MessageLookupByLibrary.simpleMessage("Завантаження..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("Редагувати"), "editLocation": MessageLookupByLibrary.simpleMessage("Змінити розташування"), @@ -760,8 +760,8 @@ class MessageLookup extends MessageLookupByLibrary { "eligible": MessageLookupByLibrary.simpleMessage("придатний"), "email": MessageLookupByLibrary.simpleMessage("Адреса електронної пошти"), - "emailChangedTo": m28, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailNoEnteAccount": m31, "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("Підтвердження через пошту"), "emailYourLogs": MessageLookupByLibrary.simpleMessage( @@ -843,7 +843,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Експортувати дані"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage( "Знайдено додаткові фотографії"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage( "Обличчя ще не згруповані, поверніться пізніше"), "faceRecognition": @@ -893,8 +893,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Типи файлів"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Типи та назви файлів"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("Файли видалено"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage("Файли збережено до галереї"), @@ -910,13 +910,13 @@ class MessageLookup extends MessageLookupByLibrary { "foundFaces": MessageLookupByLibrary.simpleMessage("Знайдені обличчя"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("Безплатне сховище отримано"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage( "Безплатне сховище можна використовувати"), "freeTrial": MessageLookupByLibrary.simpleMessage("Безплатний пробний період"), - "freeTrialValidTill": m37, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("Звільніть місце на пристрої"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( @@ -927,7 +927,7 @@ class MessageLookup extends MessageLookupByLibrary { "general": MessageLookupByLibrary.simpleMessage("Загальні"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Створення ключів шифрування..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("Перейти до налаштувань"), "googlePlayId": MessageLookupByLibrary.simpleMessage("Google Play ID"), @@ -1008,7 +1008,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Схоже, що щось пішло не так. Спробуйте ще раз через деякий час. Якщо помилка не зникне, зв\'яжіться з нашою командою підтримки."), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Елементи показують кількість днів, що залишилися до остаточного видалення"), @@ -1032,7 +1032,7 @@ class MessageLookup extends MessageLookupByLibrary { "legacy": MessageLookupByLibrary.simpleMessage("Спадок"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("Облікові записи «Спадку»"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage( "«Спадок» дозволяє довіреним контактам отримати доступ до вашого облікового запису під час вашої відсутності."), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( @@ -1045,7 +1045,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Досягнуто ліміту пристроїв"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Увімкнено"), "linkExpired": MessageLookupByLibrary.simpleMessage("Закінчився"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage( "Термін дії посилання закінчився"), "linkHasExpired": @@ -1111,8 +1111,6 @@ class MessageLookup extends MessageLookupByLibrary { "Довго утримуйте поштову адресу, щоб перевірити наскрізне шифрування."), "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Натисніть і утримуйте елемент для перегляду в повноекранному режимі"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "loopVideoOff": MessageLookupByLibrary.simpleMessage("Вимкнено зациклювання відео"), "loopVideoOn": MessageLookupByLibrary.simpleMessage( @@ -1175,7 +1173,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Перемістити до альбому"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage( "Перемістити до прихованого альбому"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("Переміщено у смітник"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1191,7 +1189,6 @@ class MessageLookup extends MessageLookupByLibrary { "newLocation": MessageLookupByLibrary.simpleMessage("Нове розташування"), "newPerson": MessageLookupByLibrary.simpleMessage("Нова особа"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "newToEnte": MessageLookupByLibrary.simpleMessage("Уперше на Ente"), "newest": MessageLookupByLibrary.simpleMessage("Найновіші"), "next": MessageLookupByLibrary.simpleMessage("Далі"), @@ -1228,10 +1225,10 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Немає результатів"), "noResultsFound": MessageLookupByLibrary.simpleMessage("Нічого не знайдено"), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage( "Не знайдено системного блокування"), - "notPersonLabel": m53, + "notPersonLabel": m54, "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( "Поки що з вами ніхто не поділився"), "nothingToSeeHere": MessageLookupByLibrary.simpleMessage( @@ -1241,10 +1238,7 @@ class MessageLookup extends MessageLookupByLibrary { "onDevice": MessageLookupByLibrary.simpleMessage("На пристрої"), "onEnte": MessageLookupByLibrary.simpleMessage("В Ente"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("Тільки вони"), "oops": MessageLookupByLibrary.simpleMessage("От халепа"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( @@ -1284,7 +1278,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Пароль успішно змінено"), "passwordLock": MessageLookupByLibrary.simpleMessage("Блокування паролем"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "Надійність пароля розраховується з урахуванням довжини пароля, використаних символів, а також того, чи входить пароль у топ 10 000 найбільш використовуваних паролів"), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -1295,7 +1289,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Не вдалося оплатити"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "На жаль, ваш платіж не вдався. Зв\'яжіться зі службою підтримки і ми вам допоможемо!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("Елементи на розгляді"), "pendingSync": @@ -1325,7 +1319,7 @@ class MessageLookup extends MessageLookupByLibrary { "pinLock": MessageLookupByLibrary.simpleMessage("Блокування PIN-кодом"), "playOnTv": MessageLookupByLibrary.simpleMessage("Відтворити альбом на ТБ"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("Передплата Play Store"), "pleaseCheckYourInternetConnectionAndTryAgain": @@ -1337,14 +1331,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Зверніться до служби підтримки, якщо проблема не зникне"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage("Надайте дозволи"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Увійдіть знову"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Виберіть посилання для видалення"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Спробуйте ще раз"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1371,7 +1365,7 @@ class MessageLookup extends MessageLookupByLibrary { "privateSharing": MessageLookupByLibrary.simpleMessage("Приватне поширення"), "proceed": MessageLookupByLibrary.simpleMessage("Продовжити"), - "processingImport": m66, + "processingImport": m67, "publicLinkCreated": MessageLookupByLibrary.simpleMessage("Публічне посилання створено"), "publicLinkEnabled": MessageLookupByLibrary.simpleMessage( @@ -1382,7 +1376,7 @@ class MessageLookup extends MessageLookupByLibrary { "rateTheApp": MessageLookupByLibrary.simpleMessage("Оцініть застосунок"), "rateUs": MessageLookupByLibrary.simpleMessage("Оцініть нас"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "recover": MessageLookupByLibrary.simpleMessage("Відновити"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Відновити обліковий запис"), @@ -1391,7 +1385,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Відновити обліковий запис"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage("Почато відновлення"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("Ключ відновлення"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( "Ключ відновлення скопійовано в буфер обміну"), @@ -1405,12 +1399,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ключ відновлення перевірено"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "Ключ відновлення — це єдиний спосіб відновити фотографії, якщо ви забули пароль. Ви можете знайти свій ключ в розділі «Налаштування» > «Обліковий запис».\n\nВведіть ключ відновлення тут, щоб перевірити, чи правильно ви його зберегли."), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage("Відновлення успішне!"), "recoveryWarning": MessageLookupByLibrary.simpleMessage( "Довірений контакт намагається отримати доступ до вашого облікового запису"), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "Ваш пристрій недостатньо потужний для перевірки пароля, але ми можемо відновити його таким чином, щоб він працював на всіх пристроях.\n\nУвійдіть за допомогою ключа відновлення та відновіть свій пароль (за бажанням ви можете використати той самий ключ знову)."), "recreatePasswordTitle": @@ -1426,7 +1420,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("1. Дайте цей код друзям"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Вони оформлюють передплату"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("Реферали"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage("Реферали зараз призупинені"), @@ -1458,7 +1452,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Вилучити посилання"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Видалити учасника"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Видалити мітку особи"), "removePublicLink": @@ -1480,7 +1474,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Перейменувати файл"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Поновити передплату"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Повідомити про помилку"), "reportBug": @@ -1560,8 +1554,8 @@ class MessageLookup extends MessageLookupByLibrary { "Запросіть людей, і ви побачите всі фотографії, якими вони поділилися, тут"), "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage( "Люди будуть показані тут після завершення оброблення та синхронізації"), - "searchResultCount": m76, - "searchSectionsLengthMismatch": m77, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("Безпека"), "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage( "Посилання на публічні альбоми в застосунку"), @@ -1593,8 +1587,8 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage( "Вибрані елементи будуть видалені з усіх альбомів і переміщені в смітник."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, "send": MessageLookupByLibrary.simpleMessage("Надіслати"), "sendEmail": MessageLookupByLibrary.simpleMessage( "Надіслати електронного листа"), @@ -1631,16 +1625,16 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Поділитися альбомом зараз"), "shareLink": MessageLookupByLibrary.simpleMessage("Поділитися посиланням"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Поділіться тільки з тими людьми, якими ви хочете"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Завантажте Ente для того, щоб легко поділитися фотографіями оригінальної якості та відео\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Поділитися з користувачами без Ente"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage( "Поділитися вашим першим альбомом"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1651,7 +1645,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Нові спільні фотографії"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "Отримувати сповіщення, коли хтось додасть фото до спільного альбому, в якому ви перебуваєте"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Поділитися зі мною"), "sharedWithYou": @@ -1668,11 +1662,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Вийти на інших пристроях"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Я приймаю умови використання і політику приватності"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "Воно буде видалено з усіх альбомів."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("Пропустити"), "social": MessageLookupByLibrary.simpleMessage("Соцмережі"), "someItemsAreInBothEnteAndYourDevice": @@ -1701,8 +1695,6 @@ class MessageLookup extends MessageLookupByLibrary { "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "На жаль, на цьому пристрої не вдалося створити безпечні ключі.\n\nЗареєструйтесь з іншого пристрою."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "sort": MessageLookupByLibrary.simpleMessage("Сортувати"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Сортувати за"), "sortNewestFirst": @@ -1722,13 +1714,13 @@ class MessageLookup extends MessageLookupByLibrary { "storage": MessageLookupByLibrary.simpleMessage("Сховище"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Сім\'я"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Ви"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage("Перевищено ліміт сховища"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "strongStrength": MessageLookupByLibrary.simpleMessage("Надійний"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("Передплачувати"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "Вам потрібна активна передплата, щоб увімкнути спільне поширення."), @@ -1745,7 +1737,7 @@ class MessageLookup extends MessageLookupByLibrary { "suggestFeatures": MessageLookupByLibrary.simpleMessage("Запропонувати нові функції"), "support": MessageLookupByLibrary.simpleMessage("Підтримка"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("Синхронізацію зупинено"), "syncing": MessageLookupByLibrary.simpleMessage("Синхронізуємо..."), @@ -1758,7 +1750,7 @@ class MessageLookup extends MessageLookupByLibrary { "Торкніться, щоби розблокувати"), "tapToUpload": MessageLookupByLibrary.simpleMessage("Натисніть, щоб завантажити"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Схоже, що щось пішло не так. Спробуйте ще раз через деякий час. Якщо помилка не зникне, зв\'яжіться з нашою командою підтримки."), "terminate": MessageLookupByLibrary.simpleMessage("Припинити"), @@ -1781,7 +1773,7 @@ class MessageLookup extends MessageLookupByLibrary { "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage( "Ці елементи будуть видалені з пристрою."), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage( "Вони будуть видалені з усіх альбомів."), "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( @@ -1797,7 +1789,7 @@ class MessageLookup extends MessageLookupByLibrary { "Ця поштова адреса вже використовується"), "thisImageHasNoExifData": MessageLookupByLibrary.simpleMessage( "Це зображення не має даних exif"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( "Це ваш Ідентифікатор підтвердження"), "thisWillLogYouOutOfTheFollowingDevice": @@ -1822,11 +1814,11 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("всього"), "totalSize": MessageLookupByLibrary.simpleMessage("Загальний розмір"), "trash": MessageLookupByLibrary.simpleMessage("Смітник"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("Вирізати"), "trustedContacts": MessageLookupByLibrary.simpleMessage("Довірені контакти"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("Спробувати знову"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "Увімкніть резервну копію для автоматичного завантаження файлів, доданих до теки пристрою в Ente."), @@ -1844,7 +1836,7 @@ class MessageLookup extends MessageLookupByLibrary { "Двоетапну перевірку успішно скинуто"), "twofactorSetup": MessageLookupByLibrary.simpleMessage( "Налаштування двоетапної перевірки"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("Розархівувати"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("Розархівувати альбом"), @@ -1867,10 +1859,10 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage("Оновлення вибору теки..."), "upgrade": MessageLookupByLibrary.simpleMessage("Покращити"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Завантажуємо файли до альбому..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage("Зберігаємо 1 спогад..."), "upto50OffUntil4thDec": @@ -1889,7 +1881,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("Використати вибране фото"), "usedSpace": MessageLookupByLibrary.simpleMessage("Використано місця"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Перевірка не вдалася, спробуйте ще раз"), @@ -1898,7 +1890,7 @@ class MessageLookup extends MessageLookupByLibrary { "verify": MessageLookupByLibrary.simpleMessage("Підтвердити"), "verifyEmail": MessageLookupByLibrary.simpleMessage("Підтвердити пошту"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Підтвердження"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("Підтвердити ключ доступу"), @@ -1937,15 +1929,16 @@ class MessageLookup extends MessageLookupByLibrary { "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "Ми не підтримуємо редагування фотографій та альбомів, якими ви ще не володієте"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Слабкий"), "welcomeBack": MessageLookupByLibrary.simpleMessage("З поверненням!"), "whatsNew": MessageLookupByLibrary.simpleMessage("Що нового"), "whyAddTrustContact": MessageLookupByLibrary.simpleMessage( "Довірений контакт може допомогти у відновленні ваших даних."), + "wishThemAHappyBirthday": m115, "yearShort": MessageLookupByLibrary.simpleMessage("рік"), "yearly": MessageLookupByLibrary.simpleMessage("Щороку"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Так"), "yesCancel": MessageLookupByLibrary.simpleMessage("Так, скасувати"), "yesConvertToViewer": @@ -1978,7 +1971,7 @@ class MessageLookup extends MessageLookupByLibrary { "Ви не можете поділитися із собою"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( "У вас немає жодних архівних елементів."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage( "Ваш обліковий запис видалено"), "yourMap": MessageLookupByLibrary.simpleMessage("Ваша мапа"), diff --git a/mobile/lib/generated/intl/messages_vi.dart b/mobile/lib/generated/intl/messages_vi.dart index cc6f338e38..154e455eec 100644 --- a/mobile/lib/generated/intl/messages_vi.dart +++ b/mobile/lib/generated/intl/messages_vi.dart @@ -69,175 +69,179 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: 'Xóa ${count} mục', other: 'Xóa ${count} mục')}"; - static String m22(currentlyDeleting, totalCount) => + static String m23(currentlyDeleting, totalCount) => "Đang xóa ${currentlyDeleting} / ${totalCount}"; - static String m23(albumName) => + static String m24(albumName) => "Điều này sẽ xóa liên kết công khai để truy cập \"${albumName}\"."; - static String m24(supportEmail) => + static String m25(supportEmail) => "Vui lòng gửi email đến ${supportEmail} từ địa chỉ email đã đăng ký của bạn"; - static String m25(count, storageSaved) => - "Bạn đã dọn dẹp ${Intl.plural(count, one: '${count} tệp trùng lặp', other: '${count} tệp trùng lặp')}, tiết kiệm (${storageSaved}!)"; + static String m26(count, storageSaved) => + "Bạn đã dọn dẹp ${Intl.plural(count, other: '${count} tệp trùng lặp')}, tiết kiệm (${storageSaved}!)"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} tệp, ${formattedSize} mỗi tệp"; - static String m28(newEmail) => "Email đã được thay đổi thành ${newEmail}"; + static String m29(newEmail) => "Email đã được thay đổi thành ${newEmail}"; - static String m30(email) => + static String m31(email) => "${email} không có tài khoản Ente.\n\nGửi cho họ một lời mời để chia sẻ ảnh."; - static String m32(text) => "Extra photos found for ${text}"; - - static String m34(count, formattedNumber) => - "${Intl.plural(count, one: '1 tệp', other: '${formattedNumber} tệp')} trên thiết bị này đã được sao lưu an toàn"; + static String m33(text) => "Extra photos found for ${text}"; static String m35(count, formattedNumber) => + "${Intl.plural(count, one: '1 tệp', other: '${formattedNumber} tệp')} trên thiết bị này đã được sao lưu an toàn"; + + static String m36(count, formattedNumber) => "${Intl.plural(count, one: '1 tệp', other: '${formattedNumber} tệp')} trong album này đã được sao lưu an toàn"; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "${storageAmountInGB} GB mỗi khi ai đó đăng ký gói trả phí và áp dụng mã của bạn"; - static String m37(endDate) => "Dùng thử miễn phí có hiệu lực đến ${endDate}"; + static String m38(endDate) => "Dùng thử miễn phí có hiệu lực đến ${endDate}"; - static String m39(sizeInMBorGB) => "Giải phóng ${sizeInMBorGB}"; + static String m40(sizeInMBorGB) => "Giải phóng ${sizeInMBorGB}"; - static String m41(currentlyProcessing, totalCount) => + static String m41(count, formattedSize) => + "${Intl.plural(count, one: 'Nó có thể được xóa khỏi thiết bị để giải phóng ${formattedSize}', other: 'Chúng có thể được xóa khỏi thiết bị để giải phóng ${formattedSize}')}"; + + static String m42(currentlyProcessing, totalCount) => "Đang xử lý ${currentlyProcessing} / ${totalCount}"; - static String m43(count) => - "${Intl.plural(count, one: '${count} mục', other: '${count} mục')}"; + static String m44(count) => "${Intl.plural(count, other: '${count} mục')}"; - static String m45(email) => + static String m46(email) => "${email} đã mời bạn trở thành một liên hệ tin cậy"; - static String m46(expiryTime) => "Liên kết sẽ hết hạn vào ${expiryTime}"; + static String m47(expiryTime) => "Liên kết sẽ hết hạn vào ${expiryTime}"; - static String m51(albumName) => "Đã di chuyển thành công đến ${albumName}"; + static String m52(albumName) => "Đã di chuyển thành công đến ${albumName}"; - static String m52(personName) => "Không có gợi ý cho ${personName}"; + static String m53(personName) => "Không có gợi ý cho ${personName}"; - static String m53(name) => "Không phải ${name}?"; + static String m54(name) => "Không phải ${name}?"; - static String m54(familyAdminEmail) => + static String m55(familyAdminEmail) => "Vui lòng liên hệ ${familyAdminEmail} để thay đổi mã của bạn."; - static String m56(passwordStrengthValue) => + static String m57(passwordStrengthValue) => "Độ mạnh mật khẩu: ${passwordStrengthValue}"; - static String m57(providerName) => + static String m58(providerName) => "Vui lòng nói chuyện với bộ phận hỗ trợ ${providerName} nếu bạn đã bị tính phí"; - static String m62(endDate) => + static String m63(endDate) => "Dùng thử miễn phí có hiệu lực đến ${endDate}.\nBạn có thể chọn gói trả phí sau đó."; - static String m63(toEmail) => + static String m64(toEmail) => "Vui lòng gửi email cho chúng tôi tại ${toEmail}"; - static String m64(toEmail) => "Vui lòng gửi nhật ký đến \n${toEmail}"; + static String m65(toEmail) => "Vui lòng gửi nhật ký đến \n${toEmail}"; - static String m66(folderName) => "Đang xử lý ${folderName}..."; + static String m67(folderName) => "Đang xử lý ${folderName}..."; - static String m67(storeName) => "Đánh giá chúng tôi trên ${storeName}"; + static String m68(storeName) => "Đánh giá chúng tôi trên ${storeName}"; - static String m69(days, email) => + static String m70(days, email) => "Bạn có thể truy cập tài khoản sau ${days} ngày. Một thông báo sẽ được gửi đến ${email}."; - static String m70(email) => + static String m71(email) => "Bạn có thể khôi phục tài khoản của ${email} bằng cách đặt lại mật khẩu mới."; - static String m71(email) => + static String m72(email) => "${email} đang cố gắng khôi phục tài khoản của bạn."; - static String m72(storageInGB) => + static String m73(storageInGB) => "3. Cả hai bạn đều nhận ${storageInGB} GB* miễn phí"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} sẽ bị xóa khỏi album chia sẻ này\n\nBất kỳ ảnh nào được thêm bởi họ cũng sẽ bị xóa khỏi album"; - static String m74(endDate) => "Đăng ký sẽ được gia hạn vào ${endDate}"; + static String m75(endDate) => "Đăng ký sẽ được gia hạn vào ${endDate}"; - static String m76(count) => - "${Intl.plural(count, one: '${count} kết quả được tìm thấy', other: '${count} kết quả được tìm thấy')}"; + static String m77(count) => + "${Intl.plural(count, other: '${count} kết quả được tìm thấy')}"; - static String m77(snapshotLength, searchLength) => + static String m78(snapshotLength, searchLength) => "Độ dài các phần không khớp: ${snapshotLength} != ${searchLength}"; - static String m78(count) => "${count} đã chọn"; + static String m80(count) => "${count} đã chọn"; - static String m79(count, yourCount) => + static String m81(count, yourCount) => "${count} đã chọn (${yourCount} của bạn)"; - static String m81(verificationID) => + static String m83(verificationID) => "Đây là ID xác minh của tôi: ${verificationID} cho ente.io."; - static String m82(verificationID) => + static String m84(verificationID) => "Chào, bạn có thể xác nhận rằng đây là ID xác minh ente.io của bạn: ${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Mã giới thiệu Ente: ${referralCode} \n\nÁp dụng nó trong Cài đặt → Chung → Giới thiệu để nhận ${referralStorageInGB} GB miễn phí sau khi bạn đăng ký gói trả phí\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Chia sẻ với những người cụ thể', one: 'Chia sẻ với 1 người', other: 'Chia sẻ với ${numberOfPeople} người')}"; - static String m85(emailIDs) => "Chia sẻ với ${emailIDs}"; + static String m87(emailIDs) => "Chia sẻ với ${emailIDs}"; - static String m86(fileType) => + static String m88(fileType) => "Tệp ${fileType} này sẽ bị xóa khỏi thiết bị của bạn."; - static String m87(fileType) => + static String m89(fileType) => "Tệp ${fileType} này có trong cả Ente và thiết bị của bạn."; - static String m88(fileType) => "Tệp ${fileType} này sẽ bị xóa khỏi Ente."; + static String m90(fileType) => "Tệp ${fileType} này sẽ bị xóa khỏi Ente."; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} trong tổng số ${totalAmount} ${totalStorageUnit} đã sử dụng"; - static String m93(id) => + static String m95(id) => "ID ${id} của bạn đã được liên kết với một tài khoản Ente khác.\nNếu bạn muốn sử dụng ID ${id} này với tài khoản này, vui lòng liên hệ với bộ phận hỗ trợ của chúng tôi."; - static String m94(endDate) => "Đăng ký của bạn sẽ bị hủy vào ${endDate}"; + static String m96(endDate) => "Đăng ký của bạn sẽ bị hủy vào ${endDate}"; - static String m95(completed, total) => + static String m97(completed, total) => "${completed}/${total} kỷ niệm đã được lưu giữ"; - static String m96(ignoreReason) => + static String m98(ignoreReason) => "Nhấn để tải lên, tải lên hiện tại bị bỏ qua do ${ignoreReason}"; - static String m97(storageAmountInGB) => + static String m99(storageAmountInGB) => "Họ cũng nhận được ${storageAmountInGB} GB"; - static String m98(email) => "Đây là ID xác minh của ${email}"; + static String m100(email) => "Đây là ID xác minh của ${email}"; - static String m101(count) => + static String m103(count) => "${Intl.plural(count, zero: 'Soon', one: '1 day', other: '${count} days')}"; - static String m104(email) => + static String m106(email) => "Bạn đã được mời làm người liên hệ thừa kế bởi ${email}."; - static String m105(galleryType) => + static String m107(galleryType) => "Loại thư viện ${galleryType} không được hỗ trợ để đổi tên"; - static String m106(ignoreReason) => "Tải lên bị bỏ qua do ${ignoreReason}"; + static String m108(ignoreReason) => "Tải lên bị bỏ qua do ${ignoreReason}"; - static String m107(count) => "Đang lưu giữ ${count} kỷ niệm..."; + static String m109(count) => "Đang lưu giữ ${count} kỷ niệm..."; - static String m108(endDate) => "Có hiệu lực đến ${endDate}"; + static String m110(endDate) => "Có hiệu lực đến ${endDate}"; - static String m109(email) => "Xác minh ${email}"; + static String m111(email) => "Xác minh ${email}"; - static String m112(email) => + static String m114(email) => "Chúng tôi đã gửi một email đến ${email}"; - static String m113(count) => - "${Intl.plural(count, one: '${count} năm trước', other: '${count} năm trước')}"; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; - static String m115(storageSaved) => + static String m116(count) => + "${Intl.plural(count, other: '${count} năm trước')}"; + + static String m118(storageSaved) => "Bạn đã giải phóng thành công ${storageSaved}!"; final messages = _notInlinedMessages(_notInlinedMessages); @@ -520,8 +524,6 @@ class MessageLookup extends MessageLookupByLibrary { "click": MessageLookupByLibrary.simpleMessage("• Nhấn"), "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage("• Nhấn vào menu thả xuống"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "close": MessageLookupByLibrary.simpleMessage("Đóng"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage("Nhóm theo thời gian chụp"), @@ -662,7 +664,7 @@ class MessageLookup extends MessageLookupByLibrary { "deleteItemCount": m21, "deleteLocation": MessageLookupByLibrary.simpleMessage("Xóa vị trí"), "deletePhotos": MessageLookupByLibrary.simpleMessage("Xóa ảnh"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Nó thiếu một tính năng quan trọng mà tôi cần"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -700,7 +702,7 @@ class MessageLookup extends MessageLookupByLibrary { "Người xem vẫn có thể chụp màn hình hoặc lưu bản sao ảnh của bạn bằng các công cụ bên ngoài"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Xin lưu ý"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Vô hiệu hóa xác thực hai yếu tố"), "disablingTwofactorAuthentication": @@ -742,9 +744,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Tải xuống thất bại"), "downloading": MessageLookupByLibrary.simpleMessage("Đang tải xuống..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("Chỉnh sửa"), "editLocation": MessageLookupByLibrary.simpleMessage("Chỉnh sửa vị trí"), @@ -760,8 +762,8 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("Email"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage("Email đã được đăng kí."), - "emailChangedTo": m28, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage("Email chưa được đăng kí."), "emailVerificationToggle": @@ -842,7 +844,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Xuất dữ liệu của bạn"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage("Tìm thấy ảnh bổ sung"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage( "Khuôn mặt chưa được phân cụm, vui lòng quay lại sau"), "faceRecognition": @@ -891,8 +893,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Loại tệp"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Loại tệp và tên"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("Tệp đã bị xóa"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage( "Các tệp đã được lưu vào thư viện"), @@ -908,25 +910,26 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Đã tìm thấy khuôn mặt"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("Lưu trữ miễn phí đã yêu cầu"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage( "Lưu trữ miễn phí có thể sử dụng"), "freeTrial": MessageLookupByLibrary.simpleMessage("Dùng thử miễn phí"), - "freeTrialValidTill": m37, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage( "Giải phóng không gian thiết bị"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Tiết kiệm không gian trên thiết bị của bạn bằng cách xóa các tệp đã được sao lưu."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Giải phóng không gian"), + "freeUpSpaceSaving": m41, "gallery": MessageLookupByLibrary.simpleMessage("Thư viện"), "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Tối đa 1000 kỷ niệm được hiển thị trong thư viện"), "general": MessageLookupByLibrary.simpleMessage("Chung"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage("Đang tạo khóa mã hóa..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("Đi đến cài đặt"), "googlePlayId": MessageLookupByLibrary.simpleMessage("ID Google Play"), "grantFullAccessPrompt": MessageLookupByLibrary.simpleMessage( @@ -1007,7 +1010,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Có vẻ như đã xảy ra sự cố. Vui lòng thử lại sau một thời gian. Nếu lỗi vẫn tiếp diễn, vui lòng liên hệ với đội ngũ hỗ trợ của chúng tôi."), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Các mục cho biết số ngày còn lại trước khi xóa vĩnh viễn"), @@ -1037,7 +1040,7 @@ class MessageLookup extends MessageLookupByLibrary { "legacy": MessageLookupByLibrary.simpleMessage("Thừa kế"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("Tài khoản thừa kế"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage( "Thừa kế cho phép các liên hệ tin cậy truy cập tài khoản của bạn khi bạn không hoạt động."), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( @@ -1050,7 +1053,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Giới hạn thiết bị"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Đã bật"), "linkExpired": MessageLookupByLibrary.simpleMessage("Hết hạn"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("Hết hạn liên kết"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("Liên kết đã hết hạn"), @@ -1113,8 +1116,6 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Nhấn và giữ vào một mục để xem toàn màn hình"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "loopVideoOff": MessageLookupByLibrary.simpleMessage("Dừng phát video lặp lại"), "loopVideoOn": @@ -1172,7 +1173,7 @@ class MessageLookup extends MessageLookupByLibrary { "moveToAlbum": MessageLookupByLibrary.simpleMessage("Chuyển đến album"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Di chuyển đến album ẩn"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("Đã chuyển vào thùng rác"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1188,7 +1189,6 @@ class MessageLookup extends MessageLookupByLibrary { "newAlbum": MessageLookupByLibrary.simpleMessage("Album mới"), "newLocation": MessageLookupByLibrary.simpleMessage("Vị trí mới"), "newPerson": MessageLookupByLibrary.simpleMessage("Người mới"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "newToEnte": MessageLookupByLibrary.simpleMessage("Mới đến Ente"), "newest": MessageLookupByLibrary.simpleMessage("Mới nhất"), "next": MessageLookupByLibrary.simpleMessage("Tiếp theo"), @@ -1226,10 +1226,10 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Không có kết quả"), "noResultsFound": MessageLookupByLibrary.simpleMessage("Không tìm thấy kết quả"), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage( "Không tìm thấy khóa hệ thống"), - "notPersonLabel": m53, + "notPersonLabel": m54, "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( "Chưa có gì được chia sẻ với bạn"), "nothingToSeeHere": MessageLookupByLibrary.simpleMessage( @@ -1239,10 +1239,7 @@ class MessageLookup extends MessageLookupByLibrary { "onDevice": MessageLookupByLibrary.simpleMessage("Trên thiết bị"), "onEnte": MessageLookupByLibrary.simpleMessage( "Trên ente"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("Chỉ họ"), "oops": MessageLookupByLibrary.simpleMessage("Ôi"), "oopsCouldNotSaveEdits": @@ -1279,7 +1276,7 @@ class MessageLookup extends MessageLookupByLibrary { "Đã thay đổi mật khẩu thành công"), "passwordLock": MessageLookupByLibrary.simpleMessage("Khóa bằng mật khẩu"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "Độ mạnh của mật khẩu được tính toán dựa trên độ dài của mật khẩu, các ký tự đã sử dụng và liệu mật khẩu có xuất hiện trong 10.000 mật khẩu được sử dụng nhiều nhất hay không"), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -1290,7 +1287,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Thanh toán thất bại"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Rất tiếc, thanh toán của bạn đã thất bại. Vui lòng liên hệ với bộ phận hỗ trợ và chúng tôi sẽ giúp bạn!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("Các mục đang chờ"), "pendingSync": @@ -1318,7 +1315,7 @@ class MessageLookup extends MessageLookupByLibrary { "pinAlbum": MessageLookupByLibrary.simpleMessage("Ghim album"), "pinLock": MessageLookupByLibrary.simpleMessage("Khóa PIN"), "playOnTv": MessageLookupByLibrary.simpleMessage("Phát album trên TV"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("Đăng ký PlayStore"), "pleaseCheckYourInternetConnectionAndTryAgain": @@ -1330,14 +1327,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Vui lòng liên hệ với bộ phận hỗ trợ nếu vấn đề vẫn tiếp diễn"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage("Vui lòng cấp quyền"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Vui lòng đăng nhập lại"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Vui lòng chọn liên kết nhanh để xóa"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Vui lòng thử lại"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1366,7 +1363,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Chia sẻ riêng tư"), "proceed": MessageLookupByLibrary.simpleMessage("Tiếp tục"), "processed": MessageLookupByLibrary.simpleMessage("Đã xử lý"), - "processingImport": m66, + "processingImport": m67, "publicLinkCreated": MessageLookupByLibrary.simpleMessage( "Liên kết công khai đã được tạo"), "publicLinkEnabled": MessageLookupByLibrary.simpleMessage( @@ -1376,7 +1373,7 @@ class MessageLookup extends MessageLookupByLibrary { "raiseTicket": MessageLookupByLibrary.simpleMessage("Tạo vé"), "rateTheApp": MessageLookupByLibrary.simpleMessage("Đánh giá ứng dụng"), "rateUs": MessageLookupByLibrary.simpleMessage("Đánh giá chúng tôi"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "recover": MessageLookupByLibrary.simpleMessage("Khôi phục"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Khôi phục tài khoản"), @@ -1385,7 +1382,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Khôi phục tài khoản"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage( "Quá trình khôi phục đã được khởi động"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("Khóa khôi phục"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( "Khóa khôi phục đã được sao chép vào clipboard"), @@ -1399,12 +1396,12 @@ class MessageLookup extends MessageLookupByLibrary { "Khóa khôi phục đã được xác minh"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "Khóa khôi phục của bạn là cách duy nhất để khôi phục ảnh của bạn nếu bạn quên mật khẩu. Bạn có thể tìm thấy khóa khôi phục của mình trong Cài đặt > Tài khoản.\n\nVui lòng nhập khóa khôi phục của bạn ở đây để xác minh rằng bạn đã lưu nó đúng cách."), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage("Khôi phục thành công!"), "recoveryWarning": MessageLookupByLibrary.simpleMessage( "Một liên hệ tin cậy đang cố gắng truy cập tài khoản của bạn"), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "Thiết bị hiện tại không đủ mạnh để xác minh mật khẩu của bạn, nhưng chúng tôi có thể tạo lại theo cách hoạt động với tất cả các thiết bị.\n\nVui lòng đăng nhập bằng khóa khôi phục của bạn và tạo lại mật khẩu (bạn có thể sử dụng lại mật khẩu cũ nếu muốn)."), "recreatePasswordTitle": @@ -1419,7 +1416,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Đưa mã này cho bạn bè của bạn"), "referralStep2": MessageLookupByLibrary.simpleMessage("2. Họ đăng ký gói trả phí"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("Giới thiệu"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Giới thiệu hiện đang tạm dừng"), @@ -1448,7 +1445,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Xóa liên kết"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Xóa người tham gia"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Xóa nhãn người"), "removePublicLink": @@ -1467,7 +1464,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("Đổi tên tệp"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Gia hạn đăng ký"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("Báo cáo lỗi"), "reportBug": MessageLookupByLibrary.simpleMessage("Báo cáo lỗi"), "resendEmail": MessageLookupByLibrary.simpleMessage("Gửi lại email"), @@ -1543,8 +1540,8 @@ class MessageLookup extends MessageLookupByLibrary { "Mời mọi người, và bạn sẽ thấy tất cả ảnh được chia sẻ bởi họ ở đây"), "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage( "Người sẽ được hiển thị ở đây sau khi hoàn tất xử lý và đồng bộ"), - "searchResultCount": m76, - "searchSectionsLengthMismatch": m77, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("Bảo mật"), "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage( "Xem liên kết album công khai trong ứng dụng"), @@ -1577,8 +1574,8 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage( "Các mục đã chọn sẽ bị xóa khỏi tất cả các album và chuyển vào thùng rác."), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, "send": MessageLookupByLibrary.simpleMessage("Gửi"), "sendEmail": MessageLookupByLibrary.simpleMessage("Gửi email"), "sendInvite": MessageLookupByLibrary.simpleMessage("Gửi lời mời"), @@ -1609,16 +1606,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage( "Chia sẻ một album ngay bây giờ"), "shareLink": MessageLookupByLibrary.simpleMessage("Chia sẻ liên kết"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Chia sẻ chỉ với những người bạn muốn"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Tải Ente để chúng ta có thể dễ dàng chia sẻ ảnh và video chất lượng gốc\n\nhttps://ente.io"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( "Chia sẻ với người dùng không phải Ente"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage( "Chia sẻ album đầu tiên của bạn"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1630,7 +1627,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ảnh chia sẻ mới"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( "Nhận thông báo khi ai đó thêm ảnh vào album chia sẻ mà bạn tham gia"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Chia sẻ với tôi"), "sharedWithYou": MessageLookupByLibrary.simpleMessage("Được chia sẻ với bạn"), @@ -1646,11 +1643,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Đăng xuất các thiết bị khác"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Tôi đồng ý với các điều khoản dịch vụchính sách bảo mật"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "Nó sẽ bị xóa khỏi tất cả các album."), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("Bỏ qua"), "social": MessageLookupByLibrary.simpleMessage("Xã hội"), "someItemsAreInBothEnteAndYourDevice": @@ -1679,8 +1676,6 @@ class MessageLookup extends MessageLookupByLibrary { "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "Xin lỗi, chúng tôi không thể tạo khóa an toàn trên thiết bị này.\n\nVui lòng đăng ký từ một thiết bị khác."), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "sort": MessageLookupByLibrary.simpleMessage("Sắp xếp"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Sắp xếp theo"), "sortNewestFirst": @@ -1699,13 +1694,13 @@ class MessageLookup extends MessageLookupByLibrary { "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Gia đình"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Bạn"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage("Vượt quá giới hạn lưu trữ"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "strongStrength": MessageLookupByLibrary.simpleMessage("Mạnh"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("Đăng ký"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( "Bạn cần một đăng ký trả phí hoạt động để kích hoạt chia sẻ."), @@ -1722,7 +1717,7 @@ class MessageLookup extends MessageLookupByLibrary { "suggestFeatures": MessageLookupByLibrary.simpleMessage("Gợi ý tính năng"), "support": MessageLookupByLibrary.simpleMessage("Hỗ trợ"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("Đồng bộ hóa đã dừng"), "syncing": MessageLookupByLibrary.simpleMessage("Đang đồng bộ hóa..."), @@ -1732,7 +1727,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Chạm để nhập mã"), "tapToUnlock": MessageLookupByLibrary.simpleMessage("Nhấn để mở khóa"), "tapToUpload": MessageLookupByLibrary.simpleMessage("Nhấn để tải lên"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Có vẻ như đã xảy ra sự cố. Vui lòng thử lại sau một thời gian. Nếu lỗi vẫn tiếp diễn, vui lòng liên hệ với đội ngũ hỗ trợ."), "terminate": MessageLookupByLibrary.simpleMessage("Kết thúc"), @@ -1756,7 +1751,7 @@ class MessageLookup extends MessageLookupByLibrary { "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage( "Các mục này sẽ bị xóa khỏi thiết bị của bạn."), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage( "Chúng sẽ bị xóa khỏi tất cả các album."), "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( @@ -1772,7 +1767,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Email này đã được sử dụng"), "thisImageHasNoExifData": MessageLookupByLibrary.simpleMessage( "Hình ảnh này không có dữ liệu exif"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage("Đây là ID xác minh của bạn"), "thisWillLogYouOutOfTheFollowingDevice": @@ -1796,11 +1791,11 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("tổng"), "totalSize": MessageLookupByLibrary.simpleMessage("Tổng kích thước"), "trash": MessageLookupByLibrary.simpleMessage("Thùng rác"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("Cắt"), "trustedContacts": MessageLookupByLibrary.simpleMessage("Liên hệ tin cậy"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("Thử lại"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "Bật sao lưu để tự động tải lên các tệp được thêm vào thư mục thiết bị này lên Ente."), @@ -1819,7 +1814,7 @@ class MessageLookup extends MessageLookupByLibrary { "Xác thực hai yếu tố đã được đặt lại thành công"), "twofactorSetup": MessageLookupByLibrary.simpleMessage("Cài đặt hai yếu tố"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("Khôi phục"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("Khôi phục album"), @@ -1843,10 +1838,10 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage( "Đang cập nhật lựa chọn thư mục..."), "upgrade": MessageLookupByLibrary.simpleMessage("Nâng cấp"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage("Đang tải tệp lên album..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage("Đang lưu giữ 1 kỷ niệm..."), "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( @@ -1864,14 +1859,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Sử dụng ảnh đã chọn"), "usedSpace": MessageLookupByLibrary.simpleMessage("Không gian đã sử dụng"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Xác minh không thành công, vui lòng thử lại"), "verificationId": MessageLookupByLibrary.simpleMessage("ID xác minh"), "verify": MessageLookupByLibrary.simpleMessage("Xác minh"), "verifyEmail": MessageLookupByLibrary.simpleMessage("Xác minh email"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Xác minh"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("Xác minh mã khóa"), @@ -1909,16 +1904,17 @@ class MessageLookup extends MessageLookupByLibrary { "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage( "Chúng tôi không hỗ trợ chỉnh sửa ảnh và album mà bạn chưa sở hữu"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("Yếu"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Chào mừng trở lại!"), "whatsNew": MessageLookupByLibrary.simpleMessage("Có gì mới"), "whyAddTrustContact": MessageLookupByLibrary.simpleMessage( "Liên hệ tin cậy có thể giúp khôi phục dữ liệu của bạn."), + "wishThemAHappyBirthday": m115, "yearShort": MessageLookupByLibrary.simpleMessage("năm"), "yearly": MessageLookupByLibrary.simpleMessage("Hàng năm"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("Có"), "yesCancel": MessageLookupByLibrary.simpleMessage("Có, hủy"), "yesConvertToViewer": @@ -1950,7 +1946,7 @@ class MessageLookup extends MessageLookupByLibrary { "Bạn không thể chia sẻ với chính mình"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( "Bạn không có mục nào đã lưu trữ."), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("Tài khoản của bạn đã bị xóa"), "yourMap": MessageLookupByLibrary.simpleMessage("Bản đồ của bạn"), diff --git a/mobile/lib/generated/intl/messages_zh.dart b/mobile/lib/generated/intl/messages_zh.dart index 1fd2fff6a4..8b697d1e49 100644 --- a/mobile/lib/generated/intl/messages_zh.dart +++ b/mobile/lib/generated/intl/messages_zh.dart @@ -80,216 +80,216 @@ class MessageLookup extends MessageLookupByLibrary { static String m21(count) => "${Intl.plural(count, one: '删除 ${count} 个项目', other: '删除 ${count} 个项目')}"; - static String m22(currentlyDeleting, totalCount) => + static String m23(currentlyDeleting, totalCount) => "正在删除 ${currentlyDeleting} /共 ${totalCount}"; - static String m23(albumName) => "这将删除用于访问\"${albumName}\"的公开链接。"; + static String m24(albumName) => "这将删除用于访问\"${albumName}\"的公开链接。"; - static String m24(supportEmail) => "请从您注册的邮箱发送一封邮件到 ${supportEmail}"; + static String m25(supportEmail) => "请从您注册的邮箱发送一封邮件到 ${supportEmail}"; - static String m25(count, storageSaved) => + static String m26(count, storageSaved) => "您已经清理了 ${Intl.plural(count, other: '${count} 个重复文件')}, 释放了 (${storageSaved}!)"; - static String m26(count, formattedSize) => + static String m27(count, formattedSize) => "${count} 个文件,每个文件 ${formattedSize}"; - static String m28(newEmail) => "电子邮件已更改为 ${newEmail}"; + static String m29(newEmail) => "电子邮件已更改为 ${newEmail}"; - static String m29(email) => "${email} 没有 Ente 账户。"; + static String m30(email) => "${email} 没有 Ente 账户。"; - static String m30(email) => "${email} 没有 Ente 帐户。\n\n向他们发出共享照片的邀请。"; + static String m31(email) => "${email} 没有 Ente 帐户。\n\n向他们发出共享照片的邀请。"; - static String m31(name) => "拥抱 ${name}"; + static String m32(name) => "拥抱 ${name}"; - static String m32(text) => "为 ${text} 找到额外照片"; + static String m33(text) => "为 ${text} 找到额外照片"; - static String m33(name) => "与 ${name} 的盛宴"; - - static String m34(count, formattedNumber) => - "此设备上的 ${Intl.plural(count, one: '1 个文件', other: '${formattedNumber} 个文件')} 已安全备份"; + static String m34(name) => "与 ${name} 的盛宴"; static String m35(count, formattedNumber) => + "此设备上的 ${Intl.plural(count, one: '1 个文件', other: '${formattedNumber} 个文件')} 已安全备份"; + + static String m36(count, formattedNumber) => "此相册中的 ${Intl.plural(count, one: '1 个文件', other: '${formattedNumber} 个文件')} 已安全备份"; - static String m36(storageAmountInGB) => + static String m37(storageAmountInGB) => "每当有人使用您的代码注册付费计划时您将获得${storageAmountInGB} GB"; - static String m37(endDate) => "免费试用有效期至 ${endDate}"; + static String m38(endDate) => "免费试用有效期至 ${endDate}"; - static String m38(count) => + static String m39(count) => "只要您拥有有效订阅,您仍然可以在 Ente 上访问 ${Intl.plural(count, one: '它', other: '它们')}"; - static String m39(sizeInMBorGB) => "释放 ${sizeInMBorGB}"; + static String m40(sizeInMBorGB) => "释放 ${sizeInMBorGB}"; - static String m40(count, formattedSize) => + static String m41(count, formattedSize) => "${Intl.plural(count, one: '它可以从设备中删除以释放 ${formattedSize}', other: '它们可以从设备中删除以释放 ${formattedSize}')}"; - static String m41(currentlyProcessing, totalCount) => + static String m42(currentlyProcessing, totalCount) => "正在处理 ${currentlyProcessing} / ${totalCount}"; - static String m42(name) => "与 ${name} 徒步"; + static String m43(name) => "与 ${name} 徒步"; - static String m43(count) => - "${Intl.plural(count, one: '${count} 个项目', other: '${count} 个项目')}"; + static String m44(count) => "${Intl.plural(count, other: '${count} 个项目')}"; - static String m44(name) => "最后一次与 ${name} 相聚"; + static String m45(name) => "最后一次与 ${name} 相聚"; - static String m45(email) => "${email} 已邀请您成为可信联系人"; + static String m46(email) => "${email} 已邀请您成为可信联系人"; - static String m46(expiryTime) => "链接将在 ${expiryTime} 过期"; + static String m47(expiryTime) => "链接将在 ${expiryTime} 过期"; - static String m47(email) => "将人员链接到 ${email}"; + static String m48(email) => "将人员链接到 ${email}"; - static String m48(personName, email) => "这将会将 ${personName} 链接到 ${email}"; + static String m49(personName, email) => "这将会将 ${personName} 链接到 ${email}"; - static String m49(count, formattedCount) => + static String m50(count, formattedCount) => "${Intl.plural(count, zero: '暂无回忆', other: '${formattedCount} 个回忆')}"; - static String m50(count) => + static String m51(count) => "${Intl.plural(count, one: '移动项目', other: '移动数个项目')}"; - static String m51(albumName) => "成功移动到 ${albumName}"; + static String m52(albumName) => "成功移动到 ${albumName}"; - static String m52(personName) => "没有针对 ${personName} 的建议"; + static String m53(personName) => "没有针对 ${personName} 的建议"; - static String m53(name) => "不是 ${name}?"; + static String m54(name) => "不是 ${name}?"; - static String m54(familyAdminEmail) => "请联系${familyAdminEmail} 以更改您的代码。"; + static String m55(familyAdminEmail) => "请联系${familyAdminEmail} 以更改您的代码。"; - static String m55(name) => "与 ${name} 开派对"; + static String m56(name) => "与 ${name} 开派对"; - static String m56(passwordStrengthValue) => "密码强度: ${passwordStrengthValue}"; + static String m57(passwordStrengthValue) => "密码强度: ${passwordStrengthValue}"; - static String m57(providerName) => "如果您被收取费用,请用英语与 ${providerName} 的客服聊天"; + static String m58(providerName) => "如果您被收取费用,请用英语与 ${providerName} 的客服聊天"; - static String m58(name, age) => "${name} ${age} 岁啦!"; + static String m59(name, age) => "${name} ${age} 岁啦!"; - static String m59(name, age) => "${name} 快满 ${age} 岁啦"; - - static String m60(count) => - "${Intl.plural(count, zero: '没有照片', one: '1 张照片', other: '${count} 张照片')}"; + static String m60(name, age) => "${name} 快满 ${age} 岁啦"; static String m61(count) => + "${Intl.plural(count, zero: '没有照片', one: '1 张照片', other: '${count} 张照片')}"; + + static String m62(count) => "${Intl.plural(count, zero: '0张照片', one: '1张照片', other: '${count} 张照片')}"; - static String m62(endDate) => "免费试用有效期至 ${endDate}。\n在此之后您可以选择付费计划。"; + static String m63(endDate) => "免费试用有效期至 ${endDate}。\n在此之后您可以选择付费计划。"; - static String m63(toEmail) => "请给我们发送电子邮件至 ${toEmail}"; + static String m64(toEmail) => "请给我们发送电子邮件至 ${toEmail}"; - static String m64(toEmail) => "请将日志发送至 \n${toEmail}"; + static String m65(toEmail) => "请将日志发送至 \n${toEmail}"; - static String m65(name) => "与 ${name} 的合影"; + static String m66(name) => "与 ${name} 的合影"; - static String m66(folderName) => "正在处理 ${folderName}..."; + static String m67(folderName) => "正在处理 ${folderName}..."; - static String m67(storeName) => "在 ${storeName} 上给我们评分"; + static String m68(storeName) => "在 ${storeName} 上给我们评分"; - static String m68(name) => "已将您重新分配给 ${name}"; + static String m69(name) => "已将您重新分配给 ${name}"; - static String m69(days, email) => "您可以在 ${days} 天后访问该账户。通知将发送至 ${email}。"; + static String m70(days, email) => "您可以在 ${days} 天后访问该账户。通知将发送至 ${email}。"; - static String m70(email) => "您现在可以通过设置新密码来恢复 ${email} 的账户。"; + static String m71(email) => "您现在可以通过设置新密码来恢复 ${email} 的账户。"; - static String m71(email) => "${email} 正在尝试恢复您的账户。"; + static String m72(email) => "${email} 正在尝试恢复您的账户。"; - static String m72(storageInGB) => "3. 你和朋友都将免费获得 ${storageInGB} GB*"; + static String m73(storageInGB) => "3. 你和朋友都将免费获得 ${storageInGB} GB*"; - static String m73(userEmail) => + static String m74(userEmail) => "${userEmail} 将从这个共享相册中删除\n\nTA们添加的任何照片也将从相册中删除"; - static String m74(endDate) => "在 ${endDate} 前续费"; + static String m75(endDate) => "在 ${endDate} 前续费"; - static String m75(name) => "与 ${name} 一起的自驾游"; + static String m76(name) => "与 ${name} 一起的自驾游"; - static String m76(count) => + static String m77(count) => "${Intl.plural(count, other: '已找到 ${count} 个结果')}"; - static String m77(snapshotLength, searchLength) => + static String m78(snapshotLength, searchLength) => "部分长度不匹配:${snapshotLength} != ${searchLength}"; - static String m78(count) => "已选择 ${count} 个"; + static String m80(count) => "已选择 ${count} 个"; - static String m79(count, yourCount) => "选择了 ${count} 个 (您的 ${yourCount} 个)"; + static String m81(count, yourCount) => "选择了 ${count} 个 (您的 ${yourCount} 个)"; - static String m80(name) => "与 ${name} 的自拍"; + static String m82(name) => "与 ${name} 的自拍"; - static String m81(verificationID) => "这是我的ente.io 的验证 ID: ${verificationID}。"; + static String m83(verificationID) => "这是我的ente.io 的验证 ID: ${verificationID}。"; - static String m82(verificationID) => + static String m84(verificationID) => "嘿,你能确认这是你的 ente.io 验证 ID吗:${verificationID}"; - static String m83(referralCode, referralStorageInGB) => + static String m85(referralCode, referralStorageInGB) => "Ente 推荐代码:${referralCode}\n\n在 \"设置\"→\"通用\"→\"推荐 \"中应用它,即可在注册付费计划后免费获得 ${referralStorageInGB} GB 存储空间\n\nhttps://ente.io"; - static String m84(numberOfPeople) => + static String m86(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: '与特定人员共享', one: '与 1 人共享', other: '与 ${numberOfPeople} 人共享')}"; - static String m85(emailIDs) => "与 ${emailIDs} 共享"; + static String m87(emailIDs) => "与 ${emailIDs} 共享"; - static String m86(fileType) => "此 ${fileType} 将从您的设备中删除。"; + static String m88(fileType) => "此 ${fileType} 将从您的设备中删除。"; - static String m87(fileType) => "${fileType} 已同时存在于 Ente 和您的设备中。"; + static String m89(fileType) => "${fileType} 已同时存在于 Ente 和您的设备中。"; - static String m88(fileType) => "${fileType} 将从 Ente 中删除。"; + static String m90(fileType) => "${fileType} 将从 Ente 中删除。"; - static String m89(name) => "与 ${name} 一起运动"; + static String m91(name) => "与 ${name} 一起运动"; - static String m90(name) => "聚光灯下的 ${name}"; + static String m92(name) => "聚光灯下的 ${name}"; - static String m91(storageAmountInGB) => "${storageAmountInGB} GB"; + static String m93(storageAmountInGB) => "${storageAmountInGB} GB"; - static String m92( + static String m94( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "已使用 ${usedAmount} ${usedStorageUnit} / ${totalAmount} ${totalStorageUnit}"; - static String m93(id) => + static String m95(id) => "您的 ${id} 已链接到另一个 Ente 账户。\n如果您想在此账户中使用您的 ${id} ,请联系我们的支持人员"; - static String m94(endDate) => "您的订阅将于 ${endDate} 取消"; + static String m96(endDate) => "您的订阅将于 ${endDate} 取消"; - static String m95(completed, total) => "已保存的回忆 ${completed}/共 ${total}"; + static String m97(completed, total) => "已保存的回忆 ${completed}/共 ${total}"; - static String m96(ignoreReason) => "点按上传,由于${ignoreReason},目前上传已被忽略"; + static String m98(ignoreReason) => "点按上传,由于${ignoreReason},目前上传已被忽略"; - static String m97(storageAmountInGB) => "他们也会获得 ${storageAmountInGB} GB"; + static String m99(storageAmountInGB) => "他们也会获得 ${storageAmountInGB} GB"; - static String m98(email) => "这是 ${email} 的验证ID"; - - static String m99(count) => - "${Intl.plural(count, one: '${count} 年前的本周', other: '${count} 年前的本周')}"; - - static String m100(dateFormat) => "${dateFormat} 年间"; + static String m100(email) => "这是 ${email} 的验证ID"; static String m101(count) => + "${Intl.plural(count, one: '${count} 年前的本周', other: '${count} 年前的本周')}"; + + static String m102(dateFormat) => "${dateFormat} 年间"; + + static String m103(count) => "${Intl.plural(count, zero: '马上', one: '1 天', other: '${count} 天')}"; - static String m102(year) => "${year} 年的旅行"; + static String m104(year) => "${year} 年的旅行"; - static String m103(location) => "前往 ${location} 的旅行"; + static String m105(location) => "前往 ${location} 的旅行"; - static String m104(email) => "您已受邀通过 ${email} 成为遗产联系人。"; + static String m106(email) => "您已受邀通过 ${email} 成为遗产联系人。"; - static String m105(galleryType) => "相册类型 ${galleryType} 不支持重命名"; + static String m107(galleryType) => "相册类型 ${galleryType} 不支持重命名"; - static String m106(ignoreReason) => "由于 ${ignoreReason},上传被忽略"; + static String m108(ignoreReason) => "由于 ${ignoreReason},上传被忽略"; - static String m107(count) => "正在保存 ${count} 个回忆..."; + static String m109(count) => "正在保存 ${count} 个回忆..."; - static String m108(endDate) => "有效期至 ${endDate}"; + static String m110(endDate) => "有效期至 ${endDate}"; - static String m109(email) => "验证 ${email}"; - - static String m111(count) => - "${Intl.plural(count, zero: '已添加0个查看者', one: '已添加1个查看者', other: '已添加 ${count} 个查看者')}"; - - static String m112(email) => "我们已经发送邮件到 ${email}"; + static String m111(email) => "验证 ${email}"; static String m113(count) => - "${Intl.plural(count, one: '${count} 年前', other: '${count} 年前')}"; + "${Intl.plural(count, zero: '已添加0个查看者', one: '已添加1个查看者', other: '已添加 ${count} 个查看者')}"; - static String m114(name) => "您和 ${name}"; + static String m114(email) => "我们已经发送邮件到 ${email}"; - static String m115(storageSaved) => "您已成功释放了 ${storageSaved}!"; + static String m115(name) => "Wish \$${name} a happy birthday! 🎉"; + + static String m116(count) => "${Intl.plural(count, other: '${count} 年前')}"; + + static String m117(name) => "您和 ${name}"; + + static String m118(storageSaved) => "您已成功释放了 ${storageSaved}!"; final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { @@ -534,8 +534,6 @@ class MessageLookup extends MessageLookupByLibrary { "click": MessageLookupByLibrary.simpleMessage("• 点击"), "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage("• 点击溢出菜单"), - "clickToInstallOurBestVersionYet": MessageLookupByLibrary.simpleMessage( - "Click to install our best version yet"), "close": MessageLookupByLibrary.simpleMessage("关闭"), "clubByCaptureTime": MessageLookupByLibrary.simpleMessage("按拍摄时间分组"), "clubByFileName": MessageLookupByLibrary.simpleMessage("按文件名排序"), @@ -646,7 +644,7 @@ class MessageLookup extends MessageLookupByLibrary { "deleteItemCount": m21, "deleteLocation": MessageLookupByLibrary.simpleMessage("删除位置"), "deletePhotos": MessageLookupByLibrary.simpleMessage("删除照片"), - "deleteProgress": m22, + "deleteProgress": m23, "deleteReason1": MessageLookupByLibrary.simpleMessage("找不到我想要的功能"), "deleteReason2": MessageLookupByLibrary.simpleMessage("应用或某个功能没有按我的预期运行"), @@ -677,7 +675,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("查看者仍然可以使用外部工具截图或保存您的照片副本"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("请注意"), - "disableLinkMessage": m23, + "disableLinkMessage": m24, "disableTwofactor": MessageLookupByLibrary.simpleMessage("禁用双重认证"), "disablingTwofactorAuthentication": MessageLookupByLibrary.simpleMessage("正在禁用双重认证..."), @@ -711,9 +709,9 @@ class MessageLookup extends MessageLookupByLibrary { "download": MessageLookupByLibrary.simpleMessage("下载"), "downloadFailed": MessageLookupByLibrary.simpleMessage("下載失敗"), "downloading": MessageLookupByLibrary.simpleMessage("正在下载..."), - "dropSupportEmail": m24, - "duplicateFileCountWithStorageSaved": m25, - "duplicateItemsGroup": m26, + "dropSupportEmail": m25, + "duplicateFileCountWithStorageSaved": m26, + "duplicateItemsGroup": m27, "edit": MessageLookupByLibrary.simpleMessage("编辑"), "editLocation": MessageLookupByLibrary.simpleMessage("编辑位置"), "editLocationTagTitle": MessageLookupByLibrary.simpleMessage("编辑位置"), @@ -726,15 +724,15 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("电子邮件地址"), "emailAlreadyRegistered": MessageLookupByLibrary.simpleMessage("此电子邮件地址已被注册。"), - "emailChangedTo": m28, - "emailDoesNotHaveEnteAccount": m29, - "emailNoEnteAccount": m30, + "emailChangedTo": m29, + "emailDoesNotHaveEnteAccount": m30, + "emailNoEnteAccount": m31, "emailNotRegistered": MessageLookupByLibrary.simpleMessage("此电子邮件地址未被注册。"), "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("电子邮件验证"), "emailYourLogs": MessageLookupByLibrary.simpleMessage("通过电子邮件发送您的日志"), - "embracingThem": m31, + "embracingThem": m32, "emergencyContacts": MessageLookupByLibrary.simpleMessage("紧急联系人"), "empty": MessageLookupByLibrary.simpleMessage("清空"), "emptyTrash": MessageLookupByLibrary.simpleMessage("要清空回收站吗?"), @@ -796,7 +794,7 @@ class MessageLookup extends MessageLookupByLibrary { "exportLogs": MessageLookupByLibrary.simpleMessage("导出日志"), "exportYourData": MessageLookupByLibrary.simpleMessage("导出您的数据"), "extraPhotosFound": MessageLookupByLibrary.simpleMessage("发现额外照片"), - "extraPhotosFoundFor": m32, + "extraPhotosFoundFor": m33, "faceNotClusteredYet": MessageLookupByLibrary.simpleMessage("人脸尚未聚类,请稍后再来"), "faceRecognition": MessageLookupByLibrary.simpleMessage("人脸识别"), @@ -825,7 +823,7 @@ class MessageLookup extends MessageLookupByLibrary { "faq": MessageLookupByLibrary.simpleMessage("常见问题"), "faqs": MessageLookupByLibrary.simpleMessage("常见问题"), "favorite": MessageLookupByLibrary.simpleMessage("收藏"), - "feastingWithThem": m33, + "feastingWithThem": m34, "feedback": MessageLookupByLibrary.simpleMessage("反馈"), "file": MessageLookupByLibrary.simpleMessage("文件"), "fileFailedToSaveToGallery": @@ -835,8 +833,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileSavedToGallery": MessageLookupByLibrary.simpleMessage("文件已保存到相册"), "fileTypes": MessageLookupByLibrary.simpleMessage("文件类型"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("文件类型和名称"), - "filesBackedUpFromDevice": m34, - "filesBackedUpInAlbum": m35, + "filesBackedUpFromDevice": m35, + "filesBackedUpInAlbum": m36, "filesDeleted": MessageLookupByLibrary.simpleMessage("文件已删除"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage("多个文件已保存到相册"), @@ -848,24 +846,24 @@ class MessageLookup extends MessageLookupByLibrary { "forgotPassword": MessageLookupByLibrary.simpleMessage("忘记密码"), "foundFaces": MessageLookupByLibrary.simpleMessage("已找到的人脸"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("已领取的免费存储"), - "freeStorageOnReferralSuccess": m36, + "freeStorageOnReferralSuccess": m37, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("可用的免费存储"), "freeTrial": MessageLookupByLibrary.simpleMessage("免费试用"), - "freeTrialValidTill": m37, - "freeUpAccessPostDelete": m38, - "freeUpAmount": m39, + "freeTrialValidTill": m38, + "freeUpAccessPostDelete": m39, + "freeUpAmount": m40, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("释放设备空间"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage("通过清除已备份的文件来节省设备空间。"), "freeUpSpace": MessageLookupByLibrary.simpleMessage("释放空间"), - "freeUpSpaceSaving": m40, + "freeUpSpaceSaving": m41, "gallery": MessageLookupByLibrary.simpleMessage("图库"), "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage("在图库中显示最多1000个回忆"), "general": MessageLookupByLibrary.simpleMessage("通用"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage("正在生成加密密钥..."), - "genericProgress": m41, + "genericProgress": m42, "goToSettings": MessageLookupByLibrary.simpleMessage("前往设置"), "googlePlayId": MessageLookupByLibrary.simpleMessage("Google Play ID"), "grantFullAccessPrompt": @@ -891,7 +889,7 @@ class MessageLookup extends MessageLookupByLibrary { "hideSharedItemsFromHomeGallery": MessageLookupByLibrary.simpleMessage("隐藏主页图库中的共享项目"), "hiding": MessageLookupByLibrary.simpleMessage("正在隐藏..."), - "hikingWithThem": m42, + "hikingWithThem": m43, "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("法国 OSM 主办"), "howItWorks": MessageLookupByLibrary.simpleMessage("工作原理"), "howToViewShareeVerificationID": MessageLookupByLibrary.simpleMessage( @@ -939,7 +937,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "看起来出了点问题。 请稍后重试。 如果错误仍然存在,请联系我们的支持团队。"), - "itemCount": m43, + "itemCount": m44, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage("项目显示永久删除前剩余的天数"), "itemsWillBeRemovedFromAlbum": @@ -957,7 +955,7 @@ class MessageLookup extends MessageLookupByLibrary { "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage("请帮助我们了解这个信息"), "language": MessageLookupByLibrary.simpleMessage("语言"), - "lastTimeWithThem": m44, + "lastTimeWithThem": m45, "lastUpdated": MessageLookupByLibrary.simpleMessage("最后更新"), "lastYearsTrip": MessageLookupByLibrary.simpleMessage("去年的旅行"), "leave": MessageLookupByLibrary.simpleMessage("离开"), @@ -967,7 +965,7 @@ class MessageLookup extends MessageLookupByLibrary { "left": MessageLookupByLibrary.simpleMessage("向左"), "legacy": MessageLookupByLibrary.simpleMessage("遗产"), "legacyAccounts": MessageLookupByLibrary.simpleMessage("遗产账户"), - "legacyInvite": m45, + "legacyInvite": m46, "legacyPageDesc": MessageLookupByLibrary.simpleMessage("遗产允许信任的联系人在您不在时访问您的账户。"), "legacyPageDesc2": MessageLookupByLibrary.simpleMessage( @@ -983,14 +981,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("来实现更快的共享"), "linkEnabled": MessageLookupByLibrary.simpleMessage("已启用"), "linkExpired": MessageLookupByLibrary.simpleMessage("已过期"), - "linkExpiresOn": m46, + "linkExpiresOn": m47, "linkExpiry": MessageLookupByLibrary.simpleMessage("链接过期"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("链接已过期"), "linkNeverExpires": MessageLookupByLibrary.simpleMessage("永不"), "linkPerson": MessageLookupByLibrary.simpleMessage("链接人员"), "linkPersonCaption": MessageLookupByLibrary.simpleMessage("来感受更好的共享体验"), - "linkPersonToEmail": m47, - "linkPersonToEmailConfirmation": m48, + "linkPersonToEmail": m48, + "linkPersonToEmailConfirmation": m49, "livePhotos": MessageLookupByLibrary.simpleMessage("实况照片"), "loadMessage1": MessageLookupByLibrary.simpleMessage("您可以与家庭分享您的订阅"), "loadMessage3": @@ -1039,8 +1037,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("长按电子邮件以验证端到端加密。"), "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage("长按一个项目来全屏查看"), - "lookBackOnYourMemories": MessageLookupByLibrary.simpleMessage( - "Look back on your memories 🌄"), "loopVideoOff": MessageLookupByLibrary.simpleMessage("循环播放视频关闭"), "loopVideoOn": MessageLookupByLibrary.simpleMessage("循环播放视频开启"), "lostDevice": MessageLookupByLibrary.simpleMessage("设备丢失?"), @@ -1063,7 +1059,7 @@ class MessageLookup extends MessageLookupByLibrary { "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), "me": MessageLookupByLibrary.simpleMessage("我"), - "memoryCount": m49, + "memoryCount": m50, "merchandise": MessageLookupByLibrary.simpleMessage("商品"), "mergeWithExisting": MessageLookupByLibrary.simpleMessage("与现有的合并"), "mergedPhotos": MessageLookupByLibrary.simpleMessage("已合并照片"), @@ -1090,12 +1086,12 @@ class MessageLookup extends MessageLookupByLibrary { "mostRecent": MessageLookupByLibrary.simpleMessage("最近"), "mostRelevant": MessageLookupByLibrary.simpleMessage("最相关"), "mountains": MessageLookupByLibrary.simpleMessage("翻过山丘"), - "moveItem": m50, + "moveItem": m51, "moveSelectedPhotosToOneDate": MessageLookupByLibrary.simpleMessage("将选定的照片调整到某一日期"), "moveToAlbum": MessageLookupByLibrary.simpleMessage("移动到相册"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("移至隐藏相册"), - "movedSuccessfullyTo": m51, + "movedSuccessfullyTo": m52, "movedToTrash": MessageLookupByLibrary.simpleMessage("已移至回收站"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage("正在将文件移动到相册..."), @@ -1109,7 +1105,6 @@ class MessageLookup extends MessageLookupByLibrary { "newAlbum": MessageLookupByLibrary.simpleMessage("新建相册"), "newLocation": MessageLookupByLibrary.simpleMessage("新位置"), "newPerson": MessageLookupByLibrary.simpleMessage("新人物"), - "newPhotosEmoji": MessageLookupByLibrary.simpleMessage(" new 📸"), "newRange": MessageLookupByLibrary.simpleMessage("新起始图片"), "newToEnte": MessageLookupByLibrary.simpleMessage("初来 Ente"), "newest": MessageLookupByLibrary.simpleMessage("最新"), @@ -1140,9 +1135,9 @@ class MessageLookup extends MessageLookupByLibrary { "由于我们端到端加密协议的性质,如果没有您的密码或恢复密钥,您的数据将无法解密"), "noResults": MessageLookupByLibrary.simpleMessage("无结果"), "noResultsFound": MessageLookupByLibrary.simpleMessage("未找到任何结果"), - "noSuggestionsForPerson": m52, + "noSuggestionsForPerson": m53, "noSystemLockFound": MessageLookupByLibrary.simpleMessage("未找到系统锁"), - "notPersonLabel": m53, + "notPersonLabel": m54, "notThisPerson": MessageLookupByLibrary.simpleMessage("不是此人?"), "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage("尚未与您共享任何内容"), @@ -1153,10 +1148,7 @@ class MessageLookup extends MessageLookupByLibrary { "onEnte": MessageLookupByLibrary.simpleMessage( "在 ente 上"), "onTheRoad": MessageLookupByLibrary.simpleMessage("再次踏上旅途"), - "onThisDay": MessageLookupByLibrary.simpleMessage("On this day"), - "onThisDayNotificationExplanation": MessageLookupByLibrary.simpleMessage( - "Receive reminders about memories from this day in previous years."), - "onlyFamilyAdminCanChangeCode": m54, + "onlyFamilyAdminCanChangeCode": m55, "onlyThem": MessageLookupByLibrary.simpleMessage("仅限他们"), "oops": MessageLookupByLibrary.simpleMessage("哎呀"), "oopsCouldNotSaveEdits": @@ -1183,7 +1175,7 @@ class MessageLookup extends MessageLookupByLibrary { "pairWithPin": MessageLookupByLibrary.simpleMessage("用 PIN 配对"), "pairingComplete": MessageLookupByLibrary.simpleMessage("配对完成"), "panorama": MessageLookupByLibrary.simpleMessage("全景"), - "partyWithThem": m55, + "partyWithThem": m56, "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage("仍需进行验证"), "passkey": MessageLookupByLibrary.simpleMessage("通行密钥"), @@ -1192,7 +1184,7 @@ class MessageLookup extends MessageLookupByLibrary { "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage("密码修改成功"), "passwordLock": MessageLookupByLibrary.simpleMessage("密码锁"), - "passwordStrength": m56, + "passwordStrength": m57, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "密码强度的计算考虑了密码的长度、使用的字符以及密码是否出现在最常用的 10,000 个密码中"), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -1201,7 +1193,7 @@ class MessageLookup extends MessageLookupByLibrary { "paymentFailed": MessageLookupByLibrary.simpleMessage("支付失败"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "不幸的是,您的付款失败。请联系支持人员,我们将为您提供帮助!"), - "paymentFailedTalkToProvider": m57, + "paymentFailedTalkToProvider": m58, "pendingItems": MessageLookupByLibrary.simpleMessage("待处理项目"), "pendingSync": MessageLookupByLibrary.simpleMessage("正在等待同步"), "people": MessageLookupByLibrary.simpleMessage("人物"), @@ -1211,18 +1203,18 @@ class MessageLookup extends MessageLookupByLibrary { "permanentlyDelete": MessageLookupByLibrary.simpleMessage("永久删除"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage("要从设备中永久删除吗?"), - "personIsAge": m58, + "personIsAge": m59, "personName": MessageLookupByLibrary.simpleMessage("人物名称"), - "personTurningAge": m59, + "personTurningAge": m60, "pets": MessageLookupByLibrary.simpleMessage("毛茸茸的伙伴"), "photoDescriptions": MessageLookupByLibrary.simpleMessage("照片说明"), "photoGridSize": MessageLookupByLibrary.simpleMessage("照片网格大小"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("照片"), - "photocountPhotos": m60, + "photocountPhotos": m61, "photos": MessageLookupByLibrary.simpleMessage("照片"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage("您添加的照片将从相册中移除"), - "photosCount": m61, + "photosCount": m62, "photosKeepRelativeTimeDifference": MessageLookupByLibrary.simpleMessage("照片保持相对时间差"), "pickCenterPoint": MessageLookupByLibrary.simpleMessage("选择中心点"), @@ -1230,7 +1222,7 @@ class MessageLookup extends MessageLookupByLibrary { "pinLock": MessageLookupByLibrary.simpleMessage("PIN 锁定"), "playOnTv": MessageLookupByLibrary.simpleMessage("在电视上播放相册"), "playOriginal": MessageLookupByLibrary.simpleMessage("播放原内容"), - "playStoreFreeTrialValidTill": m62, + "playStoreFreeTrialValidTill": m63, "playStream": MessageLookupByLibrary.simpleMessage("播放流"), "playstoreSubscription": MessageLookupByLibrary.simpleMessage("PlayStore 订阅"), @@ -1241,12 +1233,12 @@ class MessageLookup extends MessageLookupByLibrary { "请用英语联系 support@ente.io ,我们将乐意提供帮助!"), "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage("如果问题仍然存在,请联系支持"), - "pleaseEmailUsAt": m63, + "pleaseEmailUsAt": m64, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage("请授予权限"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("请重新登录"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage("请选择要删除的快速链接"), - "pleaseSendTheLogsTo": m64, + "pleaseSendTheLogsTo": m65, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("请重试"), "pleaseVerifyTheCodeYouHaveEntered": MessageLookupByLibrary.simpleMessage("请验证您输入的代码"), @@ -1257,7 +1249,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("请稍等片刻后再重试"), "pleaseWaitThisWillTakeAWhile": MessageLookupByLibrary.simpleMessage("请稍候,这将需要一段时间。"), - "posingWithThem": m65, + "posingWithThem": m66, "preparingLogs": MessageLookupByLibrary.simpleMessage("正在准备日志..."), "preserveMore": MessageLookupByLibrary.simpleMessage("保留更多"), "pressAndHoldToPlayVideo": @@ -1272,7 +1264,7 @@ class MessageLookup extends MessageLookupByLibrary { "proceed": MessageLookupByLibrary.simpleMessage("继续"), "processed": MessageLookupByLibrary.simpleMessage("已处理"), "processing": MessageLookupByLibrary.simpleMessage("正在处理"), - "processingImport": m66, + "processingImport": m67, "processingVideos": MessageLookupByLibrary.simpleMessage("正在处理视频"), "publicLinkCreated": MessageLookupByLibrary.simpleMessage("公共链接已创建"), "publicLinkEnabled": MessageLookupByLibrary.simpleMessage("公开链接已启用"), @@ -1282,16 +1274,16 @@ class MessageLookup extends MessageLookupByLibrary { "raiseTicket": MessageLookupByLibrary.simpleMessage("提升工单"), "rateTheApp": MessageLookupByLibrary.simpleMessage("为此应用评分"), "rateUs": MessageLookupByLibrary.simpleMessage("给我们评分"), - "rateUsOnStore": m67, + "rateUsOnStore": m68, "reassignMe": MessageLookupByLibrary.simpleMessage("重新分配“我”"), - "reassignedToName": m68, + "reassignedToName": m69, "reassigningLoading": MessageLookupByLibrary.simpleMessage("正在重新分配..."), "recover": MessageLookupByLibrary.simpleMessage("恢复"), "recoverAccount": MessageLookupByLibrary.simpleMessage("恢复账户"), "recoverButton": MessageLookupByLibrary.simpleMessage("恢复"), "recoveryAccount": MessageLookupByLibrary.simpleMessage("恢复账户"), "recoveryInitiated": MessageLookupByLibrary.simpleMessage("已启动恢复"), - "recoveryInitiatedDesc": m69, + "recoveryInitiatedDesc": m70, "recoveryKey": MessageLookupByLibrary.simpleMessage("恢复密钥"), "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage("恢复密钥已复制到剪贴板"), @@ -1304,11 +1296,11 @@ class MessageLookup extends MessageLookupByLibrary { "recoveryKeyVerified": MessageLookupByLibrary.simpleMessage("恢复密钥已验证"), "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( "如果您忘记了密码,恢复密钥是恢复照片的唯一方法。您可以在“设置”>“账户”中找到恢复密钥。\n\n请在此处输入恢复密钥,以验证您是否已正确保存。"), - "recoveryReady": m70, + "recoveryReady": m71, "recoverySuccessful": MessageLookupByLibrary.simpleMessage("恢复成功!"), "recoveryWarning": MessageLookupByLibrary.simpleMessage("一位可信联系人正在尝试访问您的账户"), - "recoveryWarningBody": m71, + "recoveryWarningBody": m72, "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( "当前设备的功能不足以验证您的密码,但我们可以以适用于所有设备的方式重新生成。\n\n请使用您的恢复密钥登录并重新生成您的密码(如果您希望,可以再次使用相同的密码)。"), "recreatePasswordTitle": MessageLookupByLibrary.simpleMessage("重新创建密码"), @@ -1319,7 +1311,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("把我们推荐给你的朋友然后获得延长一倍的订阅计划"), "referralStep1": MessageLookupByLibrary.simpleMessage("1. 将此代码提供给您的朋友"), "referralStep2": MessageLookupByLibrary.simpleMessage("2. 他们注册一个付费计划"), - "referralStep3": m72, + "referralStep3": m73, "referrals": MessageLookupByLibrary.simpleMessage("推荐"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage("推荐已暂停"), @@ -1342,7 +1334,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeInvite": MessageLookupByLibrary.simpleMessage("移除邀请"), "removeLink": MessageLookupByLibrary.simpleMessage("移除链接"), "removeParticipant": MessageLookupByLibrary.simpleMessage("移除参与者"), - "removeParticipantBody": m73, + "removeParticipantBody": m74, "removePersonLabel": MessageLookupByLibrary.simpleMessage("移除人物标签"), "removePublicLink": MessageLookupByLibrary.simpleMessage("删除公开链接"), "removePublicLinks": MessageLookupByLibrary.simpleMessage("删除公开链接"), @@ -1357,7 +1349,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameAlbum": MessageLookupByLibrary.simpleMessage("重命名相册"), "renameFile": MessageLookupByLibrary.simpleMessage("重命名文件"), "renewSubscription": MessageLookupByLibrary.simpleMessage("续费订阅"), - "renewsOn": m74, + "renewsOn": m75, "reportABug": MessageLookupByLibrary.simpleMessage("报告错误"), "reportBug": MessageLookupByLibrary.simpleMessage("报告错误"), "resendEmail": MessageLookupByLibrary.simpleMessage("重新发送电子邮件"), @@ -1375,7 +1367,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("请检查并删除您认为重复的项目。"), "reviewSuggestions": MessageLookupByLibrary.simpleMessage("查看建议"), "right": MessageLookupByLibrary.simpleMessage("向右"), - "roadtripWithThem": m75, + "roadtripWithThem": m76, "rotate": MessageLookupByLibrary.simpleMessage("旋转"), "rotateLeft": MessageLookupByLibrary.simpleMessage("向左旋转"), "rotateRight": MessageLookupByLibrary.simpleMessage("向右旋转"), @@ -1420,8 +1412,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("邀请他人,您将在此看到他们分享的所有照片"), "searchPersonsEmptySection": MessageLookupByLibrary.simpleMessage("处理和同步完成后,人物将显示在此处"), - "searchResultCount": m76, - "searchSectionsLengthMismatch": m77, + "searchResultCount": m77, + "searchSectionsLengthMismatch": m78, "security": MessageLookupByLibrary.simpleMessage("安全"), "seePublicAlbumLinksInApp": MessageLookupByLibrary.simpleMessage("在应用程序中查看公开相册链接"), @@ -1457,9 +1449,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("所选项目将从所有相册中删除并移动到回收站。"), "selectedItemsWillBeRemovedFromThisPerson": MessageLookupByLibrary.simpleMessage("选定的项目将从此人身上移除,但不会从您的库中删除。"), - "selectedPhotos": m78, - "selectedPhotosWithYours": m79, - "selfiesWithThem": m80, + "selectedPhotos": m80, + "selectedPhotosWithYours": m81, + "selfiesWithThem": m82, "send": MessageLookupByLibrary.simpleMessage("发送"), "sendEmail": MessageLookupByLibrary.simpleMessage("发送电子邮件"), "sendInvite": MessageLookupByLibrary.simpleMessage("发送邀请"), @@ -1482,16 +1474,16 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("打开相册并点击右上角的分享按钮进行分享"), "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("立即分享相册"), "shareLink": MessageLookupByLibrary.simpleMessage("分享链接"), - "shareMyVerificationID": m81, + "shareMyVerificationID": m83, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage("仅与您想要的人分享"), - "shareTextConfirmOthersVerificationID": m82, + "shareTextConfirmOthersVerificationID": m84, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage("下载 Ente,让我们轻松共享高质量的原始照片和视频"), - "shareTextReferralCode": m83, + "shareTextReferralCode": m85, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage("与非 Ente 用户共享"), - "shareWithPeopleSectionTitle": m84, + "shareWithPeopleSectionTitle": m86, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage("分享您的第一个相册"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( @@ -1502,7 +1494,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("新共享的照片"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage("当有人将照片添加到您所属的共享相册时收到通知"), - "sharedWith": m85, + "sharedWith": m87, "sharedWithMe": MessageLookupByLibrary.simpleMessage("与我共享"), "sharedWithYou": MessageLookupByLibrary.simpleMessage("已与您共享"), "sharing": MessageLookupByLibrary.simpleMessage("正在分享..."), @@ -1516,11 +1508,11 @@ class MessageLookup extends MessageLookupByLibrary { "signOutOtherDevices": MessageLookupByLibrary.simpleMessage("登出其他设备"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "我同意 服务条款隐私政策"), - "singleFileDeleteFromDevice": m86, + "singleFileDeleteFromDevice": m88, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage("它将从所有相册中删除。"), - "singleFileInBothLocalAndRemote": m87, - "singleFileInRemoteOnly": m88, + "singleFileInBothLocalAndRemote": m89, + "singleFileInRemoteOnly": m90, "skip": MessageLookupByLibrary.simpleMessage("跳过"), "social": MessageLookupByLibrary.simpleMessage("社交"), "someItemsAreInBothEnteAndYourDevice": @@ -1542,15 +1534,13 @@ class MessageLookup extends MessageLookupByLibrary { "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": MessageLookupByLibrary.simpleMessage( "抱歉,我们无法在此设备上生成安全密钥。\n\n请使用其他设备注册。"), - "sorryWeHadToPauseYourBackups": MessageLookupByLibrary.simpleMessage( - "Sorry, we had to pause your backups"), "sort": MessageLookupByLibrary.simpleMessage("排序"), "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("排序方式"), "sortNewestFirst": MessageLookupByLibrary.simpleMessage("最新在前"), "sortOldestFirst": MessageLookupByLibrary.simpleMessage("最旧在前"), "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ 成功"), - "sportsWithThem": m89, - "spotlightOnThem": m90, + "sportsWithThem": m91, + "spotlightOnThem": m92, "spotlightOnYourself": MessageLookupByLibrary.simpleMessage("聚光灯下的自己"), "startAccountRecoveryTitle": MessageLookupByLibrary.simpleMessage("开始恢复"), @@ -1561,13 +1551,13 @@ class MessageLookup extends MessageLookupByLibrary { "storage": MessageLookupByLibrary.simpleMessage("存储空间"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("家庭"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("您"), - "storageInGB": m91, + "storageInGB": m93, "storageLimitExceeded": MessageLookupByLibrary.simpleMessage("已超出存储限制"), - "storageUsageInfo": m92, + "storageUsageInfo": m94, "streamDetails": MessageLookupByLibrary.simpleMessage("流详情"), "strongStrength": MessageLookupByLibrary.simpleMessage("强"), - "subAlreadyLinkedErrMessage": m93, - "subWillBeCancelledOn": m94, + "subAlreadyLinkedErrMessage": m95, + "subWillBeCancelledOn": m96, "subscribe": MessageLookupByLibrary.simpleMessage("订阅"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage("您需要有效的付费订阅才能启用共享。"), @@ -1581,7 +1571,7 @@ class MessageLookup extends MessageLookupByLibrary { "suggestFeatures": MessageLookupByLibrary.simpleMessage("建议新功能"), "sunrise": MessageLookupByLibrary.simpleMessage("在地平线上"), "support": MessageLookupByLibrary.simpleMessage("支持"), - "syncProgress": m95, + "syncProgress": m97, "syncStopped": MessageLookupByLibrary.simpleMessage("同步已停止"), "syncing": MessageLookupByLibrary.simpleMessage("正在同步···"), "systemTheme": MessageLookupByLibrary.simpleMessage("适应系统"), @@ -1589,7 +1579,7 @@ class MessageLookup extends MessageLookupByLibrary { "tapToEnterCode": MessageLookupByLibrary.simpleMessage("点击以输入代码"), "tapToUnlock": MessageLookupByLibrary.simpleMessage("点击解锁"), "tapToUpload": MessageLookupByLibrary.simpleMessage("点按上传"), - "tapToUploadIsIgnoredDue": m96, + "tapToUploadIsIgnoredDue": m98, "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "看起来出了点问题。 请稍后重试。 如果错误仍然存在,请联系我们的支持团队。"), @@ -1609,7 +1599,7 @@ class MessageLookup extends MessageLookupByLibrary { "theme": MessageLookupByLibrary.simpleMessage("主题"), "theseItemsWillBeDeletedFromYourDevice": MessageLookupByLibrary.simpleMessage("这些项目将从您的设备中删除。"), - "theyAlsoGetXGb": m97, + "theyAlsoGetXGb": m99, "theyWillBeDeletedFromAllAlbums": MessageLookupByLibrary.simpleMessage("他们将从所有相册中删除。"), "thisActionCannotBeUndone": @@ -1624,11 +1614,11 @@ class MessageLookup extends MessageLookupByLibrary { "thisImageHasNoExifData": MessageLookupByLibrary.simpleMessage("此图像没有Exif 数据"), "thisIsMeExclamation": MessageLookupByLibrary.simpleMessage("这就是我!"), - "thisIsPersonVerificationId": m98, + "thisIsPersonVerificationId": m100, "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage("这是您的验证 ID"), "thisWeekThroughTheYears": MessageLookupByLibrary.simpleMessage("历年本周"), - "thisWeekXYearsAgo": m99, + "thisWeekXYearsAgo": m101, "thisWillLogYouOutOfTheFollowingDevice": MessageLookupByLibrary.simpleMessage("这将使您在以下设备中退出登录:"), "thisWillLogYouOutOfThisDevice": @@ -1637,7 +1627,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("这将使所有选定的照片的日期和时间相同。"), "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage("这将删除所有选定的快速链接的公共链接。"), - "throughTheYears": m100, + "throughTheYears": m102, "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": MessageLookupByLibrary.simpleMessage("要启用应用锁,请在系统设置中设置设备密码或屏幕锁。"), "toHideAPhotoOrVideo": MessageLookupByLibrary.simpleMessage("隐藏照片或视频"), @@ -1649,12 +1639,12 @@ class MessageLookup extends MessageLookupByLibrary { "total": MessageLookupByLibrary.simpleMessage("总计"), "totalSize": MessageLookupByLibrary.simpleMessage("总大小"), "trash": MessageLookupByLibrary.simpleMessage("回收站"), - "trashDaysLeft": m101, + "trashDaysLeft": m103, "trim": MessageLookupByLibrary.simpleMessage("修剪"), - "tripInYear": m102, - "tripToLocation": m103, + "tripInYear": m104, + "tripToLocation": m105, "trustedContacts": MessageLookupByLibrary.simpleMessage("可信联系人"), - "trustedInviteBody": m104, + "trustedInviteBody": m106, "tryAgain": MessageLookupByLibrary.simpleMessage("请再试一次"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "打开备份可自动上传添加到此设备文件夹的文件至 Ente。"), @@ -1669,7 +1659,7 @@ class MessageLookup extends MessageLookupByLibrary { "twofactorAuthenticationSuccessfullyReset": MessageLookupByLibrary.simpleMessage("成功重置双重认证"), "twofactorSetup": MessageLookupByLibrary.simpleMessage("双重认证设置"), - "typeOfGallerGallerytypeIsNotSupportedForRename": m105, + "typeOfGallerGallerytypeIsNotSupportedForRename": m107, "unarchive": MessageLookupByLibrary.simpleMessage("取消存档"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("取消存档相册"), "unarchiving": MessageLookupByLibrary.simpleMessage("正在取消存档..."), @@ -1689,10 +1679,10 @@ class MessageLookup extends MessageLookupByLibrary { "updatingFolderSelection": MessageLookupByLibrary.simpleMessage("正在更新文件夹选择..."), "upgrade": MessageLookupByLibrary.simpleMessage("升级"), - "uploadIsIgnoredDueToIgnorereason": m106, + "uploadIsIgnoredDueToIgnorereason": m108, "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage("正在将文件上传到相册..."), - "uploadingMultipleMemories": m107, + "uploadingMultipleMemories": m109, "uploadingSingleMemory": MessageLookupByLibrary.simpleMessage("正在保存 1 个回忆..."), "upto50OffUntil4thDec": @@ -1707,13 +1697,13 @@ class MessageLookup extends MessageLookupByLibrary { "useRecoveryKey": MessageLookupByLibrary.simpleMessage("使用恢复密钥"), "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("使用所选照片"), "usedSpace": MessageLookupByLibrary.simpleMessage("已用空间"), - "validTill": m108, + "validTill": m110, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage("验证失败,请重试"), "verificationId": MessageLookupByLibrary.simpleMessage("验证 ID"), "verify": MessageLookupByLibrary.simpleMessage("验证"), "verifyEmail": MessageLookupByLibrary.simpleMessage("验证电子邮件"), - "verifyEmailID": m109, + "verifyEmailID": m111, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("验证"), "verifyPasskey": MessageLookupByLibrary.simpleMessage("验证通行密钥"), "verifyPassword": MessageLookupByLibrary.simpleMessage("验证密码"), @@ -1733,7 +1723,7 @@ class MessageLookup extends MessageLookupByLibrary { "viewLogs": MessageLookupByLibrary.simpleMessage("查看日志"), "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("查看恢复密钥"), "viewer": MessageLookupByLibrary.simpleMessage("查看者"), - "viewersSuccessfullyAdded": m111, + "viewersSuccessfullyAdded": m113, "visitWebToManage": MessageLookupByLibrary.simpleMessage("请访问 web.ente.io 来管理您的订阅"), "waitingForVerification": @@ -1743,15 +1733,16 @@ class MessageLookup extends MessageLookupByLibrary { "weAreOpenSource": MessageLookupByLibrary.simpleMessage("我们是开源的 !"), "weDontSupportEditingPhotosAndAlbumsThatYouDont": MessageLookupByLibrary.simpleMessage("我们不支持编辑您尚未拥有的照片和相册"), - "weHaveSendEmailTo": m112, + "weHaveSendEmailTo": m114, "weakStrength": MessageLookupByLibrary.simpleMessage("弱"), "welcomeBack": MessageLookupByLibrary.simpleMessage("欢迎回来!"), "whatsNew": MessageLookupByLibrary.simpleMessage("更新日志"), "whyAddTrustContact": MessageLookupByLibrary.simpleMessage("可信联系人可以帮助恢复您的数据。"), + "wishThemAHappyBirthday": m115, "yearShort": MessageLookupByLibrary.simpleMessage("年"), "yearly": MessageLookupByLibrary.simpleMessage("每年"), - "yearsAgo": m113, + "yearsAgo": m116, "yes": MessageLookupByLibrary.simpleMessage("是"), "yesCancel": MessageLookupByLibrary.simpleMessage("是的,取消"), "yesConvertToViewer": MessageLookupByLibrary.simpleMessage("是的,转换为查看者"), @@ -1762,7 +1753,7 @@ class MessageLookup extends MessageLookupByLibrary { "yesRenew": MessageLookupByLibrary.simpleMessage("是的,续费"), "yesResetPerson": MessageLookupByLibrary.simpleMessage("是,重设人物"), "you": MessageLookupByLibrary.simpleMessage("您"), - "youAndThem": m114, + "youAndThem": m117, "youAreOnAFamilyPlan": MessageLookupByLibrary.simpleMessage("你在一个家庭计划中!"), "youAreOnTheLatestVersion": @@ -1779,7 +1770,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("莫开玩笑,您不能与自己分享"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage("您没有任何存档的项目。"), - "youHaveSuccessfullyFreedUp": m115, + "youHaveSuccessfullyFreedUp": m118, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("您的账户已删除"), "yourMap": MessageLookupByLibrary.simpleMessage("您的地图"), diff --git a/mobile/lib/generated/l10n.dart b/mobile/lib/generated/l10n.dart index b580aada38..6fb57e9450 100644 --- a/mobile/lib/generated/l10n.dart +++ b/mobile/lib/generated/l10n.dart @@ -11925,6 +11925,376 @@ class S { args: [], ); } + + /// `Birthday notifications` + String get birthdayNotifications { + return Intl.message( + 'Birthday notifications', + name: 'birthdayNotifications', + desc: '', + args: [], + ); + } + + /// `Receive reminders when it's someone's birthday. Tapping on the notification will take you to photos of the birthday person.` + String get receiveRemindersOnBirthdays { + return Intl.message( + 'Receive reminders when it\'s someone\'s birthday. Tapping on the notification will take you to photos of the birthday person.', + name: 'receiveRemindersOnBirthdays', + desc: '', + args: [], + ); + } + + /// `Happy birthday! 🥳` + String get happyBirthday { + return Intl.message( + 'Happy birthday! 🥳', + name: 'happyBirthday', + desc: '', + args: [], + ); + } + + /// `Birthdays` + String get birthdays { + return Intl.message( + 'Birthdays', + name: 'birthdays', + desc: '', + args: [], + ); + } + + /// `Wish {name} a happy birthday! 🎉` + String wishThemAHappyBirthday(Object name) { + return Intl.message( + 'Wish $name a happy birthday! 🎉', + name: 'wishThemAHappyBirthday', + desc: '', + args: [name], + ); + } + + /// `Are you sure you want to remove this face from this person?` + String get areYouSureRemoveThisFaceFromPerson { + return Intl.message( + 'Are you sure you want to remove this face from this person?', + name: 'areYouSureRemoveThisFaceFromPerson', + desc: '', + args: [], + ); + } + + /// `Other detected faces` + String get otherDetectedFaces { + return Intl.message( + 'Other detected faces', + name: 'otherDetectedFaces', + desc: '', + args: [], + ); + } + + /// `Are they ` + String get areThey { + return Intl.message( + 'Are they ', + name: 'areThey', + desc: '', + args: [], + ); + } + + /// `?` + String get questionmark { + return Intl.message( + '?', + name: 'questionmark', + desc: '', + args: [], + ); + } + + /// `Save as another person` + String get saveAsAnotherPerson { + return Intl.message( + 'Save as another person', + name: 'saveAsAnotherPerson', + desc: '', + args: [], + ); + } + + /// `Show less faces` + String get showLessFaces { + return Intl.message( + 'Show less faces', + name: 'showLessFaces', + desc: '', + args: [], + ); + } + + /// `Show more faces` + String get showMoreFaces { + return Intl.message( + 'Show more faces', + name: 'showMoreFaces', + desc: '', + args: [], + ); + } + + /// `Ignore` + String get ignore { + return Intl.message( + 'Ignore', + name: 'ignore', + desc: '', + args: [], + ); + } + + /// `Merge` + String get merge { + return Intl.message( + 'Merge', + name: 'merge', + desc: '', + args: [], + ); + } + + /// `Reset` + String get reset { + return Intl.message( + 'Reset', + name: 'reset', + desc: '', + args: [], + ); + } + + /// `Are you sure you want to ignore this person?` + String get areYouSureYouWantToIgnoreThisPerson { + return Intl.message( + 'Are you sure you want to ignore this person?', + name: 'areYouSureYouWantToIgnoreThisPerson', + desc: '', + args: [], + ); + } + + /// `Are you sure you want to ignore these persons?` + String get areYouSureYouWantToIgnoreThesePersons { + return Intl.message( + 'Are you sure you want to ignore these persons?', + name: 'areYouSureYouWantToIgnoreThesePersons', + desc: '', + args: [], + ); + } + + /// `The person groups will not be displayed in the people section anymore. Photos will remain untouched.` + String get thePersonGroupsWillNotBeDisplayed { + return Intl.message( + 'The person groups will not be displayed in the people section anymore. Photos will remain untouched.', + name: 'thePersonGroupsWillNotBeDisplayed', + desc: '', + args: [], + ); + } + + /// `The person will not be displayed in the people section anymore. Photos will remain untouched.` + String get thePersonWillNotBeDisplayed { + return Intl.message( + 'The person will not be displayed in the people section anymore. Photos will remain untouched.', + name: 'thePersonWillNotBeDisplayed', + desc: '', + args: [], + ); + } + + /// `Are you sure you want to merge them?` + String get areYouSureYouWantToMergeThem { + return Intl.message( + 'Are you sure you want to merge them?', + name: 'areYouSureYouWantToMergeThem', + desc: '', + args: [], + ); + } + + /// `All unnamed groups will be merged into the selected person. This can still be undone from the suggestions history overview of the person.` + String get allUnnamedGroupsWillBeMergedIntoTheSelectedPerson { + return Intl.message( + 'All unnamed groups will be merged into the selected person. This can still be undone from the suggestions history overview of the person.', + name: 'allUnnamedGroupsWillBeMergedIntoTheSelectedPerson', + desc: '', + args: [], + ); + } + + /// `Yes, ignore` + String get yesIgnore { + return Intl.message( + 'Yes, ignore', + name: 'yesIgnore', + desc: '', + args: [], + ); + } + + /// `Same` + String get same { + return Intl.message( + 'Same', + name: 'same', + desc: '', + args: [], + ); + } + + /// `Different` + String get different { + return Intl.message( + 'Different', + name: 'different', + desc: '', + args: [], + ); + } + + /// `Same person?` + String get sameperson { + return Intl.message( + 'Same person?', + name: 'sameperson', + desc: '', + args: [], + ); + } + + /// `Uploading Large Video Files` + String get cLTitle1 { + return Intl.message( + 'Uploading Large Video Files', + name: 'cLTitle1', + desc: '', + args: [], + ); + } + + /// `On the back of video streaming beta, and work on resumable uploads and downloads, we have now increased the file upload limit to 10GB. This is now available in both desktop and mobile apps.` + String get cLDesc1 { + return Intl.message( + 'On the back of video streaming beta, and work on resumable uploads and downloads, we have now increased the file upload limit to 10GB. This is now available in both desktop and mobile apps.', + name: 'cLDesc1', + desc: '', + args: [], + ); + } + + /// `Background Upload` + String get cLTitle2 { + return Intl.message( + 'Background Upload', + name: 'cLTitle2', + desc: '', + args: [], + ); + } + + /// `Background uploads are now supported on iOS as well, in addition to Android devices. No need to open the app to backup your latest photos and videos.` + String get cLDesc2 { + return Intl.message( + 'Background uploads are now supported on iOS as well, in addition to Android devices. No need to open the app to backup your latest photos and videos.', + name: 'cLDesc2', + desc: '', + args: [], + ); + } + + /// `Autoplay Memories` + String get cLTitle3 { + return Intl.message( + 'Autoplay Memories', + name: 'cLTitle3', + desc: '', + args: [], + ); + } + + /// `We have made significant improvements to our memories experience, including autoplay, swipe to next memory and a lot more.` + String get cLDesc3 { + return Intl.message( + 'We have made significant improvements to our memories experience, including autoplay, swipe to next memory and a lot more.', + name: 'cLDesc3', + desc: '', + args: [], + ); + } + + /// `Improved Face Recognition` + String get cLTitle4 { + return Intl.message( + 'Improved Face Recognition', + name: 'cLTitle4', + desc: '', + args: [], + ); + } + + /// `Along with a bunch of under the hood improvements, now its much easier to see all detected faces, provide feedback on similar faces, and add/remove faces from a single photo.` + String get cLDesc4 { + return Intl.message( + 'Along with a bunch of under the hood improvements, now its much easier to see all detected faces, provide feedback on similar faces, and add/remove faces from a single photo.', + name: 'cLDesc4', + desc: '', + args: [], + ); + } + + /// `Birthday Notifications` + String get cLTitle5 { + return Intl.message( + 'Birthday Notifications', + name: 'cLTitle5', + desc: '', + args: [], + ); + } + + /// `You will now receive an opt-out notification for all the birthdays your have saved on Ente, along with a collection of their best photos.` + String get cLDesc5 { + return Intl.message( + 'You will now receive an opt-out notification for all the birthdays your have saved on Ente, along with a collection of their best photos.', + name: 'cLDesc5', + desc: '', + args: [], + ); + } + + /// `Resumable Uploads and Downloads` + String get cLTitle6 { + return Intl.message( + 'Resumable Uploads and Downloads', + name: 'cLTitle6', + desc: '', + args: [], + ); + } + + /// `No more waiting for uploads/downloads to complete before you can close the app. All uploads and downloads now have the ability to be paused midway, and resume from where you left off.` + String get cLDesc6 { + return Intl.message( + 'No more waiting for uploads/downloads to complete before you can close the app. All uploads and downloads now have the ability to be paused midway, and resume from where you left off.', + name: 'cLDesc6', + desc: '', + args: [], + ); + } } class AppLocalizationDelegate extends LocalizationsDelegate { @@ -11955,6 +12325,7 @@ class AppLocalizationDelegate extends LocalizationsDelegate { Locale.fromSubtags(languageCode: 'ja'), Locale.fromSubtags(languageCode: 'km'), Locale.fromSubtags(languageCode: 'ko'), + Locale.fromSubtags(languageCode: 'ku'), Locale.fromSubtags(languageCode: 'lt'), Locale.fromSubtags(languageCode: 'lv'), Locale.fromSubtags(languageCode: 'ml'), @@ -11968,6 +12339,7 @@ class AppLocalizationDelegate extends LocalizationsDelegate { Locale.fromSubtags(languageCode: 'ro'), Locale.fromSubtags(languageCode: 'ru'), Locale.fromSubtags(languageCode: 'sl'), + Locale.fromSubtags(languageCode: 'sr'), Locale.fromSubtags(languageCode: 'sv'), Locale.fromSubtags(languageCode: 'ta'), Locale.fromSubtags(languageCode: 'te'), diff --git a/mobile/lib/l10n/intl_ar.arb b/mobile/lib/l10n/intl_ar.arb index 4e3cb12286..c7db982d1e 100644 --- a/mobile/lib/l10n/intl_ar.arb +++ b/mobile/lib/l10n/intl_ar.arb @@ -1,6 +1,7 @@ { "@@locale ": "en", "enterYourEmailAddress": "أدخل عنوان بريدك الإلكتروني", + "enterYourNewEmailAddress": "أدخل عنوان بريدك الإلكتروني الجديد", "accountWelcomeBack": "أهلاً بعودتك!", "emailAlreadyRegistered": "البريد الإلكتروني مُسجل من قبل.", "emailNotRegistered": "البريد الإلكتروني غير مسجل.", @@ -35,7 +36,7 @@ "activeSessions": "الجلسات النشطة", "oops": "عفوًا", "somethingWentWrongPleaseTryAgain": "حدث خطأ ما، يرجى المحاولة مرة أخرى", - "thisWillLogYouOutOfThisDevice": "سيؤدي هذا إلى تسجيل خروجك من هذا الجهاز.", + "thisWillLogYouOutOfThisDevice": "سيؤدي هذا إلى تسجيل خروجك من هذا الجهاز!", "thisWillLogYouOutOfTheFollowingDevice": "سيؤدي هذا إلى تسجيل خروجك من الجهاز التالي:", "terminateSession": "إنهاء الجَلسةِ؟", "terminate": "إنهاء", @@ -45,7 +46,7 @@ "decrypting": "جارٍ فك التشفير...", "incorrectRecoveryKeyTitle": "مفتاح الاسترداد غير صحيح", "incorrectRecoveryKeyBody": "مفتاح الاسترداد الذي أدخلته غير صحيح", - "forgotPassword": "نسيت كلمة المرور؟", + "forgotPassword": "نسيت كلمة المرور", "enterYourRecoveryKey": "أدخل مفتاح الاسترداد", "noRecoveryKey": "لا تملك مفتاح استرداد؟", "sorry": "عفوًا", @@ -120,7 +121,7 @@ "recoveryKeyCopiedToClipboard": "تم نسخ مفتاح الاسترداد إلى الحافظة", "recoverAccount": "استعادة الحساب", "recover": "استعادة", - "dropSupportEmail": "يرجى إرسال بريد إلكتروني إلى {supportEmail} من عنوان بريدك الإلكتروني المسجل.", + "dropSupportEmail": "يرجى إرسال بريد إلكتروني إلى {supportEmail} من عنوان بريدك الإلكتروني المسجل", "@dropSupportEmail": { "placeholders": { "supportEmail": { @@ -140,12 +141,12 @@ "enterThe6digitCodeFromnyourAuthenticatorApp": "أدخل الرمز المكون من 6 أرقام من\n تطبيق المصادقة الخاص بك", "confirm": "تأكيد", "setupComplete": "اكتمل الإعداد", - "saveYourRecoveryKeyIfYouHaventAlready": "احفظ مفتاح الاسترداد إذا لم تكن قد فعلت ذلك بالفعل.", - "thisCanBeUsedToRecoverYourAccountIfYou": "يمكن استخدام هذا المفتاح لاستعادة حسابك إذا فقدت جهاز المصادقة الثنائية.", + "saveYourRecoveryKeyIfYouHaventAlready": "احفظ مفتاح الاسترداد إذا لم تكن قد فعلت ذلك", + "thisCanBeUsedToRecoverYourAccountIfYou": "يمكن استخدام هذا المفتاح لاستعادة حسابك إذا فقدت العامل الثاني للمصادقة", "twofactorAuthenticationPageTitle": "المصادقة الثنائية", "lostDevice": "جهاز مفقود؟", "verifyingRecoveryKey": "جارٍ التحقق من مفتاح الاسترداد...", - "recoveryKeyVerified": "تم التحقق من مفتاح الاسترداد.", + "recoveryKeyVerified": "تم التحقق من مفتاح الاسترداد", "recoveryKeySuccessBody": "مفتاح الاسترداد الخاص بك صالح. شكرًا على التحقق.\n\nيرجى تذكر الاحتفاظ بنسخة احتياطية آمنة من مفتاح الاسترداد.", "invalidRecoveryKey": "مفتاح الاسترداد الذي أدخلته غير صالح. يرجى التأكد من أنه يحتوي على 24 كلمة، والتحقق من كتابة كل كلمة بشكل صحيح.\n\nإذا كنت تستخدم مفتاح استرداد قديمًا، تأكد من أنه مكون من 64 حرفًا، وتحقق من صحة كل حرف.", "invalidKey": "المفتاح غير صالح", @@ -190,7 +191,7 @@ "canNotOpenTitle": "لا يمكن فتح هذا الألبوم", "canNotOpenBody": "عذرًا، لا يمكن فتح هذا الألبوم في التطبيق.", "disableDownloadWarningTitle": "يرجى الملاحظة", - "disableDownloadWarningBody": "لا يزال بإمكان المشاهدين التقاط لقطات شاشة أو حفظ نسخة من صورك باستخدام أدوات خارجية.", + "disableDownloadWarningBody": "لا يزال بإمكان المشاهدين التقاط لقطات شاشة أو حفظ نسخة من صورك باستخدام أدوات خارجية", "allowDownloads": "السماح بالتنزيلات", "linkDeviceLimit": "حد الأجهزة", "noDeviceLimit": "لا شيء", @@ -220,7 +221,7 @@ "after1Month": "بعد شهر", "after1Year": "بعد سنة", "manageParticipants": "إدارة المشاركين", - "albumParticipantsCount": "{count, plural, =0 {لا يوجد مشاركون} =1 {مشارك واحد} two {مشاركان} few {{count} مشاركين} many {{count} مشاركًا} other {{count} مشارك}}", + "albumParticipantsCount": "{count, plural, =0 {لا يوجد مُشاركون}=1 {مُشارك واحد} other {{count} مُشاركين}}", "@albumParticipantsCount": { "placeholders": { "count": { @@ -230,7 +231,7 @@ }, "description": "Number of participants in an album, including the album owner." }, - "collabLinkSectionDescription": "أنشئ رابطًا يسمح للأشخاص بإضافة الصور ومشاهدتها في ألبومك المشترك دون الحاجة إلى تطبيق Ente أو حساب. خيار مثالي لجمع صور الفعاليات بسهولة.", + "collabLinkSectionDescription": "أنشئ رابطًا يسمح للأشخاص بإضافة الصور ومشاهدتها في ألبومك المشترك دون الحاجة إلى تطبيق أو حساب Ente. خيار مثالي لجمع صور الفعاليات بسهولة.", "collectPhotos": "جمع الصور", "collaborativeLink": "رابط تعاوني", "shareWithNonenteUsers": "المشاركة مع غير مستخدمي Ente", @@ -241,7 +242,7 @@ "publicLinkEnabled": "تمكين الرابط العام", "shareALink": "مشاركة رابط", "sharedAlbumSectionDescription": "أنشئ ألبومات مشتركة وتعاونية مع مستخدمي Ente الآخرين، بما في ذلك المستخدمين ذوي الاشتراكات المجانية.", - "shareWithPeopleSectionTitle": "{numberOfPeople, plural, =0 {مشاركة مع أشخاص محددين} =1 {تمت المشاركة مع شخص واحد} two {تمت المشاركة مع شخصين} few {تمت المشاركة مع {numberOfPeople} أشخاص} many {تمت المشاركة مع {numberOfPeople} شخصًا} other {تمت المشاركة مع {numberOfPeople} شخصًا}}", + "shareWithPeopleSectionTitle": "{numberOfPeople, plural, =0 {مشاركة مع أشخاص مُحددين}=1 {مُشارَك مع شخص واحد} other {مُشارَك مع {numberOfPeople} أشخاص}}", "@shareWithPeopleSectionTitle": { "placeholders": { "numberOfPeople": { @@ -266,13 +267,13 @@ "verifyEmailID": "التحقق من {email}", "emailNoEnteAccount": "{email} لا يملك حسابًا على Ente.\n\nأرسل له دعوة لمشاركة الصور.", "shareMyVerificationID": "إليك معرّف التحقق الخاص بي لـ ente.io: {verificationID}", - "shareTextConfirmOthersVerificationID": "مرحبًا، هل يمكنك تأكيد أن هذا هو معرّف التحقق الخاص بك على ente.io: {verificationID}؟", + "shareTextConfirmOthersVerificationID": "مرحبًا، هل يمكنك تأكيد أن هذا هو معرّف التحقق الخاص بك على ente.io: {verificationID}", "somethingWentWrong": "حدث خطأ ما", "sendInvite": "إرسال دعوة", "shareTextRecommendUsingEnte": "قم بتنزيل تطبيق Ente حتى نتمكن من مشاركة الصور ومقاطع الفيديو بالجودة الأصلية بسهولة.\n\nhttps://ente.io", "done": "تم", "applyCodeTitle": "تطبيق الرمز", - "enterCodeDescription": "أدخل الرمز المقدم من صديقك للمطالبة بمساحة تخزين مجانية لكما.", + "enterCodeDescription": "أدخل الرمز المقدم من صديقك للمطالبة بمساحة تخزين مجانية لكما", "apply": "تطبيق", "failedToApplyCode": "فشل تطبيق الرمز", "enterReferralCode": "أدخل رمز الإحالة", @@ -354,8 +355,8 @@ "importing": "جارٍ الاستيراد...", "failedToLoadAlbums": "فشل تحميل الألبومات", "hidden": "المخفية", - "authToViewYourHiddenFiles": "يرجى المصادقة للوصول إلى ملفاتك المخفية.", - "authToViewTrashedFiles": "يرجى المصادقة لعرض ملفاتك المحذوفة.", + "authToViewYourHiddenFiles": "يرجى المصادقة للوصول إلى ملفاتك المخفية", + "authToViewTrashedFiles": "يرجى المصادقة لعرض ملفاتك المحذوفة", "trash": "سلة المهملات", "uncategorized": "غير مصنف", "videoSmallCase": "فيديو", @@ -364,14 +365,14 @@ "singleFileInBothLocalAndRemote": "{fileType} موجود في Ente وعلى جهازك.", "singleFileInRemoteOnly": "سيتم حذف {fileType} من Ente.", "singleFileDeleteFromDevice": "سيتم حذف {fileType} من جهازك.", - "deleteFromEnte": "الحذف من Ente", + "deleteFromEnte": "حذف من Ente", "yesDelete": "نعم، حذف", "movedToTrash": "تم النقل إلى سلة المهملات", "deleteFromDevice": "الحذف من الجهاز", "deleteFromBoth": "الحذف من كليهما", "newAlbum": "ألبوم جديد", "albums": "الألبومات", - "memoryCount": "{count, plural, =0 {لا توجد ذكريات} one {ذكرى واحدة} two {ذكريتان} few {{formattedCount} ذكريات} many {{formattedCount} ذكرى} other {{formattedCount} ذكرى}}", + "memoryCount": "{count, plural, =0 {لا توجد ذكريات} one {ذكرى واحدة} two {ذكريتان} other {{formattedCount} ذكرى}}", "@memoryCount": { "description": "The text to display the number of memories", "type": "text", @@ -459,7 +460,7 @@ "skip": "تخط", "updatingFolderSelection": "جارٍ تحديث تحديد المجلد...", "itemCount": "{count, plural, one {{count} عُنْصُر} other {{count} عَنَاصِر}}", - "deleteItemCount": "{count, plural, =1 {حذف عنصر واحد} two {حذف عنصرين} few {حذف {count} عناصر} many {حذف {count} عنصرًا} other {حذف {count} عنصرًا}}", + "deleteItemCount": "{count, plural, =1 {حذف عنصر واحد} two {حذف عنصرين} other {حذف {count} عنصرًا}}", "duplicateItemsGroup": "{count} ملفات، {formattedSize} لكل منها", "@duplicateItemsGroup": { "description": "Display the number of duplicate files and their size", @@ -476,7 +477,7 @@ } }, "showMemories": "عرض الذكريات", - "yearsAgo": "{count, plural, one {قبل سنة} two {قبل سنتين} few {قبل {count} سنوات} many {قبل {count} سنة} other {قبل {count} سنة}}", + "yearsAgo": "{count, plural, one {قبل سنة} two {قبل سنتين} other {قبل {count} سنة}}", "backupSettings": "إعدادات النسخ الاحتياطي", "backupStatus": "حالة النسخ الاحتياطي", "backupStatusDescription": "ستظهر العناصر التي تم نسخها احتياطيًا هنا", @@ -494,14 +495,14 @@ "youAreOnTheLatestVersion": "أنت تستخدم أحدث إصدار.", "account": "الحساب", "manageSubscription": "إدارة الاشتراك", - "authToChangeYourEmail": "يرجى المصادقة لتغيير بريدك الإلكتروني.", + "authToChangeYourEmail": "يرجى المصادقة لتغيير بريدك الإلكتروني", "changePassword": "تغيير كلمة المرور", - "authToChangeYourPassword": "يرجى المصادقة لتغيير كلمة المرور الخاصة بك.", + "authToChangeYourPassword": "يرجى المصادقة لتغيير كلمة المرور الخاصة بك", "emailVerificationToggle": "تأكيد عنوان البريد الإلكتروني", - "authToChangeEmailVerificationSetting": "يرجى المصادقة لتغيير إعداد التحقق من البريد الإلكتروني.", + "authToChangeEmailVerificationSetting": "يرجى المصادقة لتغيير إعداد التحقق من البريد الإلكتروني", "exportYourData": "تصدير بياناتك", "logout": "تسجيل الخروج", - "authToInitiateAccountDeletion": "يرجى المصادقة لبدء عملية حذف الحساب.", + "authToInitiateAccountDeletion": "يرجى المصادقة لبدء عملية حذف الحساب", "areYouSureYouWantToLogout": "هل أنت متأكد من رغبتك في تسجيل الخروج؟", "yesLogout": "نعم، تسجيل الخروج", "aNewVersionOfEnteIsAvailable": "يتوفر إصدار جديد من Ente.", @@ -511,24 +512,24 @@ "updateAvailable": "يتوفر تحديث", "ignoreUpdate": "تجاهل", "downloading": "جارٍ التنزيل...", - "cannotDeleteSharedFiles": "لا يمكن حذف الملفات المشتركة.", - "theDownloadCouldNotBeCompleted": "تعذر إكمال التنزيل.", + "cannotDeleteSharedFiles": "لا يمكن حذف الملفات المشتركة", + "theDownloadCouldNotBeCompleted": "تعذر إكمال التنزيل", "retry": "إعادة المحاولة", "backedUpFolders": "المجلدات المنسوخة احتياطيًا", "backup": "النسخ الاحتياطي", "freeUpDeviceSpace": "تحرير مساحة على الجهاز", "freeUpDeviceSpaceDesc": "وفر مساحة على جهازك عن طريق مسح الملفات التي تم نسخها احتياطيًا.", "allClear": "✨ كل شيء واضح", - "noDeviceThatCanBeDeleted": "لا توجد ملفات على هذا الجهاز يمكن حذفها.", + "noDeviceThatCanBeDeleted": "لا توجد ملفات على هذا الجهاز يمكن حذفها", "removeDuplicates": "إزالة النسخ المكررة", "removeDuplicatesDesc": "مراجعة وإزالة الملفات المتطابقة تمامًا.", "viewLargeFiles": "الملفات الكبيرة", "viewLargeFilesDesc": "عرض الملفات التي تستهلك أكبر قدر من مساحة التخزين.", "noDuplicates": "✨ لا توجد ملفات مكررة", - "youveNoDuplicateFilesThatCanBeCleared": "لا توجد لديك أي ملفات مكررة يمكن مسحها.", + "youveNoDuplicateFilesThatCanBeCleared": "لا توجد لديك أي ملفات مكررة يمكن مسحها", "success": "تم بنجاح", "rateUs": "تقييم التطبيق", - "remindToEmptyDeviceTrash": "تذكر أيضًا إفراغ \"المحذوفة مؤخرًا\" من \"الإعدادات\" -> \"التخزين\" لاستعادة المساحة المحررة.", + "remindToEmptyDeviceTrash": "تذكر أيضًا إفراغ \"المحذوفة مؤخرًا\" من \"الإعدادات\" -> \"التخزين\" لاستعادة المساحة المحررة", "youHaveSuccessfullyFreedUp": "لقد حررت {storageSaved} بنجاح!", "@youHaveSuccessfullyFreedUp": { "description": "The text to display when the user has successfully freed up storage", @@ -542,7 +543,7 @@ }, "remindToEmptyEnteTrash": "تذكر أيضًا إفراغ \"سلة المهملات\" لاستعادة المساحة المحررة.", "sparkleSuccess": "✨ نجاح", - "duplicateFileCountWithStorageSaved": "لقد قمت بتنظيف {count, plural, one {ملف مكرر واحد} two {ملفين مكررين} few {{count} ملفات مكررة} many {{count} ملفًا مكررًا} other {{count} ملفًا مكررًا}}، مما وفر {storageSaved}!", + "duplicateFileCountWithStorageSaved": "لقد قمت بتنظيف {count, plural, one {ملف مكرر واحد} two {ملفين مكررين} other {{count} ملفًا مكررًا}}، مما وفر {storageSaved}!", "@duplicateFileCountWithStorageSaved": { "description": "The text to display when the user has successfully cleaned up duplicate files", "type": "text", @@ -598,7 +599,7 @@ "selectYourPlan": "اختر خطتك", "enteSubscriptionPitch": "يحفظ Ente ذكرياتك، بحيث تظل دائمًا متاحة لك حتى لو فقدت جهازك.", "enteSubscriptionShareWithFamily": "يمكنك أيضًا إضافة أفراد عائلتك إلى خطتك.", - "currentUsageIs": "استخدامك الحالي هو", + "currentUsageIs": "استخدامك الحالي هو ", "@currentUsageIs": { "description": "This text is followed by storage usage", "examples": { @@ -682,7 +683,7 @@ "areYouSureYouWantToExit": "هل أنت متأكد من رغبتك في الخروج؟", "thankYou": "شكرًا لك", "failedToVerifyPaymentStatus": "فشل التحقق من حالة الدفع.", - "pleaseWaitForSometimeBeforeRetrying": "يرجى الانتظار لبعض الوقت قبل إعادة المحاولة.", + "pleaseWaitForSometimeBeforeRetrying": "يرجى الانتظار لبعض الوقت قبل إعادة المحاولة", "paymentFailedMessage": "للأسف، فشلت عملية الدفع الخاصة بك. يرجى الاتصال بالدعم وسوف نساعدك!", "youAreOnAFamilyPlan": "أنت مشترك في خطة عائلية!", "contactFamilyAdmin": "يرجى الاتصال بـ {familyAdminEmail} لإدارة اشتراكك.", @@ -691,9 +692,9 @@ "leave": "مغادرة", "rateTheApp": "تقييم التطبيق", "startBackup": "بدء النسخ الاحتياطي", - "noPhotosAreBeingBackedUpRightNow": "لا يتم نسخ أي صور احتياطيًا في الوقت الحالي.", + "noPhotosAreBeingBackedUpRightNow": "لا يتم نسخ أي صور احتياطيًا في الوقت الحالي", "preserveMore": "حفظ المزيد", - "grantFullAccessPrompt": "يرجى السماح بالوصول إلى جميع الصور في تطبيق الإعدادات.", + "grantFullAccessPrompt": "الرجاء السماح بالوصول إلى جميع الصور في تطبيق الإعدادات", "allowPermTitle": "السماح بالوصول إلى الصور", "allowPermBody": "يرجى السماح بالوصول إلى صورك من الإعدادات حتى يتمكن Ente من عرض نسختك الاحتياطية ومكتبتك.", "openSettings": "فتح الإعدادات", @@ -710,10 +711,10 @@ "androidIosWebDesktop": "أندرويد، iOS، الويب، سطح المكتب", "mobileWebDesktop": "الهاتف المحمول، الويب، سطح المكتب", "newToEnte": "جديد في Ente", - "pleaseLoginAgain": "يرجى تسجيل الدخول مرة أخرى.", + "pleaseLoginAgain": "يرجى تسجيل الدخول مرة أخرى", "autoLogoutMessage": "بسبب خلل تقني، تم تسجيل خروجك. نعتذر عن الإزعاج.", - "yourSubscriptionHasExpired": "انتهت صلاحية اشتراكك.", - "storageLimitExceeded": "تم تجاوز حد التخزين.", + "yourSubscriptionHasExpired": "انتهت صلاحية اشتراكك", + "storageLimitExceeded": "تم تجاوز حد التخزين", "upgrade": "ترقية", "raiseTicket": "فتح تذكرة دعم", "@raiseTicket": { @@ -723,8 +724,8 @@ "backupFailed": "فشل النسخ الاحتياطي", "sorryBackupFailedDesc": "عذرًا، لم نتمكن من عمل نسخة احتياطية لهذا الملف الآن، سنعيد المحاولة لاحقًا.", "couldNotBackUpTryLater": "لم نتمكن من نسخ بياناتك احتياطيًا.\nسنحاول مرة أخرى لاحقًا.", - "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": "يمكن لـ Ente تشفير وحفظ الملفات فقط إذا منحت الإذن بالوصول إليها.", - "pleaseGrantPermissions": "يرجى منح الأذونات.", + "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": "يمكن لـ Ente تشفير وحفظ الملفات فقط إذا منحت الإذن بالوصول إليها", + "pleaseGrantPermissions": "يرجى منح الأذونات", "grantPermission": "منح الإذن", "privateSharing": "مشاركة خاصة", "shareOnlyWithThePeopleYouWant": "شارك فقط مع الأشخاص الذين تريدهم.", @@ -793,11 +794,11 @@ "share": "مشاركة", "unhideToAlbum": "إظهار في الألبوم", "restoreToAlbum": "استعادة إلى الألبوم", - "moveItem": "{count, plural, =1 {نقل عنصر} two {نقل عنصرين} few {نقل {count} عناصر} many {نقل {count} عنصرًا} other {نقل {count} عنصرًا}}", + "moveItem": "{count, plural, =1 {نقل عنصر} two {نقل عنصرين} other {نقل {count} عنصرًا}}", "@moveItem": { "description": "Page title while moving one or more items to an album" }, - "addItem": "{count, plural, =1 {إضافة عنصر} two {إضافة عنصرين} few {إضافة {count} عناصر} many {إضافة {count} عنصرًا} other {إضافة {count} عنصرًا}}", + "addItem": "{count, plural, =1 {إضافة عنصر} two {إضافة عنصرين} other {إضافة {count} عنصرًا}}", "@addItem": { "description": "Page title while adding one or more items to album" }, @@ -825,7 +826,7 @@ "referFriendsAnd2xYourPlan": "أحِل الأصدقاء وضاعف خطتك مرتين", "shareAlbumHint": "افتح ألبومًا وانقر على زر المشاركة في الزاوية اليمنى العليا للمشاركة.", "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": "تعرض العناصر عدد الأيام المتبقية قبل الحذف الدائم.", - "trashDaysLeft": "{count, plural, =0 {قريبًا} =1 {يوم واحد} two {يومان} few {{count} أيام} many {{count} يومًا} other {{count} يومًا}}", + "trashDaysLeft": "{count, plural, =0 {قريبًا} =1 {يوم واحد} two {يومان} other {{count} يومًا}}", "@trashDaysLeft": { "description": "Text to indicate number of days remaining before permanent deletion", "placeholders": { @@ -898,8 +899,8 @@ "authToViewYourMemories": "يرجى المصادقة لعرض ذكرياتك.", "unlock": "فتح", "freeUpSpace": "تحرير المساحة", - "freeUpSpaceSaving": "{count, plural, =1 {يمكن حذفه من الجهاز لتحرير {formattedSize}} two {يمكن حذفهما من الجهاز لتحرير {formattedSize}} few {يمكن حذفها من الجهاز لتحرير {formattedSize}} many {يمكن حذفها من الجهاز لتحرير {formattedSize}} other {يمكن حذفها من الجهاز لتحرير {formattedSize}}}", - "filesBackedUpInAlbum": "{count, plural, one {ملف واحد} two {ملفان} few {{formattedNumber} ملفات} many {{formattedNumber} ملفًا} other {{formattedNumber} ملفًا}} في هذا الألبوم تم نسخه احتياطيًا بأمان", + "freeUpSpaceSaving": "{count, plural, =1 {يمكن حذفه من الجهاز لتحرير {formattedSize}} two {يمكن حذفهما من الجهاز لتحرير {formattedSize}} other {يمكن حذفها من الجهاز لتحرير {formattedSize}}}", + "filesBackedUpInAlbum": "{count, plural, one {ملف واحد} two {ملفان} other {{formattedNumber} ملفًا}} في هذا الألبوم تم نسخه احتياطيًا بأمان", "@filesBackedUpInAlbum": { "description": "Text to tell user how many files have been backed up in the album", "placeholders": { @@ -914,7 +915,7 @@ } } }, - "filesBackedUpFromDevice": "{count, plural, one {ملف واحد} two {ملفان} few {{formattedNumber} ملفات} many {{formattedNumber} ملفًا} other {{formattedNumber} ملفًا}} على هذا الجهاز تم نسخه احتياطيًا بأمان", + "filesBackedUpFromDevice": "{count, plural, one {ملف واحد} two {ملفان} other {{formattedNumber} ملفًا}} على هذا الجهاز تم نسخه احتياطيًا بأمان", "@filesBackedUpFromDevice": { "description": "Text to tell user how many files have been backed up from this device", "placeholders": { @@ -1030,7 +1031,7 @@ "didYouKnow": "هل تعلم؟", "loadingMessage": "جارٍ تحميل صورك...", "loadMessage1": "يمكنك مشاركة اشتراكك مع عائلتك.", - "loadMessage2": "لقد حفظنا أكثر من 200 مليون ذكرى حتى الآن.", + "loadMessage2": "لقد حفظنا أكثر من 200 مليون ذكرى حتى الآن", "loadMessage3": "نحتفظ بـ 3 نسخ من بياناتك، إحداها في ملجأ للطوارئ تحت الأرض.", "loadMessage4": "جميع تطبيقاتنا مفتوحة المصدر.", "loadMessage5": "تم تدقيق شفرتنا المصدرية والتشفير الخاص بنا خارجيًا.", @@ -1216,7 +1217,7 @@ "searchHint4": "الموقع", "searchHint5": "قريبًا: الوجوه والبحث السحري ✨", "addYourPhotosNow": "أضف صورك الآن", - "searchResultCount": "{count, plural, one{{count} النتائج التي تم العثور عليها} other{{count} النتائج التي تم العثور عليها}}", + "searchResultCount": "{count, plural, other{{count} النتائج التي تم العثور عليها}}", "@searchResultCount": { "description": "Text to tell user how many results were found for their search query", "placeholders": { @@ -1268,8 +1269,8 @@ "description": "Subtitle to indicate that the user can find people quickly by name" }, "findPeopleByName": "البحث عن الأشخاص بسرعة بالاسم", - "addViewers": "{count, plural, =0 {إضافة مشاهد} =1 {إضافة مشاهد} two {إضافة مشاهدين} few {إضافة {count} مشاهدين} many {إضافة {count} مشاهدًا} other {إضافة {count} مشاهدًا}}", - "addCollaborators": "{count, plural, =0 {إضافة متعاون} =1 {إضافة متعاون} two {إضافة متعاونين} few {إضافة {count} متعاونين} many {إضافة {count} متعاونًا} other {إضافة {count} متعاونًا}}", + "addViewers": "{count, plural, =0 {إضافة مشاهد} =1 {إضافة مشاهد} two {إضافة مشاهدين} other {إضافة {count} مشاهدًا}}", + "addCollaborators": "{count, plural, =0 {إضافة متعاون} =1 {إضافة متعاون} two {إضافة متعاونين} other {إضافة {count} متعاونًا}}", "longPressAnEmailToVerifyEndToEndEncryption": "اضغط مطولاً على بريد إلكتروني للتحقق من التشفير من طرف إلى طرف.", "developerSettingsWarning": "هل أنت متأكد من رغبتك في تعديل إعدادات المطور؟", "developerSettings": "إعدادات المطور", @@ -1403,7 +1404,7 @@ "enableMachineLearningBanner": "قم بتمكين تعلم الآلة للبحث السحري والتعرف على الوجوه.", "searchDiscoverEmptySection": "سيتم عرض الصور هنا بمجرد اكتمال المعالجة والمزامنة.", "searchPersonsEmptySection": "سيتم عرض الأشخاص هنا بمجرد اكتمال المعالجة والمزامنة.", - "viewersSuccessfullyAdded": "{count, plural, =0 {تمت إضافة 0 مشاهدين} =1 {تمت إضافة مشاهد واحد} two {تمت إضافة مشاهدين} few {تمت إضافة {count} مشاهدين} many {تمت إضافة {count} مشاهدًا} other {تمت إضافة {count} مشاهدًا}}", + "viewersSuccessfullyAdded": "{count, plural, =0 {تمت إضافة 0 مشاهدين} =1 {تمت إضافة مشاهد واحد} two {تمت إضافة مشاهدين} other {تمت إضافة {count} مشاهدًا}}", "@viewersSuccessfullyAdded": { "placeholders": { "count": { @@ -1413,7 +1414,7 @@ }, "description": "Number of viewers that were successfully added to an album." }, - "collaboratorsSuccessfullyAdded": "{count, plural, =0 {تمت إضافة 0 متعاونين} =1 {تمت إضافة متعاون واحد} two {تمت إضافة متعاونين} few {تمت إضافة {count} متعاونين} many {تمت إضافة {count} متعاونًا} other {تمت إضافة {count} متعاونًا}}", + "collaboratorsSuccessfullyAdded": "{count, plural, =0 {تمت إضافة 0 متعاونين} =1 {تمت إضافة متعاون واحد} two {تمت إضافة متعاونين} other {تمت إضافة {count} متعاونًا}}", "@collaboratorsSuccessfullyAdded": { "placeholders": { "count": { @@ -1488,7 +1489,7 @@ }, "currentlyRunning": "قيد التشغيل حاليًا", "ignored": "تم التجاهل", - "photosCount": "{count, plural, =0 {لا توجد صور} =1 {صورة واحدة} two {صورتان} few {{count} صور} many {{count} صورة} other {{count} صورة}}", + "photosCount": "{count, plural, =0 {لا توجد صور} =1 {صورة واحدة} two {صورتان} other {{count} صورة}}", "@photosCount": { "placeholders": { "count": { @@ -1686,7 +1687,7 @@ "moveSelectedPhotosToOneDate": "نقل الصور المحددة إلى تاريخ واحد", "shiftDatesAndTime": "تغيير التواريخ والوقت", "photosKeepRelativeTimeDifference": "تحتفظ الصور بالفرق الزمني النسبي", - "photocountPhotos": "{count, plural, =0 {لا توجد صور} =1 {صورة واحدة} two {صورتان} few {{count} صور} many {{count} صورة} other {{count} صورة}}", + "photocountPhotos": "{count, plural, =0 {لا توجد صور} =1 {صورة واحدة} two {صورتان} other {{count} صورة}}", "@photocountPhotos": { "placeholders": { "count": { @@ -1700,7 +1701,7 @@ "selectedItemsWillBeRemovedFromThisPerson": "سيتم إزالة العناصر المحددة من هذا الشخص، ولكن لن يتم حذفها من مكتبتك.", "throughTheYears": "{dateFormat} عبر السنين", "thisWeekThroughTheYears": "هذا الأسبوع عبر السنين", - "thisWeekXYearsAgo": "{count, plural, =1 {هذا الأسبوع، قبل سنة} two {هذا الأسبوع، قبل سنتين} few {هذا الأسبوع، قبل {count} سنوات} many {هذا الأسبوع، قبل {count} سنة} other {هذا الأسبوع، قبل {count} سنة}}", + "thisWeekXYearsAgo": "{count, plural, =1 {هذا الأسبوع، قبل سنة} two {هذا الأسبوع، قبل سنتين} other {هذا الأسبوع، قبل {count} سنة}}", "youAndThem": "أنت و {name}", "admiringThem": "الإعجاب بـ {name}", "embracingThem": "معانقة {name}", @@ -1729,21 +1730,16 @@ "onTheRoad": "على الطريق مرة أخرى", "food": "متعة الطهي", "pets": "رفاق فروي", - "cLIcon": "أيقونة جديدة", - "cLIconDesc": "أخيرًا، أيقونة تطبيق جديدة، نعتقد أنها تمثل عملنا على أفضل وجه. أضفنا أيضًا مبدل أيقونات حتى تتمكن من الاستمرار في استخدام الأيقونة القديمة.", - "cLMemories": "الذكريات", - "cLMemoriesDesc": "أعد اكتشاف لحظاتك الخاصة - تسليط الضوء على الأشخاص المفضلين لديك، رحلاتك وعطلاتك، أفضل لقطاتك، وأكثر من ذلك بكثير. قم بتشغيل تعلم الآلة، ضع علامة على نفسك وقم بتسمية أصدقائك للحصول على أفضل تجربة.", - "cLWidgets": "الأدوات المصغرة (Widgets)", - "cLWidgetsDesc": "الأدوات المصغرة للشاشة الرئيسية المدمجة مع الذكريات متاحة الآن. ستعرض لحظاتك الخاصة دون فتح التطبيق.", - "cLFamilyPlan": "حدود الخطة العائلية", - "cLFamilyPlanDesc": "يمكنك الآن تعيين حدود لمقدار التخزين الذي يمكن لأفراد عائلتك استخدامه.", - "cLBulkEdit": "تعديل التواريخ بشكل جماعي", - "cLBulkEditDesc": "يمكنك الآن تحديد صور متعددة، وتعديل التاريخ/الوقت لجميعها بإجراء سريع واحد. تغيير التواريخ مدعوم أيضًا.", "curatedMemories": "ذكريات منسقة", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "memories": "ذكريات", + "deleteMultipleAlbumDialog": "هل تريد أيضًا حذف الصور (والمقاطع) الموجودة في هذه الألبومات {count} من كافة الألبومات الأخرى التي تشترك فيها؟", + "addParticipants": "إضافة مشاركين", + "selectedAlbums": "{count} تم تحديد", + "actionNotSupportedOnFavouritesAlbum": "الإجراء غير مدعوم في ألبوم المفضلة", + "onThisDay": "في هذا اليوم", + "newPhotosEmoji": " جديد 📸", + "happyBirthday": "عيد ميلاد سعيد! 🥳", + "happyBirthdayToPerson": "عيد ميلاد سعيد إلى {name}! 🎉", + "birthdays": "أعياد الميلاد", + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_be.arb b/mobile/lib/l10n/intl_be.arb index 7b254e8083..0971a36afe 100644 --- a/mobile/lib/l10n/intl_be.arb +++ b/mobile/lib/l10n/intl_be.arb @@ -1,7 +1,9 @@ { "@@locale ": "en", "enterYourEmailAddress": "Увядзіце свой адрас электроннай пошты", + "enterYourNewEmailAddress": "Увядзіце ваш новы адрас электроннай пошты", "accountWelcomeBack": "З вяртаннем!", + "emailAlreadyRegistered": "Электронная пошта ўжо зарэгістравана.", "email": "Электронная пошта", "cancel": "Скасаваць", "verify": "Праверыць", @@ -209,10 +211,5 @@ "systemTheme": "Сістэма", "freeTrial": "Бясплатная пробная версія", "faqs": "Частыя пытанні", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_bg.arb b/mobile/lib/l10n/intl_bg.arb index 00a3e71e90..bfa658ba0d 100644 --- a/mobile/lib/l10n/intl_bg.arb +++ b/mobile/lib/l10n/intl_bg.arb @@ -1,9 +1,4 @@ { "@@locale ": "en", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ca.arb b/mobile/lib/l10n/intl_ca.arb index 00a3e71e90..bfa658ba0d 100644 --- a/mobile/lib/l10n/intl_ca.arb +++ b/mobile/lib/l10n/intl_ca.arb @@ -1,9 +1,4 @@ { "@@locale ": "en", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_cs.arb b/mobile/lib/l10n/intl_cs.arb index 762941ec54..a63d72a280 100644 --- a/mobile/lib/l10n/intl_cs.arb +++ b/mobile/lib/l10n/intl_cs.arb @@ -437,13 +437,12 @@ "newRange": "Nový rozsah", "youAndThem": "Vy a {name}", "selfiesWithThem": "Selfie s {name}", - "cLIcon": "Nová ikona", - "cLMemories": "Vzpomínky", - "cLWidgets": "Widgety", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉", + "showMoreFaces": "Show more faces", + "showLessFaces": "Show less faces", + "otherDetectedFaces": "Other detected faces", + "areYouSureRemoveThisFaceFromPerson": "Are you sure you want to remove this face from this person?", + "areThey": "Are they ", + "questionmark": "?", + "saveAsAnotherPerson": "Save as another person" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_da.arb b/mobile/lib/l10n/intl_da.arb index a6b4f4872d..eb92d5168d 100644 --- a/mobile/lib/l10n/intl_da.arb +++ b/mobile/lib/l10n/intl_da.arb @@ -323,10 +323,5 @@ "developerSettingsWarning": "Er du sikker på, at du vil ændre udviklerindstillingerne?", "next": "Næste", "enterPin": "Indtast PIN", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_de.arb b/mobile/lib/l10n/intl_de.arb index cf0761aba6..3f012a2e6e 100644 --- a/mobile/lib/l10n/intl_de.arb +++ b/mobile/lib/l10n/intl_de.arb @@ -1,6 +1,7 @@ { "@@locale ": "en", "enterYourEmailAddress": "Gib deine E-Mail-Adresse ein", + "enterYourNewEmailAddress": "Gib Deine neue E-Mail-Adresse ein", "accountWelcomeBack": "Willkommen zurück!", "emailAlreadyRegistered": "E-Mail ist bereits registriert.", "emailNotRegistered": "E-Mail nicht registriert.", @@ -1662,6 +1663,7 @@ "@linkPersonCaption": { "description": "Caption for the 'Link person' title. It should be a continuation of the 'Link person' title. Just like how 'Link person' + 'for better sharing experience' forms a proper sentence in English, the combination of these two strings should also be a proper sentence in other languages." }, + "videoStreaming": "Streambare Videos", "processingVideos": "Verarbeite Videos", "streamDetails": "Stream-Details", "processing": "In Bearbeitung", @@ -1728,21 +1730,44 @@ "onTheRoad": "Wieder unterwegs", "food": "Kulinarische Genüsse", "pets": "Pelzige Begleiter", - "cLIcon": "Neues Icon", - "cLIconDesc": "Endlich ein neues App-Icon, das unserer Meinung nach unser Werk am besten repräsentiert. Zudem ist es möglich, weiterhin das alte App-Icon zu verwenden.", - "cLMemories": "Erinnerungen", - "cLMemoriesDesc": "Entdecke Deine besonderen Momente neu – Spot auf Deine liebsten Personen, Deine Reisen und Urlaube, Deine besten Schnappschüsse und vieles mehr. Aktiviere das maschinelle Lernen, tagge Dich selbst und benenne Deine Freunde für die besten Ergebnisse.", - "cLWidgets": "Widgets", - "cLWidgetsDesc": "Homescreen-Widgets mit integrierten Erinnerungen sind nun verfügbar. Sie zeigen dir deine besonderen Momente an, ohne die App zu öffnen.", - "cLFamilyPlan": "Obergrenzen für den Familientarif", - "cLFamilyPlanDesc": "Du kannst jetzt festlegen, wie viel Speicherplatz deine Familienmitglieder nutzen können.", - "cLBulkEdit": "Massenbearbeitung von Datumsangaben", - "cLBulkEditDesc": "Du kannst jetzt mehrere Fotos auswählen, und das Datum/Uhrzeit für alle mit einer Aktion ändern. Das Verschieben von Daten wird auch unterstützt.", "curatedMemories": "Ausgewählte Erinnerungen", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "widgets": "Widgets", + "memories": "Erinnerungen", + "peopleWidgetDesc": "Wähle die Personen, die du auf der Startseite sehen möchtest.", + "albumsWidgetDesc": "Wähle die Alben, die du auf der Startseite sehen möchtest.", + "memoriesWidgetDesc": "Wähle die Arten von Erinnerungen, die du auf der Startseite sehen möchtest.", + "smartMemories": "Smarte Erinnerungen", + "pastYearsMemories": "Erinnerungen der letzten Jahre", + "deleteMultipleAlbumDialog": "Sollen die Fotos (und Videos) aus diesen {count} Alben auch aus allen anderen Alben gelöscht werden, in denen sie enthalten sind?", + "addParticipants": "Teilnehmer hinzufügen", + "selectedAlbums": "{count} ausgewählt", + "actionNotSupportedOnFavouritesAlbum": "Aktion für das Favoritenalbum nicht unterstützt", + "onThisDayMemories": "Erinnerungen an diesem Tag", + "onThisDay": "An diesem Tag", + "lookBackOnYourMemories": "Schau zurück auf deine Erinnerungen 🌄", + "newPhotosEmoji": " neue 📸", + "sorryWeHadToPauseYourBackups": "Entschuldigung, wir mussten deine Sicherungen pausieren", + "clickToInstallOurBestVersionYet": "Klicke, um unsere bisher beste Version zu installieren", + "onThisDayNotificationExplanation": "Erhalte Erinnerungen von diesem Tag in den vergangenen Jahren.", + "addMemoriesWidgetPrompt": "Füge ein Erinnerungs-Widget zu deiner Startseite hinzu und komm hierher zurück, um es anzupassen.", + "addAlbumWidgetPrompt": "Füge ein Alben-Widget zu deiner Startseite hinzu und komm hierher zurück, um es anzupassen.", + "addPeopleWidgetPrompt": "Füge ein Personen-Widget zu deiner Startseite hinzu und komm hierher zurück, um es anzupassen.", + "birthdayNotifications": "Geburtstagsbenachrichtigungen", + "receiveRemindersOnBirthdays": "Erhalte Erinnerungen, wenn jemand Geburtstag hat. Ein Klick auf die Benachrichtigung bringt dich zu den Fotos der Person, die Geburtstag hat.", + "happyBirthday": "Herzlichen Glückwunsch zum Geburtstag! 🥳", + "happyBirthdayToPerson": "Alles Gutes zum Geburtstag an {name}! 🎉", + "birthdays": "Geburtstage", + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉", + "cLTitle1": "Upload großer Videodateien", + "cLDesc1": "Nach der Video-Streaming-Beta und der Arbeit an fortsetzbaren Uploads und Downloads haben wir das Datei-Upload-Limit auf 10 GB erhöht. Dies ist jetzt sowohl in Desktop- als auch in mobilen Apps verfügbar.", + "cLTitle2": "Hintergrund-Upload", + "cLDesc2": "Hintergrund-Uploads werden jetzt auch auf iOS unterstützt, zusätzlich zu Android-Geräten. Du musst die App nicht öffnen, um deine neuesten Fotos und Videos zu sichern.", + "cLTitle3": "Autoplay-Erinnerungen", + "cLDesc3": "Wir haben erhebliche Verbesserungen an unserer Erinnerungserfahrung vorgenommen, einschließlich Autoplay, Wischen zur nächsten Erinnerung und vieles mehr.", + "cLTitle4": "Verbesserte Gesichtserkennung", + "cLDesc4": "Zusammen mit vielen internen Verbesserungen ist es jetzt viel einfacher, alle erkannten Gesichter zu sehen, Feedback zu ähnlichen Gesichtern zu geben und Gesichter zu einem einzelnen Foto hinzuzufügen/zu entfernen.", + "cLTitle5": "Geburtstags-Benachrichtigungen", + "cLDesc5": "Du erhältst jetzt eine optionale Benachrichtigung für alle Geburtstage, die du auf Ente gespeichert hast, zusammen mit einer Sammlung ihrer besten Fotos.", + "cLTitle6": "Fortsetzbare Uploads und Downloads", + "cLDesc6": "Kein Warten mehr darauf, dass Uploads/Downloads abgeschlossen werden, bevor du die App schließen kannst. Alle Uploads und Downloads können jetzt mitten im Vorgang pausiert und von dort fortgesetzt werden, wo du aufgehört hast." } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_el.arb b/mobile/lib/l10n/intl_el.arb index c1d4422188..5cdbdb9968 100644 --- a/mobile/lib/l10n/intl_el.arb +++ b/mobile/lib/l10n/intl_el.arb @@ -1,10 +1,5 @@ { "@@locale ": "en", "enterYourEmailAddress": "Εισάγετε την διεύθυνση ηλ. ταχυδρομείου σας", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_en.arb b/mobile/lib/l10n/intl_en.arb index c6711a6996..121c65bb63 100644 --- a/mobile/lib/l10n/intl_en.arb +++ b/mobile/lib/l10n/intl_en.arb @@ -1751,5 +1751,42 @@ "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years.", "addMemoriesWidgetPrompt": "Add a memories widget to your homescreen and come back here to customize.", "addAlbumWidgetPrompt": "Add an album widget to your homescreen and come back here to customize.", - "addPeopleWidgetPrompt": "Add a people widget to your homescreen and come back here to customize." -} \ No newline at end of file + "addPeopleWidgetPrompt": "Add a people widget to your homescreen and come back here to customize.", + "birthdayNotifications": "Birthday notifications", + "receiveRemindersOnBirthdays": "Receive reminders when it's someone's birthday. Tapping on the notification will take you to photos of the birthday person.", + "happyBirthday": "Happy birthday! 🥳", + "birthdays": "Birthdays", + "wishThemAHappyBirthday": "Wish {name} a happy birthday! 🎉", + "areYouSureRemoveThisFaceFromPerson": "Are you sure you want to remove this face from this person?", + "otherDetectedFaces": "Other detected faces", + "areThey": "Are they ", + "questionmark": "?", + "saveAsAnotherPerson": "Save as another person", + "showLessFaces": "Show less faces", + "showMoreFaces": "Show more faces", + "ignore": "Ignore", + "merge": "Merge", + "reset": "Reset", + "areYouSureYouWantToIgnoreThisPerson": "Are you sure you want to ignore this person?", + "areYouSureYouWantToIgnoreThesePersons": "Are you sure you want to ignore these persons?", + "thePersonGroupsWillNotBeDisplayed": "The person groups will not be displayed in the people section anymore. Photos will remain untouched.", + "thePersonWillNotBeDisplayed": "The person will not be displayed in the people section anymore. Photos will remain untouched.", + "areYouSureYouWantToMergeThem": "Are you sure you want to merge them?", + "allUnnamedGroupsWillBeMergedIntoTheSelectedPerson": "All unnamed groups will be merged into the selected person. This can still be undone from the suggestions history overview of the person.", + "yesIgnore": "Yes, ignore", + "same": "Same", + "different": "Different", + "sameperson": "Same person?", + "cLTitle1": "Uploading Large Video Files", + "cLDesc1": "On the back of video streaming beta, and work on resumable uploads and downloads, we have now increased the file upload limit to 10GB. This is now available in both desktop and mobile apps.", + "cLTitle2": "Background Upload", + "cLDesc2": "Background uploads are now supported on iOS as well, in addition to Android devices. No need to open the app to backup your latest photos and videos.", + "cLTitle3": "Autoplay Memories", + "cLDesc3": "We have made significant improvements to our memories experience, including autoplay, swipe to next memory and a lot more.", + "cLTitle4": "Improved Face Recognition", + "cLDesc4": "Along with a bunch of under the hood improvements, now its much easier to see all detected faces, provide feedback on similar faces, and add/remove faces from a single photo.", + "cLTitle5": "Birthday Notifications", + "cLDesc5": "You will now receive an opt-out notification for all the birthdays your have saved on Ente, along with a collection of their best photos.", + "cLTitle6": "Resumable Uploads and Downloads", + "cLDesc6": "No more waiting for uploads/downloads to complete before you can close the app. All uploads and downloads now have the ability to be paused midway, and resume from where you left off." +} diff --git a/mobile/lib/l10n/intl_es.arb b/mobile/lib/l10n/intl_es.arb index dedaff19bb..a3d910ac85 100644 --- a/mobile/lib/l10n/intl_es.arb +++ b/mobile/lib/l10n/intl_es.arb @@ -1724,21 +1724,18 @@ "onTheRoad": "De nuevo en la carretera", "food": "Delicia culinaria", "pets": "Compañeros peludos", - "cLIcon": "Nuevo ícono", - "cLIconDesc": "Por fin, un nuevo icono de la aplicación, que creemos que representa mejor nuestro trabajo. También hemos añadido una opción para que puedas seguir utilizando el icono anterior.", - "cLMemories": "Recuerdos", - "cLMemoriesDesc": "Redescubre tus momentos especiales: enfócate en tu gente favorita, tus viajes y vacaciones, tus mejores clics, y mucho más. Activa el aprendizaje de automático, etiquétate a ti mismo y etiqueta a tus amigos para la mejor experiencia.", - "cLWidgets": "Widgets", - "cLWidgetsDesc": "Ya están disponibles los widgets de pantalla de inicio con tus recuerdos. Podrás ver tus momentos especiales sin abrir la aplicación.", - "cLFamilyPlan": "Límites de plan familiar", - "cLFamilyPlanDesc": "Ahora puede establecer límites en cuanto al almacenamiento que los miembros de tu familia pueden utilizar.", - "cLBulkEdit": "Edición masiva de fechas", - "cLBulkEditDesc": "Ahora puedes seleccionar múltiples fotos y editar la fecha/hora para todas ellas con una acción rápida. También es posible cambiar las fechas.", "curatedMemories": "Memorias revisadas", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉", + "cLTitle1": "Subida de archivos de video grandes", + "cLDesc1": "Tras el lanzamiento de la versión beta de transmisión de video y el trabajo en subidas y descargas reanudables, ahora hemos aumentado el límite de subida de archivos a 10GB. Esto ya está disponible tanto en aplicaciones de escritorio como móviles.", + "cLTitle2": "Subida en segundo plano", + "cLDesc2": "Las subidas en segundo plano ahora también son compatibles con iOS, además de dispositivos Android. No necesitas abrir la aplicación para hacer una copia de seguridad de tus fotos y videos más recientes.", + "cLTitle3": "Reproducción automática de recuerdos", + "cLDesc3": "Hemos hecho mejoras significativas en nuestra experiencia de recuerdos, incluyendo reproducción automática, deslizar al siguiente recuerdo y mucho más.", + "cLTitle4": "Reconocimiento facial mejorado", + "cLDesc4": "Junto con un montón de mejoras internas, ahora es mucho más fácil ver todas las caras detectadas, proporcionar comentarios sobre caras similares y agregar/eliminar caras de una sola foto.", + "cLTitle5": "Notificaciones de cumpleaños", + "cLDesc5": "Ahora recibirás una notificación opcional para todos los cumpleaños que hayas guardado en Ente, junto con una colección de sus mejores fotos.", + "cLTitle6": "Subidas y descargas reanudables", + "cLDesc6": "No más esperas para que se completen las subidas/descargas antes de poder cerrar la aplicación. Todas las subidas y descargas ahora tienen la capacidad de pausarse a mitad de camino y reanudarse desde donde lo dejaste." } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_et.arb b/mobile/lib/l10n/intl_et.arb index 1fd198de38..6c5cdfdbd9 100644 --- a/mobile/lib/l10n/intl_et.arb +++ b/mobile/lib/l10n/intl_et.arb @@ -219,10 +219,5 @@ "@storageBreakupYou": { "description": "Label to indicate how much storage you are using when you are part of a family plan" }, - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_eu.arb b/mobile/lib/l10n/intl_eu.arb index d7e4e63e2b..7666621081 100644 --- a/mobile/lib/l10n/intl_eu.arb +++ b/mobile/lib/l10n/intl_eu.arb @@ -459,10 +459,5 @@ "@iOSLockOut": { "description": "Message advising the user to re-enable biometrics on their device. It shows in a dialog on iOS side." }, - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_fa.arb b/mobile/lib/l10n/intl_fa.arb index 67313ebc71..083c8b449b 100644 --- a/mobile/lib/l10n/intl_fa.arb +++ b/mobile/lib/l10n/intl_fa.arb @@ -308,10 +308,5 @@ "search": "جستجو", "whatsNew": "تغییرات جدید", "reviewSuggestions": "مرور پیشنهادها", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_fr.arb b/mobile/lib/l10n/intl_fr.arb index 37728a70f6..0eba0c5291 100644 --- a/mobile/lib/l10n/intl_fr.arb +++ b/mobile/lib/l10n/intl_fr.arb @@ -1,6 +1,7 @@ { "@@locale ": "en", "enterYourEmailAddress": "Entrez votre adresse e-mail", + "enterYourNewEmailAddress": "Entrez votre nouvelle adresse e-mail", "accountWelcomeBack": "Bon retour parmi nous !", "emailAlreadyRegistered": "Email déjà enregistré.", "emailNotRegistered": "E-mail non enregistré.", @@ -721,6 +722,7 @@ "type": "text" }, "backupFailed": "Échec de la sauvegarde", + "sorryBackupFailedDesc": "Désolé, nous n'avons pas pu sauvegarder ce fichier maintenant, nous allons réessayer plus tard.", "couldNotBackUpTryLater": "Nous n'avons pas pu sauvegarder vos données.\nNous allons réessayer plus tard.", "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": "Ente peut chiffrer et conserver des fichiers que si vous leur accordez l'accès", "pleaseGrantPermissions": "Veuillez accorder la permission", @@ -792,6 +794,14 @@ "share": "Partager", "unhideToAlbum": "Afficher dans l'album", "restoreToAlbum": "Restaurer vers l'album", + "moveItem": "{count, plural,=1 {Déplacer un élément} other {Déplacer des éléments}}", + "@moveItem": { + "description": "Page title while moving one or more items to an album" + }, + "addItem": "{count, plural, =1 {Ajouter un élément} other {Ajouter des éléments}}", + "@addItem": { + "description": "Page title while adding one or more items to album" + }, "createOrSelectAlbum": "Créez ou sélectionnez un album", "selectAlbum": "Sélectionner album", "searchByAlbumNameHint": "Nom de l'album", @@ -889,6 +899,7 @@ "authToViewYourMemories": "Authentifiez-vous pour voir vos souvenirs", "unlock": "Déverrouiller", "freeUpSpace": "Libérer de l'espace", + "freeUpSpaceSaving": "{count, plural, =1 {Il peut être supprimé de l'appareil pour libérer {formattedSize}} other {Ils peuvent être supprimés de l'appareil pour libérer {formattedSize}}}", "filesBackedUpInAlbum": "{count, plural, one {1 fichier dans cet album a été sauvegardé en toute sécurité} other {{formattedNumber} fichiers dans cet album ont été sauvegardés en toute sécurité}}", "@filesBackedUpInAlbum": { "description": "Text to tell user how many files have been backed up in the album", @@ -919,6 +930,18 @@ } } }, + "@freeUpSpaceSaving": { + "description": "Text to tell user how much space they can free up by deleting items from the device" + }, + "freeUpAccessPostDelete": "Vous pouvez toujours {count, plural, =1 {l'} other {les}} accéder sur Ente tant que vous avez un abonnement actif", + "@freeUpAccessPostDelete": { + "placeholders": { + "count": { + "example": "1", + "type": "int" + } + } + }, "freeUpAmount": "Libérer {sizeInMBorGB}", "thisEmailIsAlreadyInUse": "Cette adresse mail est déjà utilisé", "incorrectCode": "Code non valide", @@ -1008,6 +1031,7 @@ "didYouKnow": "Le savais-tu ?", "loadingMessage": "Chargement de vos photos...", "loadMessage1": "Vous pouvez partager votre abonnement avec votre famille", + "loadMessage2": "Nous avons préservé plus de 200 millions de souvenirs jusqu'à présent", "loadMessage3": "Nous conservons 3 copies de vos données, l'une dans un abri anti-atomique", "loadMessage4": "Toutes nos applications sont open source", "loadMessage5": "Notre code source et notre cryptographie ont été audités en externe", @@ -1245,6 +1269,8 @@ "description": "Subtitle to indicate that the user can find people quickly by name" }, "findPeopleByName": "Trouver des personnes rapidement par leur nom", + "addViewers": "{count, plural, =0 {Ajouter un spectateur} =1 {Ajouter une spectateur} other {Ajouter des spectateurs}}", + "addCollaborators": "{count, plural, =0 {Ajouter un collaborateur} =1 {Ajouter un collaborateur} other {Ajouter des collaborateurs}}", "longPressAnEmailToVerifyEndToEndEncryption": "Appuyez longuement sur un email pour vérifier le chiffrement de bout en bout.", "developerSettingsWarning": "Êtes-vous sûr de vouloir modifier les paramètres du développeur ?", "developerSettings": "Paramètres du développeur", @@ -1256,6 +1282,7 @@ "createCollaborativeLink": "Créer un lien collaboratif", "search": "Rechercher", "enterPersonName": "Entrez le nom d'une personne", + "editEmailAlreadyLinked": "Cet e-mail est déjà lié à {name}.", "viewPersonToUnlink": "Voir {name} pour délier", "enterName": "Saisir un nom", "savePerson": "Enregistrer la personne", @@ -1377,6 +1404,16 @@ "enableMachineLearningBanner": "Activer l'apprentissage automatique pour la reconnaissance des visages et la recherche magique", "searchDiscoverEmptySection": "Les images seront affichées ici une fois le traitement terminé", "searchPersonsEmptySection": "Les personnes seront affichées ici une fois le traitement terminé", + "viewersSuccessfullyAdded": "{count, plural, =0 {0 spectateur ajouté} =1 {Un spectateur ajouté} other {{count} spectateurs ajoutés}}", + "@viewersSuccessfullyAdded": { + "placeholders": { + "count": { + "type": "int", + "example": "2" + } + }, + "description": "Number of viewers that were successfully added to an album." + }, "collaboratorsSuccessfullyAdded": "{count, plural, =0 {0 collaborateur ajouté} =1 {1 collaborateur ajouté} other {{count} collaborateurs ajoutés}}", "@collaboratorsSuccessfullyAdded": { "placeholders": { @@ -1452,6 +1489,15 @@ }, "currentlyRunning": "en cours d'exécution", "ignored": "ignoré", + "photosCount": "{count, plural, =0 {0 photo} =1 {1 photo} other {{count} photos}}", + "@photosCount": { + "placeholders": { + "count": { + "type": "int", + "example": "2" + } + } + }, "file": "Fichier", "searchSectionsLengthMismatch": "Incompatibilité de longueur des sections : {snapshotLength} != {searchLength}", "@searchSectionsLengthMismatch": { @@ -1617,6 +1663,7 @@ "@linkPersonCaption": { "description": "Caption for the 'Link person' title. It should be a continuation of the 'Link person' title. Just like how 'Link person' + 'for better sharing experience' forms a proper sentence in English, the combination of these two strings should also be a proper sentence in other languages." }, + "videoStreaming": "Vidéos diffusables", "processingVideos": "Traitement des vidéos", "streamDetails": "Détails du stream", "processing": "Traitement en cours", @@ -1683,21 +1730,44 @@ "onTheRoad": "De nouveau sur la route", "food": "Plaisir culinaire", "pets": "Compagnons à quatre pattes", - "cLIcon": "Nouvel icône", - "cLIconDesc": "Finalement, création d'un nouvel icône d'application qui, selon nous, représente au mieux notre travail. Nous avons également ajouté un changeur d'icône pour que vous puissiez continuer à utiliser l'ancien.", - "cLMemories": "Souvenirs", - "cLMemoriesDesc": "Redécouvrez vos précieux souvenirs - focus sur vos connaissances préférées, vos voyages et vos vacances, vos meilleurs clics et bien plus encore. Activez l'apprentissage automatique, taguez-vous et nommez vos amis pour une meilleure expérience.", - "cLWidgets": "Widgets", - "cLWidgetsDesc": "Les widgets (ou gadgets) de l'écran d'accueil, qui sont intégrés à des souvenirs, sont maintenant disponibles. Ils montreront vos moments spéciaux sans nécessité d'ouvrir l'application.", - "cLFamilyPlan": "Limites pour le forfait Famille", - "cLFamilyPlanDesc": "Vous pouvez maintenant fixer des limites sur la quantité de stockage que les membres de votre famille peuvent utiliser.", - "cLBulkEdit": "Dates de modification multiples", - "cLBulkEditDesc": "Vous pouvez maintenant sélectionner plusieurs photos et modifier la date/heure pour toutes celles-ci, en une seule action rapide. Les dates de décalage sont également prises en charge.", "curatedMemories": "Souvenirs conservés", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "widgets": "Gadgets", + "memories": "Souvenirs", + "peopleWidgetDesc": "Sélectionnez les personnes que vous souhaitez voir sur votre écran d'accueil.", + "albumsWidgetDesc": "Sélectionnez les personnes que vous souhaitez voir sur votre écran d'accueil.", + "memoriesWidgetDesc": "Sélectionnez le type de souvenirs que vous souhaitez voir sur votre écran d'accueil.", + "smartMemories": "Souvenirs intelligents", + "pastYearsMemories": "Souvenirs de ces dernières années", + "deleteMultipleAlbumDialog": "Supprimer également les photos (et les vidéos) présentes dans ces {count} albums de tous les autres albums dont ils font partie ?", + "addParticipants": "Ajouter des participants", + "selectedAlbums": "{count} sélectionné(s)", + "actionNotSupportedOnFavouritesAlbum": "Action non prise en charge sur l'album des Favoris", + "onThisDayMemories": "Souvenirs du jour", + "onThisDay": "Ce jour-ci", + "lookBackOnYourMemories": "Regarde tes souvenirs passés 🌄", + "newPhotosEmoji": " nouveau 📸", + "sorryWeHadToPauseYourBackups": "Désolé, nous avons dû mettre en pause vos sauvegardes", + "clickToInstallOurBestVersionYet": "Cliquez pour installer notre meilleure version", + "onThisDayNotificationExplanation": "Recevoir des rappels sur les souvenirs de cette journée des années précédentes.", + "addMemoriesWidgetPrompt": "Ajoutez un gadget des souvenirs à votre écran d'accueil et revenez ici pour le personnaliser.", + "addAlbumWidgetPrompt": "Ajoutez un gadget d'album à votre écran d'accueil et revenez ici pour le personnaliser.", + "addPeopleWidgetPrompt": "Ajoutez un gadget des personnes à votre écran d'accueil et revenez ici pour le personnaliser.", + "birthdayNotifications": "Notifications d’anniversaire", + "receiveRemindersOnBirthdays": "Recevoir des rappels quand c'est l'anniversaire de quelqu'un. Appuyer sur la notification vous amènera à des photos de son anniversaire.", + "happyBirthday": "Joyeux anniversaire ! 🥳", + "happyBirthdayToPerson": "Joyeux anniversaire {name}! 🎉", + "birthdays": "Anniversaires", + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉", + "cLTitle1": "Téléchargement de fichiers vidéo volumineux", + "cLDesc1": "Suite à la version bêta du streaming vidéo et au travail sur les téléchargements reprenables, nous avons maintenant augmenté la limite de téléchargement de fichiers à 10 Go. Ceci est maintenant disponible dans les applications desktop et mobiles.", + "cLTitle2": "Téléchargement en arrière-plan", + "cLDesc2": "Les téléchargements en arrière-plan sont maintenant pris en charge sur iOS également, en plus des appareils Android. Pas besoin d'ouvrir l'application pour sauvegarder vos dernières photos et vidéos.", + "cLTitle3": "Lecture automatique des souvenirs", + "cLDesc3": "Nous avons apporté des améliorations significatives à notre expérience de souvenirs, y compris la lecture automatique, le balayage vers le souvenir suivant et bien plus encore.", + "cLTitle4": "Reconnaissance faciale améliorée", + "cLDesc4": "Avec un tas d'améliorations internes, il est maintenant beaucoup plus facile de voir tous les visages détectés, de donner des commentaires sur les visages similaires et d'ajouter/supprimer des visages d'une seule photo.", + "cLTitle5": "Notifications d'anniversaire", + "cLDesc5": "Vous recevrez maintenant une notification optionnelle pour tous les anniversaires que vous avez sauvegardés sur Ente, ainsi qu'une collection de leurs meilleures photos.", + "cLTitle6": "Téléchargements reprenables", + "cLDesc6": "Plus besoin d'attendre que les téléchargements se terminent avant de pouvoir fermer l'application. Tous les téléchargements ont maintenant la capacité d'être mis en pause à mi-chemin et de reprendre là où vous vous êtes arrêté." } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_gu.arb b/mobile/lib/l10n/intl_gu.arb index 00a3e71e90..bfa658ba0d 100644 --- a/mobile/lib/l10n/intl_gu.arb +++ b/mobile/lib/l10n/intl_gu.arb @@ -1,9 +1,4 @@ { "@@locale ": "en", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_he.arb b/mobile/lib/l10n/intl_he.arb index 46631e6473..a87335344f 100644 --- a/mobile/lib/l10n/intl_he.arb +++ b/mobile/lib/l10n/intl_he.arb @@ -389,8 +389,8 @@ "selectAll": "בחר הכל", "skip": "דלג", "updatingFolderSelection": "מעדכן את בחירת התיקיות...", - "itemCount": "{count, plural, one{{count} פריט} two {{count} פריטים} many {{count} פריטים} other{{count} פריטים}}", - "deleteItemCount": "{count, plural, =1 {מחק {count} פריט} two {מחק {count} פריטים} other {מחק {count} פריטים}}", + "itemCount": "{count, plural, one{{count} פריט} other{{count} פריטים}}", + "deleteItemCount": "{count, plural, =1 {מחק {count} פריט} other {מחק {count} פריטים}}", "duplicateItemsGroup": "{count} קבצים, כל אחד {formattedSize}", "@duplicateItemsGroup": { "description": "Display the number of duplicate files and their size", @@ -407,7 +407,7 @@ } }, "showMemories": "הצג זכרונות", - "yearsAgo": "{count, plural, one{לפני {count} שנה} two {לפני {count} שנים} many {לפני {count} שנים} other{לפני {count} שנים}}", + "yearsAgo": "{count, plural, one{לפני {count} שנה} other{לפני {count} שנים}}", "backupSettings": "הגדרות גיבוי", "backupOverMobileData": "גבה על רשת סלולרית", "backupVideos": "גבה סרטונים", @@ -792,10 +792,5 @@ "create": "צור", "viewAll": "הצג הכל", "hiding": "מחביא...", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_hi.arb b/mobile/lib/l10n/intl_hi.arb index cb3d6271b1..a139c7d33a 100644 --- a/mobile/lib/l10n/intl_hi.arb +++ b/mobile/lib/l10n/intl_hi.arb @@ -49,10 +49,5 @@ "noRecoveryKeyNoDecryption": "हमारे एंड-टू-एंड एन्क्रिप्शन प्रोटोकॉल की प्रकृति के कारण, आपके डेटा को आपके पासवर्ड या रिकवरी कुंजी के बिना डिक्रिप्ट नहीं किया जा सकता है", "verifyEmail": "ईमेल सत्यापित करें", "toResetVerifyEmail": "अपना पासवर्ड रीसेट करने के लिए, कृपया पहले अपना ईमेल सत्यापित करें।", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_hu.arb b/mobile/lib/l10n/intl_hu.arb index b3fe594370..34473f1582 100644 --- a/mobile/lib/l10n/intl_hu.arb +++ b/mobile/lib/l10n/intl_hu.arb @@ -11,10 +11,5 @@ "askDeleteReason": "Miért törli a fiókját?", "deleteAccountFeedbackPrompt": "Sajnáljuk, hogy távozik. Kérjük, ossza meg velünk visszajelzéseit, hogy segítsen nekünk a fejlődésben.", "feedback": "Visszajelzés", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_id.arb b/mobile/lib/l10n/intl_id.arb index 1b0c31e36e..901c3225b1 100644 --- a/mobile/lib/l10n/intl_id.arb +++ b/mobile/lib/l10n/intl_id.arb @@ -1,7 +1,10 @@ { "@@locale ": "en", "enterYourEmailAddress": "Masukkan alamat email kamu", + "enterYourNewEmailAddress": "Masukkan alamat email baru anda", "accountWelcomeBack": "Selamat datang kembali!", + "emailAlreadyRegistered": "Email sudah terdaftar.", + "emailNotRegistered": "Email belum terdaftar.", "email": "Email", "cancel": "Batal", "verify": "Verifikasi", @@ -328,6 +331,7 @@ "removingFromFavorites": "Menghapus dari favorit...", "sorryCouldNotAddToFavorites": "Maaf, tidak dapat menambahkan ke favorit!", "sorryCouldNotRemoveFromFavorites": "Maaf, tidak dapat menghapus dari favorit!", + "subscribeToEnableSharing": "Anda memerlukan langganan berbayar yang aktif untuk bisa berbagi.", "subscribe": "Berlangganan", "canOnlyRemoveFilesOwnedByYou": "Hanya dapat menghapus berkas yang dimiliki oleh mu", "deleteSharedAlbum": "Hapus album bersama?", @@ -397,6 +401,8 @@ "description": "The text to display in the advanced settings section" }, "photoGridSize": "Ukuran kotak foto", + "manageDeviceStorage": "Mengelola cache perangkat", + "manageDeviceStorageDesc": "Tinjau dan hapus penyimpanan cache lokal.", "machineLearning": "Pemelajaran mesin", "mlConsent": "Aktifkan pemelajaran mesin", "mlConsentTitle": "Aktifkan pemelajaran mesin?", @@ -404,8 +410,13 @@ "mlConsentPrivacy": "Klik di sini untuk detail lebih lanjut tentang fitur ini pada kebijakan privasi kami", "mlConsentConfirmation": "Saya memahami, dan bersedia mengaktifkan pemelajaran mesin", "magicSearch": "Penelusuran ajaib", + "discover": "Temukan", + "@discover": { + "description": "The text to display for the discover section under which we show receipts, screenshots, sunsets, greenery, etc." + }, "discover_identity": "Identitas", "discover_screenshots": "Tangkapan layar", + "discover_receipts": "Tanda Terima", "discover_notes": "Catatan", "discover_memes": "Meme", "discover_babies": "Bayi", @@ -413,6 +424,7 @@ "discover_selfies": "Swafoto", "discover_wallpapers": "Gambar latar", "discover_food": "Makanan", + "discover_celebrations": "Perayaan", "discover_sunset": "Senja", "discover_hills": "Bukit", "mlIndexingDescription": "Perlu diperhatikan bahwa pemelajaran mesin dapat meningkatkan penggunaan data dan baterai perangkat hingga seluruh item selesai terindeks. Gunakan aplikasi desktop untuk pengindeksan lebih cepat, seluruh hasil akan tersinkronkan secara otomatis.", @@ -647,6 +659,8 @@ "startBackup": "Mulai pencadangan", "noPhotosAreBeingBackedUpRightNow": "Tidak ada foto yang sedang dicadangkan sekarang", "grantFullAccessPrompt": "Harap berikan akses ke semua foto di app Pengaturan", + "allowPermTitle": "Izinkan akses ke foto", + "allowPermBody": "Ijinkan akses ke foto Anda dari Pengaturan agar Ente dapat menampilkan dan mencadangkan pustaka Anda.", "openSettings": "Buka Pengaturan", "selectMorePhotos": "Pilih lebih banyak foto", "existingUser": "Masuk", @@ -672,6 +686,7 @@ "type": "text" }, "backupFailed": "Pencadangan gagal", + "sorryBackupFailedDesc": "Maaf, kami tidak dapat mencadangkan berkas ini sekarang, kami akan mencobanya kembali nanti.", "couldNotBackUpTryLater": "Kami tidak dapat mencadangkan data kamu.\nKami akan coba lagi nanti.", "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": "Ente hanya dapat mengenkripsi dan menyimpan file jika kamu berikan izin", "pleaseGrantPermissions": "Harap berikan izin", @@ -1097,10 +1112,5 @@ "left": "Kiri", "right": "Kanan", "whatsNew": "Hal yang baru", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_it.arb b/mobile/lib/l10n/intl_it.arb index 15f3e6aae5..5665592fdb 100644 --- a/mobile/lib/l10n/intl_it.arb +++ b/mobile/lib/l10n/intl_it.arb @@ -1,6 +1,7 @@ { "@@locale ": "en", "enterYourEmailAddress": "Inserisci il tuo indirizzo email", + "enterYourNewEmailAddress": "Inserisci il tuo nuovo indirizzo email", "accountWelcomeBack": "Bentornato!", "emailAlreadyRegistered": "Email già registrata.", "emailNotRegistered": "Email non registrata.", @@ -371,6 +372,21 @@ "deleteFromBoth": "Elimina da entrambi", "newAlbum": "Nuovo album", "albums": "Album", + "memoryCount": "{count, plural, =0{nessun ricordo} one{{formattedCount} ricordo} other{{formattedCount} ricordi}}", + "@memoryCount": { + "description": "The text to display the number of memories", + "type": "text", + "placeholders": { + "count": { + "example": "1", + "type": "int" + }, + "formattedCount": { + "type": "String", + "example": "11.513, 11,511" + } + } + }, "selectedPhotos": "{count} selezionati", "@selectedPhotos": { "description": "Display the number of selected photos", @@ -510,6 +526,7 @@ "viewLargeFiles": "File di grandi dimensioni", "viewLargeFilesDesc": "Visualizza i file che stanno occupando la maggior parte dello spazio di archiviazione.", "noDuplicates": "✨ Nessun doppione", + "youveNoDuplicateFilesThatCanBeCleared": "Non ci sono file duplicati che possono essere eliminati", "success": "Operazione riuscita", "rateUs": "Lascia una recensione", "remindToEmptyDeviceTrash": "Vuota anche \"Cancellati di recente\" da \"Impostazioni\" -> \"Storage\" per avere più spazio libero", @@ -705,6 +722,7 @@ "type": "text" }, "backupFailed": "Backup fallito", + "sorryBackupFailedDesc": "Purtroppo non è stato possibile eseguire il backup del file in questo momento, riproveremo più tardi.", "couldNotBackUpTryLater": "Impossibile eseguire il backup dei tuoi dati.\nRiproveremo più tardi.", "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": "Ente può criptare e conservare i file solo se gliene concedi l'accesso", "pleaseGrantPermissions": "Concedi i permessi", @@ -776,6 +794,14 @@ "share": "Condividi", "unhideToAlbum": "Non nascondere l'album", "restoreToAlbum": "Ripristina l'album", + "moveItem": "{count, plural, =1 {Sposta elemento} other {Sposta elementi}}", + "@moveItem": { + "description": "Page title while moving one or more items to an album" + }, + "addItem": "{count, plural, =1 {Aggiungi elemento} other {Aggiungi elementi}}", + "@addItem": { + "description": "Page title while adding one or more items to album" + }, "createOrSelectAlbum": "Crea o seleziona album", "selectAlbum": "Seleziona album", "searchByAlbumNameHint": "Nome album", @@ -873,6 +899,7 @@ "authToViewYourMemories": "Autenticati per visualizzare le tue foto", "unlock": "Sblocca", "freeUpSpace": "Libera spazio", + "freeUpSpaceSaving": "{count, plural, =1 {Può essere cancellato per liberare {formattedSize}} other {Possono essere cancellati per liberare {formattedSize}}}", "filesBackedUpInAlbum": "{count, plural, one {1 file} other {{formattedNumber} file}} di quest'album sono stati salvati in modo sicuro", "@filesBackedUpInAlbum": { "description": "Text to tell user how many files have been backed up in the album", @@ -903,6 +930,9 @@ } } }, + "@freeUpSpaceSaving": { + "description": "Text to tell user how much space they can free up by deleting items from the device" + }, "freeUpAmount": "Libera {sizeInMBorGB}", "thisEmailIsAlreadyInUse": "Questo indirizzo email è già registrato", "incorrectCode": "Codice sbagliato", @@ -1230,6 +1260,8 @@ "description": "Subtitle to indicate that the user can find people quickly by name" }, "findPeopleByName": "Trova rapidamente le persone per nome", + "addViewers": "{count, plural, =0 {Aggiungi visualizzatore} =1 {Add viewer} other {Aggiungi visualizzatori}}", + "addCollaborators": "{count, plural, =0 {Aggiungi collaboratore} =1 {Aggiungi collaboratore} other {Aggiungi collaboratori}}", "longPressAnEmailToVerifyEndToEndEncryption": "Premi a lungo un'email per verificare la crittografia end to end.", "developerSettingsWarning": "Sei sicuro di voler modificare le Impostazioni sviluppatore?", "developerSettings": "Impostazioni sviluppatore", @@ -1241,9 +1273,12 @@ "createCollaborativeLink": "Crea link collaborativo", "search": "Cerca", "enterPersonName": "Inserisci il nome della persona", + "editEmailAlreadyLinked": "Questa email è già collegata a {name}.", + "viewPersonToUnlink": "Visualizza {name} per scollegare", "enterName": "Aggiungi nome", "savePerson": "Salva persona", "editPerson": "Modifica persona", + "mergedPhotos": "Fotografie unite", "orMergeWithExistingPerson": "O unisci con esistente", "enterDateOfBirth": "Compleanno (Opzionale)", "birthday": "Compleanno", @@ -1350,6 +1385,7 @@ "extraPhotosFound": "Trovate foto aggiuntive", "configuration": "Configurazione", "localIndexing": "Indicizzazione locale", + "processed": "Processato", "resetPerson": "Rimuovi", "areYouSureYouWantToResetThisPerson": "Sei sicuro di voler resettare questa persona?", "allPersonGroupingWillReset": "Tutti i raggruppamenti per questa persona saranno resettati e perderai tutti i suggerimenti fatti per questa persona", @@ -1359,6 +1395,16 @@ "enableMachineLearningBanner": "Abilita l'apprendimento automatico per la ricerca magica e il riconoscimento facciale", "searchDiscoverEmptySection": "Le immagini saranno mostrate qui una volta che l'elaborazione e la sincronizzazione saranno completate", "searchPersonsEmptySection": "Le persone saranno mostrate qui una volta che l'elaborazione e la sincronizzazione saranno completate", + "viewersSuccessfullyAdded": "{count, plural, =0 {Added 0 visualizzatori} =1 {Added 1 visualizzatore} other {Added {count} visualizzatori}}", + "@viewersSuccessfullyAdded": { + "placeholders": { + "count": { + "type": "int", + "example": "2" + } + }, + "description": "Number of viewers that were successfully added to an album." + }, "collaboratorsSuccessfullyAdded": "{count, plural, =0 {Aggiunti 0 collaboratori} =1 {Aggiunto 1 collaboratore} other {Aggiunti {count} collaboratori}}", "@collaboratorsSuccessfullyAdded": { "placeholders": { @@ -1389,6 +1435,15 @@ } } }, + "typeOfGallerGallerytypeIsNotSupportedForRename": "Il tipo di galleria {galleryType} non è supportato per la rinomina", + "@typeOfGallerGallerytypeIsNotSupportedForRename": { + "placeholders": { + "galleryType": { + "type": "String", + "example": "no network" + } + } + }, "tapToUploadIsIgnoredDue": "Tocca per caricare, il caricamento è attualmente ignorato a causa di {ignoreReason}", "@tapToUploadIsIgnoredDue": { "description": "Shown in upload icon widet, inside a tooltip.", @@ -1425,16 +1480,46 @@ }, "currentlyRunning": "attualmente in esecuzione", "ignored": "ignorato", + "photosCount": "{count, plural, =0 {0 foto} =1 {1 foto} other {{count} foto}}", + "@photosCount": { + "placeholders": { + "count": { + "type": "int", + "example": "2" + } + } + }, "file": "File", + "searchSectionsLengthMismatch": "Lunghezza sezioni non corrisponde: {snapshotLength} != {searchLength}", + "@searchSectionsLengthMismatch": { + "description": "Appears in search tab page", + "placeholders": { + "snapshotLength": { + "type": "int", + "example": "1" + }, + "searchLength": { + "type": "int", + "example": "2" + } + } + }, + "selectMailApp": "Seleziona app email", + "selectAllShort": "Tutte", + "@selectAllShort": { + "description": "Text that appears in bottom right when you start to select multiple photos. When clicked, it selects all photos." + }, "selectCoverPhoto": "Seleziona foto di copertina", "newLocation": "Nuova posizione", "faceNotClusteredYet": "Faccia non ancora raggruppata, per favore torna più tardi", + "theLinkYouAreTryingToAccessHasExpired": "Il link a cui stai cercando di accedere è scaduto.", "openFile": "Apri file", "backupFile": "File di backup", "openAlbumInBrowser": "Apri album nel browser", "openAlbumInBrowserTitle": "Utilizza l'app web per aggiungere foto a questo album", "allow": "Consenti", "allowAppToOpenSharedAlbumLinks": "Consenti all'app di aprire link all'album condiviso", + "seePublicAlbumLinksInApp": "Vedi link album pubblici nell'app", "emergencyContacts": "Contatti di emergenza", "acceptTrustInvite": "Accetta l'invito", "declineTrustInvite": "Rifiuta l'invito", @@ -1498,6 +1583,14 @@ "useDifferentPlayerInfo": "Hai problemi a riprodurre questo video? Premi a lungo qui per provare un altro lettore.", "hideSharedItemsFromHomeGallery": "Nascondi gli elementi condivisi dalla galleria principale", "gallery": "Galleria", + "joinAlbum": "Unisciti all'album", + "joinAlbumSubtext": "per visualizzare e aggiungere le tue foto", + "joinAlbumSubtextViewer": "per aggiungerla agli album condivisi", + "join": "Unisciti", + "linkEmail": "Link Email", + "link": "Link", + "noEnteAccountExclamation": "Nessun account Ente!", + "orPickFromYourContacts": "o scegli tra i tuoi contatti", "emailDoesNotHaveEnteAccount": "{email} non ha un account Ente.", "@emailDoesNotHaveEnteAccount": { "description": "Shown when email doesn't have an Ente account", @@ -1531,6 +1624,19 @@ } } }, + "linkPersonToEmailConfirmation": "Questo collegherà {personName} a {email}", + "@linkPersonToEmailConfirmation": { + "description": "Confirmation message when linking a person to an email", + "placeholders": { + "personName": { + "type": "String" + }, + "email": { + "type": "String" + } + } + }, + "selectYourFace": "Seleziona il tuo volto", "reassigningLoading": "Riassegnando...", "reassignedToName": "Riassegnato a {name}", "@reassignedToName": { @@ -1540,6 +1646,7 @@ } } }, + "saveChangesBeforeLeavingQuestion": "Salvare le modifiche prima di uscire?", "dontSave": "Non salvare", "thisIsMeExclamation": "Questo sono io!", "linkPerson": "Collega persona", @@ -1547,12 +1654,111 @@ "@linkPersonCaption": { "description": "Caption for the 'Link person' title. It should be a continuation of the 'Link person' title. Just like how 'Link person' + 'for better sharing experience' forms a proper sentence in English, the combination of these two strings should also be a proper sentence in other languages." }, + "videoStreaming": "Video in streaming", "processingVideos": "Elaborando video", - "onThisDay": "On this day", + "streamDetails": "Dettagli dello streaming", + "processing": "In elaborazione", + "queued": "In coda", + "ineligible": "Non idoneo", + "failed": "Non riuscito", + "playStream": "Riproduci lo streaming", + "playOriginal": "Riproduci originale", "joinAlbumConfirmationDialogBody": "Unirsi a un album renderà visibile la tua email ai suoi partecipanti.", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "pleaseWaitThisWillTakeAWhile": "Attendere, potrebbe volerci un po' di tempo.", + "editTime": "Modifica orario", + "selectTime": "Imposta ora", + "selectDate": "Imposta data", + "previous": "Precedente", + "selectOneDateAndTimeForAll": "Seleziona una data e un'ora per tutti", + "selectStartOfRange": "Seleziona inizio dell'intervallo", + "thisWillMakeTheDateAndTimeOfAllSelected": "In questo modo la data e l'ora di tutte le foto selezionate saranno uguali.", + "allWillShiftRangeBasedOnFirst": "Questo è il primo nel gruppo. Altre foto selezionate si sposteranno automaticamente in base a questa nuova data", + "newRange": "Nuovo intervallo", + "selectOneDateAndTime": "Seleziona data e orario", + "moveSelectedPhotosToOneDate": "Sposta foto selezionate in una data specifica", + "shiftDatesAndTime": "Sposta date e orari", + "photosKeepRelativeTimeDifference": "Le foto mantengono una differenza di tempo relativa", + "photocountPhotos": "{count, plural, =0 {Nessuna foto} =1 {1 foto} other {{count} foto}}", + "@photocountPhotos": { + "placeholders": { + "count": { + "type": "int", + "example": "2" + } + } + }, + "appIcon": "Icona dell'app", + "notThisPerson": "Non è questa persona?", + "selectedItemsWillBeRemovedFromThisPerson": "Gli elementi selezionati verranno rimossi da questa persona, ma non eliminati dalla tua libreria.", + "throughTheYears": "{dateFormat} negli anni", + "thisWeekThroughTheYears": "Questa settimana negli anni", + "thisWeekXYearsAgo": "{count, plural, =1 {Questa settimana, {count} anno fa} other {Questa settimana, {count} anni fa}}", + "youAndThem": "Tu e {name}", + "admiringThem": "Ammirando {name}", + "embracingThem": "Abbracciando {name}", + "partyWithThem": "Festa con {name}", + "hikingWithThem": "Escursioni con {name}", + "feastingWithThem": "Festeggiando con {name}", + "selfiesWithThem": "Selfie con {name}", + "posingWithThem": "In posa con {name}", + "backgroundWithThem": "Bellissimi panorami con {name}", + "sportsWithThem": "Sport con {name}", + "roadtripWithThem": "Viaggio con {name}", + "spotlightOnYourself": "Tu in primo piano", + "spotlightOnThem": "Riflettori su {name}", + "personIsAge": "{name} ha {age}!", + "personTurningAge": "{name} sta per compiere {age} anni", + "lastTimeWithThem": "Ultima volta con {name}", + "tripToLocation": "Viaggio a {location}", + "tripInYear": "Viaggio nel {year}", + "lastYearsTrip": "Viaggio dello scorso anno", + "sunrise": "All'orizzonte", + "mountains": "Oltre le colline", + "greenery": "In mezzo al verde", + "beach": "Sabbia e mare", + "city": "In città", + "moon": "Al chiaro di luna", + "onTheRoad": "Un altro viaggio su strada", + "food": "Delizia culinaria", + "pets": "Compagni pelosetti", + "curatedMemories": "Ricordi importanti", + "widgets": "Widget", + "memories": "Ricordi", + "peopleWidgetDesc": "Seleziona le persone che desideri vedere nella schermata principale.", + "albumsWidgetDesc": "Seleziona gli album che desideri vedere nella schermata principale.", + "memoriesWidgetDesc": "Seleziona il tipo di ricordi che desideri vedere nella schermata principale.", + "smartMemories": "Ricordi intelligenti", + "pastYearsMemories": "Ricordi degli ultimi anni", + "deleteMultipleAlbumDialog": "Eliminare anche le foto (e i video) presenti su {count} album da tutti gli altri album di cui fanno parte?", + "addParticipants": "Aggiungi Partecipanti", + "selectedAlbums": "{count} selezionati", + "actionNotSupportedOnFavouritesAlbum": "Questa azione non è supportata nei Preferiti", + "onThisDayMemories": "Ricordi di questo giorno", + "onThisDay": "In questo giorno", + "lookBackOnYourMemories": "Rivivi i tuoi ricordi 🌄", + "newPhotosEmoji": " nuova 📸", + "sorryWeHadToPauseYourBackups": "Spiacenti, abbiamo dovuto mettere in pausa i backup", + "clickToInstallOurBestVersionYet": "Clicca per installare l'ultima versione dell'app", + "onThisDayNotificationExplanation": "Ricevi promemoria sui ricordi da questo giorno negli anni precedenti.", + "addMemoriesWidgetPrompt": "Aggiungi un widget dei ricordi nella schermata iniziale e torna qui per personalizzarlo.", + "addAlbumWidgetPrompt": "Aggiungi un widget per gli album nella schermata iniziale e torna qui per personalizzarlo.", + "addPeopleWidgetPrompt": "Aggiungi un widget delle persone nella schermata iniziale e torna qui per personalizzarlo.", + "birthdayNotifications": "Notifiche dei compleanni", + "receiveRemindersOnBirthdays": "Ricevi promemoria quando è il compleanno di qualcuno. Toccare la notifica ti porterà alle foto della persona che compie gli anni.", + "happyBirthday": "Buon compleanno! 🥳", + "happyBirthdayToPerson": "Buon compleanno a {name}! 🎉", + "birthdays": "Compleanni", + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉", + "cLTitle1": "Caricamento di file video di grandi dimensioni", + "cLDesc1": "Dopo la versione beta dello streaming video e il lavoro sui caricamenti e download ripresi, abbiamo ora aumentato il limite di caricamento file a 10GB. Questo è ora disponibile sia nelle app desktop che mobili.", + "cLTitle2": "Caricamento in background", + "cLDesc2": "I caricamenti in background sono ora supportati anche su iOS, oltre ai dispositivi Android. Non è necessario aprire l'app per eseguire il backup delle tue foto e video più recenti.", + "cLTitle3": "Riproduzione automatica dei ricordi", + "cLDesc3": "Abbiamo apportato miglioramenti significativi alla nostra esperienza dei ricordi, inclusa la riproduzione automatica, scorrimento al ricordo successivo e molto altro.", + "cLTitle4": "Riconoscimento facciale migliorato", + "cLDesc4": "Insieme a un sacco di miglioramenti interni, ora è molto più facile vedere tutti i volti rilevati, fornire feedback sui volti simili e aggiungere/rimuovere volti da una singola foto.", + "cLTitle5": "Notifiche di compleanno", + "cLDesc5": "Ora riceverai una notifica opzionale per tutti i compleanni che hai salvato su Ente, insieme a una raccolta delle loro migliori foto.", + "cLTitle6": "Caricamenti e download ripresi", + "cLDesc6": "Non più attese per il completamento di caricamenti/download prima di poter chiudere l'app. Tutti i caricamenti e download ora hanno la capacità di essere messi in pausa a metà e ripresi da dove hai lasciato." } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ja.arb b/mobile/lib/l10n/intl_ja.arb index b31a3b22ae..4652fe9ba2 100644 --- a/mobile/lib/l10n/intl_ja.arb +++ b/mobile/lib/l10n/intl_ja.arb @@ -461,7 +461,7 @@ } }, "showMemories": "思い出を表示", - "yearsAgo": "{count, plural, one{{count} 年前} other{{count} 年前}}", + "yearsAgo": "{count, plural, other{{count} 年前}}", "backupSettings": "バックアップ設定", "backupStatus": "バックアップの状態", "backupStatusDescription": "バックアップされたアイテムがここに表示されます", @@ -527,7 +527,7 @@ }, "remindToEmptyEnteTrash": "「ゴミ箱」も空にするとアカウントのストレージが解放されます", "sparkleSuccess": "成功✨", - "duplicateFileCountWithStorageSaved": "お掃除しました {count, plural, one{{count} 個の重複ファイル} other{{count} 個の重複ファイル}}, ({storageSaved}が開放されます!)", + "duplicateFileCountWithStorageSaved": "お掃除しました {count, plural, other{{count} 個の重複ファイル}}, ({storageSaved}が開放されます!)", "@duplicateFileCountWithStorageSaved": { "description": "The text to display when the user has successfully cleaned up duplicate files", "type": "text", @@ -1178,7 +1178,7 @@ "searchHint4": "場所", "searchHint5": "近日公開: フェイスとマジック検索 ✨", "addYourPhotosNow": "写真を今すぐ追加する", - "searchResultCount": "{count, plural, one{{count} 個の結果} other{{count} 個の結果}}", + "searchResultCount": "{count, plural, other{{count} 個の結果}}", "@searchResultCount": { "description": "Text to tell user how many results were found for their search query", "placeholders": { @@ -1667,20 +1667,17 @@ "onTheRoad": "再び道で", "food": "料理を楽しむ", "pets": "毛むくじゃらな仲間たち", - "cLIcon": "新しいアイコン", - "cLIconDesc": "新しいアプリのアイコンが登場です!ちなみに、古いアイコンが好きだった人のためにアイコンの切り替え機能も用意がございます。", - "cLMemories": "思い出", - "cLMemoriesDesc": "あなたにとって特別な瞬間を再発見しましょう。 - あなたの好きな人々、あなたの旅行や休日。 機械学習をオンにすると、自分自身にタグを付けたり、友達の顔に名前をつけたりすることができます。", - "cLWidgets": "ウィジェット", - "cLWidgetsDesc": "Enteの「思い出」機能と統合されたホーム画面ウィジェットが利用可能になりました!", - "cLFamilyPlan": "ファミリープランの制限", - "cLFamilyPlanDesc": "ファミリーメンバーが使用できるストレージ容量の制限を設定できるようになりました。", - "cLBulkEdit": "日付を一括編集", - "cLBulkEditDesc": "複数の写真を、1回の操作で日付/時刻を編集することもできるようになりました。", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉", + "cLTitle1": "大きな動画ファイルのアップロード", + "cLDesc1": "動画ストリーミングベータ版と再開可能なアップロード・ダウンロードの作業により、ファイルアップロード制限を10GBに増加しました。これはデスクトップとモバイルアプリの両方で利用可能です。", + "cLTitle2": "バックグラウンドアップロード", + "cLDesc2": "バックグラウンドアップロードがAndroidデバイスに加えてiOSでもサポートされるようになりました。最新の写真や動画をバックアップするためにアプリを開く必要がありません。", + "cLTitle3": "メモリーの自動再生", + "cLDesc3": "自動再生、次のメモリーへのスワイプなど、メモリー体験に大幅な改善を加えました。", + "cLTitle4": "顔認識の改善", + "cLDesc4": "多くの内部改善とともに、検出されたすべての顔を確認し、類似した顔にフィードバックを提供し、1枚の写真から顔を追加/削除することがはるかに簡単になりました。", + "cLTitle5": "誕生日通知", + "cLDesc5": "Enteに保存したすべての誕生日について、その人のベスト写真のコレクションとともに、オプトアウト通知を受け取るようになります。", + "cLTitle6": "再開可能なアップロードとダウンロード", + "cLDesc6": "アプリを閉じる前にアップロード/ダウンロードの完了を待つ必要がなくなりました。すべてのアップロードとダウンロードは途中で一時停止し、中断したところから再開できるようになりました。" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_km.arb b/mobile/lib/l10n/intl_km.arb index 00a3e71e90..bfa658ba0d 100644 --- a/mobile/lib/l10n/intl_km.arb +++ b/mobile/lib/l10n/intl_km.arb @@ -1,9 +1,4 @@ { "@@locale ": "en", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ko.arb b/mobile/lib/l10n/intl_ko.arb index d2b77112d0..8967926b59 100644 --- a/mobile/lib/l10n/intl_ko.arb +++ b/mobile/lib/l10n/intl_ko.arb @@ -13,10 +13,5 @@ "confirmAccountDeletion": "계정 삭제 확인", "deleteAccountPermanentlyButton": "계정을 영구적으로 삭제", "yourAccountHasBeenDeleted": "계정이 삭제되었습니다.", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ku.arb b/mobile/lib/l10n/intl_ku.arb new file mode 100644 index 0000000000..bfa658ba0d --- /dev/null +++ b/mobile/lib/l10n/intl_ku.arb @@ -0,0 +1,4 @@ +{ + "@@locale ": "en", + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_lt.arb b/mobile/lib/l10n/intl_lt.arb index 9025d45938..24395032ba 100644 --- a/mobile/lib/l10n/intl_lt.arb +++ b/mobile/lib/l10n/intl_lt.arb @@ -1,6 +1,7 @@ { "@@locale ": "en", "enterYourEmailAddress": "Įveskite savo el. pašto adresą", + "enterYourNewEmailAddress": "Įveskite savo naują el. pašto adresą", "accountWelcomeBack": "Sveiki sugrįžę!", "emailAlreadyRegistered": "El. paštas jau užregistruotas.", "emailNotRegistered": "El. paštas neregistruotas.", @@ -156,7 +157,7 @@ "confirmYourRecoveryKey": "Patvirtinkite savo atkūrimo raktą", "addViewer": "Pridėti žiūrėtoją", "addCollaborator": "Pridėti bendradarbį", - "addANewEmail": "Pridėti naują el. paštą", + "addANewEmail": "Įtraukite naują el. paštą", "orPickAnExistingOne": "Arba pasirinkite esamą", "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": "Bendradarbiai gali pridėti nuotraukų ir vaizdo įrašų į bendrintą albumą.", "enterEmail": "Įveskite el. paštą", @@ -561,7 +562,7 @@ "referrals": "Rekomendacijos", "notifications": "Pranešimai", "sharedPhotoNotifications": "Naujos bendrintos nuotraukos", - "sharedPhotoNotificationsExplanation": "Gaukite pranešimus, kai kas nors prideda nuotrauką į bendrinamą albumą, kuriame dalyvaujate.", + "sharedPhotoNotificationsExplanation": "Gaukite pranešimus, kai kas nors įtraukia nuotrauką į bendrinamą albumą, kuriame dalyvaujate.", "advanced": "Išplėstiniai", "general": "Bendrieji", "security": "Saugumas", @@ -859,6 +860,7 @@ "toHideAPhotoOrVideo": "Kad paslėptumėte nuotrauką ar vaizdo įrašą", "openTheItem": "• Atverkite elementą.", "clickOnTheOverflowMenu": "• Spustelėkite ant perpildymo meniu", + "click": "• Spauskite", "nothingToSeeHere": "Čia nėra nieko, ką pamatyti. 👀", "unarchiveAlbum": "Išarchyvuoti albumą", "archiveAlbum": "Archyvuoti albumą", @@ -898,7 +900,7 @@ "unlock": "Atrakinti", "freeUpSpace": "Atlaisvinti vietos", "freeUpSpaceSaving": "{count, plural, =1 {Jį galima ištrinti iš įrenginio, kad atlaisvintų {formattedSize}} other {Jų galima ištrinti iš įrenginio, kad atlaisvintų {formattedSize}}}", - "filesBackedUpInAlbum": "{count, plural, one {{formattedNumber} failas šiame albume saugiai sukurta atsarginė kopija} few {{formattedNumber} failai šiame albume saugiai sukurtos atsarginės kopijos} many {{formattedNumber} failo šiame albume saugiai sukurtos atsargines kopijos} other {{formattedNumber} failų šiame albume saugiai sukurta atsarginė kopija}}.", + "filesBackedUpInAlbum": "{count, plural, one {{formattedNumber} failas šiame albume saugiai sukurta atsarginė kopija} other {{formattedNumber} failų šiame albume saugiai sukurta atsarginė kopija}}.", "@filesBackedUpInAlbum": { "description": "Text to tell user how many files have been backed up in the album", "placeholders": { @@ -913,6 +915,21 @@ } } }, + "filesBackedUpFromDevice": "{count, plural, one {{formattedNumber} failas šiame įrenginyje saugiai sukurta atsarginė kopija} other {{formattedNumber} failų šiame įrenginyje saugiai sukurta atsarginių kopijų}}.", + "@filesBackedUpFromDevice": { + "description": "Text to tell user how many files have been backed up from this device", + "placeholders": { + "count": { + "example": "1", + "type": "int" + }, + "formattedNumber": { + "content": "{formattedNumber}", + "example": "1,000", + "type": "String" + } + } + }, "@freeUpSpaceSaving": { "description": "Text to tell user how much space they can free up by deleting items from the device" }, @@ -936,6 +953,9 @@ "theRecoveryKeyYouEnteredIsIncorrect": "Įvestas atkūrimo raktas yra neteisingas.", "twofactorAuthenticationSuccessfullyReset": "Dvigubas tapatybės nustatymas sėkmingai iš naujo nustatytas.", "pleaseVerifyTheCodeYouHaveEntered": "Patvirtinkite įvestą kodą.", + "pleaseContactSupportIfTheProblemPersists": "Jei problema išlieka, susisiekite su pagalbos komanda.", + "twofactorAuthenticationHasBeenDisabled": "Dvigubas tapatybės nustatymas išjungtas.", + "sorryTheCodeYouveEnteredIsIncorrect": "Atsiprašome, įvestas kodas yra neteisingas.", "yourVerificationCodeHasExpired": "Jūsų patvirtinimo kodas nebegaliojantis.", "emailChangedTo": "El. paštas pakeistas į {newEmail}", "verifying": "Patvirtinama...", @@ -972,12 +992,20 @@ "successfullyArchived": "Sėkmingai suarchyvuota", "successfullyUnarchived": "Sėkmingai išarchyvuota", "renameFile": "Pervadinti failą", + "enterFileName": "Įveskite failo pavadinimą", + "filesDeleted": "Failai ištrinti", "selectedFilesAreNotOnEnte": "Pasirinkti failai nėra platformoje „Ente“", + "thisActionCannotBeUndone": "Šio veiksmo negalima anuliuoti.", "emptyTrash": "Ištuštinti šiukšlinę?", + "permDeleteWarning": "Visi elementai šiukšlinėje bus negrįžtamai ištrinti.\n\nŠio veiksmo negalima anuliuoti.", "empty": "Ištuštinti", "couldNotFreeUpSpace": "Nepavyko atlaisvinti vietos.", "permanentlyDeleteFromDevice": "Ištrinti negrįžtamai iš įrenginio?", "someOfTheFilesYouAreTryingToDeleteAre": "Kai kurie failai, kuriuos bandote ištrinti, yra pasiekiami tik jūsų įrenginyje ir jų negalima atkurti, jei jie buvo ištrinti.", + "theyWillBeDeletedFromAllAlbums": "Jie bus ištrinti iš visų albumų.", + "someItemsAreInBothEnteAndYourDevice": "Kai kurie elementai yra ir platformoje „Ente“ bei jūsų įrenginyje.", + "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": "Pasirinkti elementai bus ištrinti iš visų albumų ir perkelti į šiukšlinę.", + "theseItemsWillBeDeletedFromYourDevice": "Šie elementai bus ištrinti iš jūsų įrenginio.", "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Atrodo, kad kažkas nutiko ne taip. Bandykite pakartotinai po kurio laiko. Jei klaida tęsiasi, susisiekite su mūsų palaikymo komanda.", "error": "Klaida", "tempErrorContactSupportIfPersists": "Atrodo, kad kažkas nutiko ne taip. Bandykite dar kartą po kurio laiko. Jei klaida tęsiasi, susisiekite su mūsų palaikymo komanda.", @@ -998,7 +1026,10 @@ "pleaseSendTheLogsTo": "Siųskite žurnalus adresu\n{toEmail}", "copyEmailAddress": "Kopijuoti el. pašto adresą", "exportLogs": "Eksportuoti žurnalus", + "pleaseEmailUsAt": "Siųskite el. laišką mums adresu {toEmail}.", + "dismiss": "Atmesti", "didYouKnow": "Ar žinojote?", + "loadingMessage": "Įkeliamos jūsų nuotraukos...", "loadMessage1": "Galite bendrinti savo prenumeratą su šeima.", "loadMessage2": "Iki šiol išsaugojome daugiau nei 200 milijonų prisiminimų.", "loadMessage3": "Laikome 3 jūsų duomenų kopijas, vieną iš jų – požeminėje priešgaisrinėje slėptuvėje.", @@ -1008,28 +1039,48 @@ "loadMessage7": "Mūsų mobiliosios programos veikia fone, kad užšifruotų ir sukurtų atsarginę kopiją visų naujų nuotraukų, kurias spustelėjate.", "loadMessage8": "web.ente.io turi sklandų įkėlėją", "loadMessage9": "Naudojame „Xchacha20Poly1305“, kad saugiai užšifruotume jūsų duomenis.", + "photoDescriptions": "Nuotraukų aprašai", + "fileTypesAndNames": "Failų tipai ir pavadinimai", "location": "Vietovė", "moments": "Akimirkos", + "searchFaceEmptySection": "Asmenys bus rodomi čia, kai bus užbaigtas indeksavimas.", + "searchDatesEmptySection": "Ieškokite pagal datą, mėnesį arba metus", "searchLocationEmptySection": "Grupės nuotraukos, kurios padarytos tam tikru spinduliu nuo nuotraukos", "searchPeopleEmptySection": "Pakvieskite asmenis ir čia matysite visas jų bendrinamas nuotraukas.", + "searchAlbumsEmptySection": "Albumai", + "searchFileTypesAndNamesEmptySection": "Failų tipai ir pavadinimai", "searchCaptionEmptySection": "Pridėkite aprašymus, pavyzdžiui, „#kelionė“, į nuotraukos informaciją, kad greičiau jas čia rastumėte.", "language": "Kalba", "selectLanguage": "Pasirinkite kalbą", "locationName": "Vietovės pavadinimas", "addLocation": "Pridėti vietovę", + "groupNearbyPhotos": "Grupuoti netoliese nuotraukas", "kiloMeterUnit": "km", "addLocationButton": "Pridėti", + "radius": "Spindulys", "locationTagFeatureDescription": "Vietos žymė grupuoja visas nuotraukas, kurios buvo padarytos tam tikru spinduliu nuo nuotraukos", "galleryMemoryLimitInfo": "Galerijoje rodoma iki 1000 prisiminimų", - "centerPoint": "Vidurio taškas", + "save": "Išsaugoti", + "centerPoint": "Centro taškas", + "pickCenterPoint": "Pasirinkite centro tašką", + "useSelectedPhoto": "Naudoti pasirinktą nuotrauką", "resetToDefault": "Atkurti numatytąsias reikšmes", "@resetToDefault": { "description": "Button text to reset cover photo to default" }, "edit": "Redaguoti", "deleteLocation": "Ištrinti vietovę", + "rotateLeft": "Sukti į kairę", + "flip": "Apversti", + "rotateRight": "Sukti į dešinę", + "saveCopy": "Išsaugoti kopiją", "light": "Šviesi", "color": "Spalva", + "yesDiscardChanges": "Taip, atmesti pakeitimus", + "doYouWantToDiscardTheEditsYouHaveMade": "Ar norite atmesti atliktus pakeitimus?", + "saving": "Išsaugoma...", + "editsSaved": "Redagavimai išsaugoti", + "oopsCouldNotSaveEdits": "Ups, nepavyko išsaugoti redagavimų.", "distanceInKMUnit": "km", "@distanceInKMUnit": { "description": "Unit for distance in km" @@ -1038,10 +1089,16 @@ "dayYesterday": "Vakar", "storage": "Saugykla", "usedSpace": "Naudojama vieta", + "storageBreakupFamily": "Šeima", "storageBreakupYou": "Jūs", "@storageBreakupYou": { "description": "Label to indicate how much storage you are using when you are part of a family plan" }, + "storageUsageInfo": "{usedAmount} {usedStorageUnit} iš {totalAmount} {totalStorageUnit} naudojama", + "@storageUsageInfo": { + "description": "Example: 1.2 GB of 2 GB used or 100 GB or 2TB used" + }, + "availableStorageSpace": "{freeAmount} {storageUnit} laisva", "appVersion": "Versija: {versionValue}", "verifyIDLabel": "Patvirtinti", "fileInfoAddDescHint": "Pridėti aprašymą...", @@ -1050,12 +1107,21 @@ "@setLabel": { "description": "Label of confirm button to add a new custom radius to the radius selector of a location tag" }, + "setRadius": "Nustatyti spindulį", "familyPlanPortalTitle": "Šeima", "familyPlanOverview": "Įtraukite 5 šeimos narius į jūsų esamą planą nemokėdami papildomai.\n\nKiekvienas narys gauna savo asmeninę vietą ir negali matyti vienas kito failų, nebent jie bendrinami.\n\nŠeimos planai pasiekiami klientams, kurie turi mokamą „Ente“ prenumeratą.\n\nPrenumeruokite dabar, kad pradėtumėte!", "androidBiometricHint": "Patvirtinkite tapatybę", "@androidBiometricHint": { "description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters." }, + "androidBiometricNotRecognized": "Neatpažinta. Bandykite dar kartą.", + "@androidBiometricNotRecognized": { + "description": "Message to let the user know that authentication was failed. It is used on Android side. Maximum 60 characters." + }, + "androidBiometricSuccess": "Sėkmė", + "@androidBiometricSuccess": { + "description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters." + }, "androidCancelButton": "Atšaukti", "@androidCancelButton": { "description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters." @@ -1096,6 +1162,8 @@ "@iOSOkButton": { "description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters." }, + "openstreetmapContributors": "„OpenStreetMap“ bendradarbiai", + "hostedAtOsmFrance": "Talpinama OSM Prancūzijoje", "map": "Žemėlapis", "@map": { "description": "Label for the map view" @@ -1103,15 +1171,32 @@ "maps": "Žemėlapiai", "enableMaps": "Įjungti žemėlapius", "enableMapsDesc": "Tai parodys jūsų nuotraukas pasaulio žemėlapyje.\n\nŠį žemėlapį talpina „OpenStreetMap“, o tiksliomis nuotraukų vietovėmis niekada nebendrinama.\n\nŠią funkciją bet kada galite išjungti iš nustatymų.", + "quickLinks": "Sparčios nuorodos", + "selectItemsToAdd": "Pasirinkite elementus įtraukti", + "addSelected": "Pridėti pasirinktus", + "addFromDevice": "Pridėti iš įrenginio", + "addPhotos": "Įtraukti nuotraukų", + "noPhotosFoundHere": "Nuotraukų čia nerasta", + "zoomOutToSeePhotos": "Padidinkite mastelį, kad matytumėte nuotraukas", "noImagesWithLocation": "Nėra vaizdų su vietove", "unpinAlbum": "Atsegti albumą", "pinAlbum": "Prisegti albumą", "create": "Kurti", "viewAll": "Peržiūrėti viską", "nothingSharedWithYouYet": "Kol kas su jumis niekuo nesibendrinama.", + "noAlbumsSharedByYouYet": "Dar nėra albumų, kuriais bendrinotės.", "sharedWithYou": "Bendrinta su jumis", "sharedByYou": "Bendrinta iš jūsų", + "inviteYourFriendsToEnte": "Pakvieskite savo draugus į „Ente“", + "failedToDownloadVideo": "Nepavyko atsisiųsti vaizdo įrašo.", "hiding": "Slepiama...", + "unhiding": "Rodoma...", + "successfullyHid": "Sėkmingai paslėptas", + "successfullyUnhid": "Sėkmingai atslėptas", + "crashReporting": "Pranešti apie strigčius", + "resumableUploads": "Tęstiniai įkėlimai", + "addToHiddenAlbum": "Įtraukti į paslėptą albumą", + "moveToHiddenAlbum": "Perkelti į paslėptą albumą", "fileTypes": "Failų tipai", "deleteConfirmDialogBody": "Ši paskyra susieta su kitomis „Ente“ programomis, jei jas naudojate. Jūsų įkelti duomenys per visas „Ente“ programas bus planuojama ištrinti, o jūsų paskyra bus ištrinta negrįžtamai.", "hearUsWhereTitle": "Kaip išgirdote apie „Ente“? (nebūtina)", @@ -1120,14 +1205,18 @@ "addOns": "Priedai", "addOnPageSubtitle": "Išsami informacija apie priedus", "yourMap": "Jūsų žemėlapis", + "modifyYourQueryOrTrySearchingFor": "Modifikuokite užklausą arba bandykite ieškoti", "blackFridaySale": "Juodojo penktadienio išpardavimas", "upto50OffUntil4thDec": "Iki 50% nuolaida, gruodžio 4 d.", "photos": "Nuotraukos", "videos": "Vaizdo įrašai", "livePhotos": "Gyvos nuotraukos", + "searchHint1": "Sparti paieška įrenginyje", + "searchHint2": "Nuotraukų datos ir aprašai", "searchHint3": "Albumai, failų pavadinimai ir tipai", "searchHint4": "Vietovė", "searchHint5": "Jau netrukus: veidų ir magiškos paieškos ✨", + "addYourPhotosNow": "Įtraukite savo nuotraukas dabar", "searchResultCount": "{count, plural, one{Rastas {count} rezultatas} other{Rasta {count} rezultatų}}", "@searchResultCount": { "description": "Text to tell user how many results were found for their search query", @@ -1140,6 +1229,7 @@ }, "faces": "Veidai", "people": "Asmenys", + "contents": "Turinys", "addNew": "Pridėti naują", "@addNew": { "description": "Text to add a new item (location tag, album, caption etc)" @@ -1147,7 +1237,9 @@ "contacts": "Kontaktai", "noInternetConnection": "Nėra interneto ryšio", "pleaseCheckYourInternetConnectionAndTryAgain": "Patikrinkite savo interneto ryšį ir bandykite dar kartą.", + "signOutFromOtherDevices": "Atsijungti iš kitų įrenginių", "signOutOtherBody": "Jei manote, kad kas nors gali žinoti jūsų slaptažodį, galite priverstinai atsijungti iš visų kitų įrenginių, naudojančių jūsų paskyrą.", + "signOutOtherDevices": "Atsijungti kitus įrenginius", "doNotSignOut": "Neatsijungti", "editLocation": "Redaguoti vietovę", "selectALocation": "Pasirinkite vietovę", @@ -1190,6 +1282,8 @@ "createCollaborativeLink": "Kurti bendradarbiavimo nuorodą", "search": "Ieškokite", "enterPersonName": "Įveskite asmens vardą", + "editEmailAlreadyLinked": "Šis el. paštas jau susietas su {name}.", + "viewPersonToUnlink": "Peržiūrėkite {name}, kad atsietumėte", "enterName": "Įveskite vardą", "savePerson": "Išsaugoti asmenį", "editPerson": "Redaguoti asmenį", @@ -1202,6 +1296,7 @@ "manualPairDesc": "Susieti su PIN kodu veikia bet kuriame ekrane, kuriame norite peržiūrėti albumą.", "connectToDevice": "Prijungti prie įrenginio", "autoCastDialogBody": "Čia matysite pasiekiamus perdavimo įrenginius.", + "autoCastiOSPermission": "Įsitikinkite, kad programai „Ente“ nuotraukos yra įjungti vietinio tinklo leidimai, nustatymuose.", "noDeviceFound": "Įrenginys nerastas", "stopCastingTitle": "Stabdyti perdavimą", "stopCastingBody": "Ar norite sustabdyti perdavimą?", @@ -1222,6 +1317,7 @@ "right": "Dešinė", "whatsNew": "Kas naujo", "reviewSuggestions": "Peržiūrėti pasiūlymus", + "review": "Peržiūrėti", "useAsCover": "Naudoti kaip viršelį", "notPersonLabel": "Ne {name}?", "@notPersonLabel": { @@ -1299,6 +1395,7 @@ "configuration": "Konfiguracija", "localIndexing": "Vietinis indeksavimas", "processed": "Apdorota", + "resetPerson": "Šalinti", "areYouSureYouWantToResetThisPerson": "Ar tikrai norite iš naujo nustatyti šį asmenį?", "allPersonGroupingWillReset": "Visi šio asmens grupavimai bus iš naujo nustatyti, o jūs neteksite visų šiam asmeniui pateiktų pasiūlymų", "yesResetPerson": "Taip, nustatyti asmenį iš naujo", @@ -1307,6 +1404,16 @@ "enableMachineLearningBanner": "Įjunkite mašininį mokymąsi magiškai paieškai ir veidų atpažinimui", "searchDiscoverEmptySection": "Vaizdai bus rodomi čia, kai bus užbaigtas apdorojimas ir sinchronizavimas.", "searchPersonsEmptySection": "Asmenys bus rodomi čia, kai bus užbaigtas apdorojimas ir sinchronizavimas.", + "viewersSuccessfullyAdded": "{count, plural, =0 {Įtraukta 0 žiūrėtojų} =1 {Įtrauktas 1 žiūrėtojas} other {Įtraukta {count} žiūrėtojų}}", + "@viewersSuccessfullyAdded": { + "placeholders": { + "count": { + "type": "int", + "example": "2" + } + }, + "description": "Number of viewers that were successfully added to an album." + }, "collaboratorsSuccessfullyAdded": "{count, plural, =0 {Pridėta 0 bendradarbių} =1 {Pridėtas 1 bendradarbis} other {Pridėta {count} bendradarbių}}", "@collaboratorsSuccessfullyAdded": { "placeholders": { @@ -1382,6 +1489,15 @@ }, "currentlyRunning": "šiuo metu vykdoma", "ignored": "ignoruota", + "photosCount": "{count, plural, =0 {0 nuotraukų} =1 {1 nuotrauka} other {{count} nuotraukų}}", + "@photosCount": { + "placeholders": { + "count": { + "type": "int", + "example": "2" + } + } + }, "file": "Failas", "searchSectionsLengthMismatch": "Sekcijų ilgio neatitikimas: {snapshotLength} != {searchLength}", "@searchSectionsLengthMismatch": { @@ -1458,7 +1574,7 @@ "trustedInviteBody": "Buvote pakviesti tapti {email} palikimo kontaktu.", "warning": "Įspėjimas", "proceed": "Tęsti", - "confirmAddingTrustedContact": "Ketinate pridėti {email} kaip patikimą kontaktą. Jie galės atkurti jūsų paskyrą, jei jūsų nebus {numOfDays} dienų.", + "confirmAddingTrustedContact": "Ketinate įtraukti {email} kaip patikimą kontaktą. Jie galės atkurti jūsų paskyrą, jei jūsų nebus {numOfDays} dienų.", "@confirmAddingTrustedContact": { "placeholders": { "email": { @@ -1502,7 +1618,21 @@ } } }, + "reassignMe": "Perskirstyti „Aš“", "me": "Aš", + "linkEmailToContactBannerCaption": "spartesniam bendrinimui", + "@linkEmailToContactBannerCaption": { + "description": "Caption for the 'Link email' title. It should be a continuation of the 'Link email' title. Just like how 'Link email' + 'for faster sharing' forms a proper sentence in English, the combination of these two strings should also be a proper sentence in other languages." + }, + "selectPersonToLink": "Pasirinkite asmenį, kurį susieti.", + "linkPersonToEmail": "Susieti asmenį su {email}", + "@linkPersonToEmail": { + "placeholders": { + "email": { + "type": "String" + } + } + }, "linkPersonToEmailConfirmation": "Tai susies {personName} su {email}.", "@linkPersonToEmailConfirmation": { "description": "Confirmation message when linking a person to an email", @@ -1515,6 +1645,8 @@ } } }, + "selectYourFace": "Pasirinkite savo veidą", + "reassigningLoading": "Perskirstoma...", "reassignedToName": "Perskirstė jus į {name}", "@reassignedToName": { "placeholders": { @@ -1527,10 +1659,11 @@ "dontSave": "Neišsaugoti", "thisIsMeExclamation": "Tai aš!", "linkPerson": "Susiekite asmenį,", - "linkPersonCaption": "kad geriau bendrintumėte patirtį", + "linkPersonCaption": "geresniam bendrinimo patirčiai", "@linkPersonCaption": { "description": "Caption for the 'Link person' title. It should be a continuation of the 'Link person' title. Just like how 'Link person' + 'for better sharing experience' forms a proper sentence in English, the combination of these two strings should also be a proper sentence in other languages." }, + "videoStreaming": "Srautiniai vaizdo įrašai", "processingVideos": "Apdorojami vaizdo įrašai", "streamDetails": "Srautinio perdavimo išsami informacija", "processing": "Apdorojama", @@ -1571,7 +1704,20 @@ "thisWeekXYearsAgo": "{count, plural, =1 {Šią savaitę, prieš {count} metus} other {Šią savaitę, prieš {count} metų}}", "youAndThem": "Jūs ir {name}", "admiringThem": "Žavisi {name}", + "embracingThem": "Apkabinat {name}", + "partyWithThem": "Vakarėlis su {name}", + "hikingWithThem": "Žygiavimas su {name}", + "feastingWithThem": "Vaišiavimas su {name}", + "selfiesWithThem": "Asmenukės su {name}", + "posingWithThem": "Pozavimas su {name}", "backgroundWithThem": "Gražūs vaizdai su {name}", + "sportsWithThem": "Sportai su {name}", + "roadtripWithThem": "Kelionė su {name}", + "spotlightOnYourself": "Dėmesys į save", + "spotlightOnThem": "Dėmesys {name}", + "personIsAge": "{name} yra {age} m.!", + "personTurningAge": "{name} netrukus sulauks {age} m.", + "lastTimeWithThem": "Paskutinį kartą su {name}", "tripToLocation": "Kelionė į {location}", "tripInYear": "Kelionė per {year}", "lastYearsTrip": "Pastarųjų metų kelionė", @@ -1583,21 +1729,28 @@ "moon": "Mėnulio šviesoje", "onTheRoad": "Vėl kelyje", "food": "Kulinarinis malonumas", - "cLIcon": "Nauja piktograma", - "cLIconDesc": "Pagaliau – nauja programos piktograma, kuri, mūsų manymu, geriausiai atspindi mūsų kūrybą. Taip pat pridėjome piktogramos perjungiklį, tad galite ir toliau naudoti senąją piktogramą.", - "cLMemories": "Prisiminimai", - "cLMemoriesDesc": "Iš naujo atraskite ypatingas akimirkas – atkreipkite dėmesį į mėgstamus asmenis, keliones ir atostogas, geriausias nuotraukas bei daug daugiau. Įjunkite mašininį mokymąsi, pažymėkite save ir įvardykite draugus dėl geriausios patirties.", - "cLWidgets": "Valdikliai", - "cLWidgetsDesc": "Dabar galima naudoti su prisiminimais integruotus pagrindinio ekrano valdiklius. Jie parodys jūsų ypatingas akimirkas neatvėrus programos.", - "cLFamilyPlan": "Šeimos plano ribos", - "cLFamilyPlanDesc": "Dabar galite nustatyti ribas, kiek saugyklos gali naudoti jūsų šeimos nariai.", - "cLBulkEdit": "Masiškai redaguokite datas", - "cLBulkEditDesc": "Dabar galite pasirinkti kelias nuotraukas ir vienu sparčiu veiksmu redaguoti visų nuotraukų datą ir laiką. Taip pat palaikomas datų perkėlimas.", + "pets": "Furio draugai", "curatedMemories": "Kuruoti prisiminimai", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "widgets": "Valdikliai", + "memories": "Prisiminimai", + "peopleWidgetDesc": "Pasirinkite asmenis, kuriuos norite matyti savo pradžios ekrane.", + "albumsWidgetDesc": "Pasirinkite albumus, kuriuos norite matyti savo pradžios ekrane.", + "memoriesWidgetDesc": "Pasirinkite, kokius prisiminimus norite matyti savo pradžios ekrane.", + "smartMemories": "Išmanieji prisiminimai", + "pastYearsMemories": "Praėjusių metų prisiminimai", + "deleteMultipleAlbumDialog": "Taip pat ištrinti nuotraukas (ir vaizdo įrašus), esančias šiuose {count} albumuose, iš visų kitų albumų, kuriuose jos yra dalis?", + "addParticipants": "Įtraukti dalyvių", + "selectedAlbums": "{count} pasirinkta", + "actionNotSupportedOnFavouritesAlbum": "Veiksmas nepalaikomas Mėgstamų albume.", + "onThisDayMemories": "Šios dienos prisiminimai", + "onThisDay": "Šią dieną", + "lookBackOnYourMemories": "Pažvelkite atgal į savo prisiminimus 🌄", + "newPhotosEmoji": " naujas 📸", + "sorryWeHadToPauseYourBackups": "Atsiprašome, turėjome pristabdyti jūsų atsarginių kopijų kūrimą.", + "clickToInstallOurBestVersionYet": "Spustelėkite, kad įdiegtumėte geriausią mūsų versiją iki šiol", + "onThisDayNotificationExplanation": "Gaukite priminimus apie praėjusių metų šios dienos prisiminimus.", + "addMemoriesWidgetPrompt": "Pridėkite prisiminimų valdiklį prie savo pradžios ekrano ir grįžkite čia, kad tinkintumėte.", + "addAlbumWidgetPrompt": "Pridėkite albumo valdiklį prie savo pradžios ekrano ir grįžkite čia, kad tinkintumėte.", + "addPeopleWidgetPrompt": "Pridėkite asmenų valdiklį prie savo pradžios ekrano ir grįžkite čia, kad tinkintumėte.", + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_lv.arb b/mobile/lib/l10n/intl_lv.arb index 00a3e71e90..bfa658ba0d 100644 --- a/mobile/lib/l10n/intl_lv.arb +++ b/mobile/lib/l10n/intl_lv.arb @@ -1,9 +1,4 @@ { "@@locale ": "en", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ml.arb b/mobile/lib/l10n/intl_ml.arb index b9d7f7fc6b..6850e6e11f 100644 --- a/mobile/lib/l10n/intl_ml.arb +++ b/mobile/lib/l10n/intl_ml.arb @@ -100,10 +100,5 @@ "calculating": "കണക്കുകൂട്ടുന്നു...", "close": "അടക്കുക", "count": "എണ്ണം", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_nl.arb b/mobile/lib/l10n/intl_nl.arb index e3efde988e..af4e6fce7f 100644 --- a/mobile/lib/l10n/intl_nl.arb +++ b/mobile/lib/l10n/intl_nl.arb @@ -1,6 +1,7 @@ { "@@locale ": "en", "enterYourEmailAddress": "Voer je e-mailadres in", + "enterYourNewEmailAddress": "Voer uw nieuwe e-mailadres in", "accountWelcomeBack": "Welkom terug!", "emailAlreadyRegistered": "E-mail is al geregistreerd.", "emailNotRegistered": "E-mail niet geregistreerd.", @@ -371,6 +372,21 @@ "deleteFromBoth": "Verwijder van beide", "newAlbum": "Nieuw album", "albums": "Albums", + "memoryCount": "{count, plural, =0{geen herinneringen} one{{formattedCount} herinnering} other{{formattedCount} herinneringen}}", + "@memoryCount": { + "description": "The text to display the number of memories", + "type": "text", + "placeholders": { + "count": { + "example": "1", + "type": "int" + }, + "formattedCount": { + "type": "String", + "example": "11.513, 11,511" + } + } + }, "selectedPhotos": "{count} geselecteerd", "@selectedPhotos": { "description": "Display the number of selected photos", @@ -461,7 +477,7 @@ } }, "showMemories": "Toon herinneringen", - "yearsAgo": "{count, plural, one{{count} jaar geleden} other{{count} jaar geleden}}", + "yearsAgo": "{count, plural, other{{count} jaar geleden}}", "backupSettings": "Back-up instellingen", "backupStatus": "Back-up status", "backupStatusDescription": "Items die zijn geback-upt, worden hier getoond", @@ -706,6 +722,7 @@ "type": "text" }, "backupFailed": "Back-up mislukt", + "sorryBackupFailedDesc": "Sorry, we kunnen dit bestand nu niet back-uppen, we zullen het later opnieuw proberen.", "couldNotBackUpTryLater": "We konden uw gegevens niet back-uppen.\nWe zullen het later opnieuw proberen.", "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": "Ente kan bestanden alleen versleutelen en bewaren als u toegang tot ze geeft", "pleaseGrantPermissions": "Geef alstublieft toestemming", @@ -777,6 +794,14 @@ "share": "Delen", "unhideToAlbum": "Zichtbaar maken in album", "restoreToAlbum": "Terugzetten naar album", + "moveItem": "{count, plural, =1 {Bestand verplaatsen} other {Bestanden verplaatsen}}", + "@moveItem": { + "description": "Page title while moving one or more items to an album" + }, + "addItem": "{count, plural, =1 {Bestand toevoegen} other {Bestanden toevoegen}}", + "@addItem": { + "description": "Page title while adding one or more items to album" + }, "createOrSelectAlbum": "Maak of selecteer album", "selectAlbum": "Album selecteren", "searchByAlbumNameHint": "Albumnaam", @@ -874,6 +899,7 @@ "authToViewYourMemories": "Graag verifiëren om uw herinneringen te bekijken", "unlock": "Ontgrendelen", "freeUpSpace": "Ruimte vrijmaken", + "freeUpSpaceSaving": "{count, plural, =1 {Het kan verwijderd worden van het apparaat om {formattedSize} vrij te maken} other {Ze kunnen verwijderd worden van het apparaat om {formattedSize} vrij te maken}}", "filesBackedUpInAlbum": "{count, plural, one {1 bestand} other {{formattedNumber} bestanden}} in dit album is veilig geback-upt", "@filesBackedUpInAlbum": { "description": "Text to tell user how many files have been backed up in the album", @@ -904,6 +930,18 @@ } } }, + "@freeUpSpaceSaving": { + "description": "Text to tell user how much space they can free up by deleting items from the device" + }, + "freeUpAccessPostDelete": "Je hebt nog steeds toegang tot {count, plural, =1 {het} other {ze}} op Ente zolang je een actief abonnement hebt", + "@freeUpAccessPostDelete": { + "placeholders": { + "count": { + "example": "1", + "type": "int" + } + } + }, "freeUpAmount": "Maak {sizeInMBorGB} vrij", "thisEmailIsAlreadyInUse": "Dit e-mailadres is al in gebruik", "incorrectCode": "Onjuiste code", @@ -993,6 +1031,7 @@ "didYouKnow": "Wist u dat?", "loadingMessage": "Uw foto's laden...", "loadMessage1": "U kunt uw abonnement met uw familie delen", + "loadMessage2": "We hebben tot nu toe meer dan 200 miljoen herinneringen bewaard", "loadMessage3": "We bewaren 3 kopieën van uw bestanden, één in een ondergrondse kernbunker", "loadMessage4": "Al onze apps zijn open source", "loadMessage5": "Onze broncode en cryptografie zijn extern gecontroleerd en geverifieerd", @@ -1230,6 +1269,8 @@ "description": "Subtitle to indicate that the user can find people quickly by name" }, "findPeopleByName": "Mensen snel op naam zoeken", + "addViewers": "{count, plural, =0 {Kijker toevoegen} =1 {Kijker toevoegen} other {Kijkers toevoegen}}", + "addCollaborators": "{count, plural, =0 {Samenwerker toevoegen} =1 {Samenwerker toevoegen} other {Samenwerkers toevoegen}}", "longPressAnEmailToVerifyEndToEndEncryption": "Druk lang op een e-mail om de versleuteling te verifiëren.", "developerSettingsWarning": "Weet je zeker dat je de ontwikkelaarsinstellingen wilt wijzigen?", "developerSettings": "Ontwikkelaarsinstellingen", @@ -1241,6 +1282,8 @@ "createCollaborativeLink": "Maak een gezamenlijke link", "search": "Zoeken", "enterPersonName": "Naam van persoon invoeren", + "editEmailAlreadyLinked": "Dit e-mailadres is al aan {name} gekoppeld.", + "viewPersonToUnlink": "Bekijk {name} om te ontkoppelen", "enterName": "Naam invoeren", "savePerson": "Persoon opslaan", "editPerson": "Persoon bewerken", @@ -1361,6 +1404,16 @@ "enableMachineLearningBanner": "Schakel machine learning in voor magische zoekopdrachten en gezichtsherkenning", "searchDiscoverEmptySection": "Afbeeldingen worden hier getoond zodra verwerking en synchroniseren voltooid is", "searchPersonsEmptySection": "Personen worden hier getoond zodra verwerking en synchroniseren voltooid is", + "viewersSuccessfullyAdded": "{count, plural, =0 {0 kijkers toegevoegd} =1 {1 kijker toegevoegd} other {{count} kijkers toegevoegd}}", + "@viewersSuccessfullyAdded": { + "placeholders": { + "count": { + "type": "int", + "example": "2" + } + }, + "description": "Number of viewers that were successfully added to an album." + }, "collaboratorsSuccessfullyAdded": "{count, plural, =0 {0 samenwerkers toegevoegd} =1 {1 samenwerker toegevoegd} other {{count} samenwerkers toegevoegd}}", "@collaboratorsSuccessfullyAdded": { "placeholders": { @@ -1436,6 +1489,15 @@ }, "currentlyRunning": "momenteel bezig", "ignored": "genegeerd", + "photosCount": "{count, plural, =0 {0 foto's} =1 {1 foto} other {{count} foto's}}", + "@photosCount": { + "placeholders": { + "count": { + "type": "int", + "example": "2" + } + } + }, "file": "Bestand", "searchSectionsLengthMismatch": "Lengte van secties komt niet overeen: {snapshotLength} != {searchLength}", "@searchSectionsLengthMismatch": { @@ -1601,6 +1663,7 @@ "@linkPersonCaption": { "description": "Caption for the 'Link person' title. It should be a continuation of the 'Link person' title. Just like how 'Link person' + 'for better sharing experience' forms a proper sentence in English, the combination of these two strings should also be a proper sentence in other languages." }, + "videoStreaming": "Video's met stream", "processingVideos": "Video's verwerken", "streamDetails": "Stream details", "processing": "Verwerken", @@ -1667,20 +1730,27 @@ "onTheRoad": "Onderweg", "food": "Culinaire vreugde", "pets": "Harige kameraden", - "cLIcon": "Nieuw icoon", - "cLIconDesc": "Tot slot, een nieuwe app icoon waarvan we denken dat het ons werk het beste weergeeft. We hebben ook een icon-switcher toegevoegd zodat je het oude icoon kunt blijven gebruiken.", - "cLMemories": "Herinneringen", - "cLMemoriesDesc": "Ontdek nog eens je speciale momenten - spotlicht op je favoriete mensen, op je reizen en vakanties, op de beste plaatjes, en nog veel meer. Zet Machine Learning aan, tag jezelf en benoem je vrienden voor de beste ervaring.", - "cLWidgets": "Widgets", - "cLWidgetsDesc": "Widgets die zijn geïntegreerd met herinneringen zijn nu beschikbaar. Ze tonen je speciale momenten zonder de app te openen.", - "cLFamilyPlan": "Familieplan limieten", - "cLFamilyPlanDesc": "Je kunt nu limieten instellen voor hoeveel opslag je familieleden kunnen gebruiken.", - "cLBulkEdit": "Bulk datums wijzigen", - "cLBulkEditDesc": "Je kunt nu meerdere foto's selecteren en de datum/tijd van ze allemaal bewerken met één snelle actie. Verschuiven van datums wordt ook ondersteund.", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "curatedMemories": "Samengestelde herinneringen", + "widgets": "Widgets", + "memories": "Herinneringen", + "peopleWidgetDesc": "Selecteer de mensen die je wilt zien op je beginscherm.", + "albumsWidgetDesc": "Selecteer de albums die je wilt zien op je beginscherm.", + "memoriesWidgetDesc": "Selecteer het soort herinneringen dat je wilt zien op je beginscherm.", + "smartMemories": "Slimme herinneringen", + "pastYearsMemories": "Afgelopen jaren", + "deleteMultipleAlbumDialog": "Verwijder de foto's (en video's) van deze {count} albums ook uit alle andere albums waar deze deel van uitmaken?", + "addParticipants": "Voeg deelnemers toe", + "selectedAlbums": "{count} geselecteerd", + "actionNotSupportedOnFavouritesAlbum": "Actie niet ondersteund op Favorieten album", + "onThisDayMemories": "Op deze dag herinneringen", + "onThisDay": "Op deze dag", + "lookBackOnYourMemories": "Kijk terug op je herinneringen 🌄", + "newPhotosEmoji": " nieuwe 📸", + "sorryWeHadToPauseYourBackups": "Sorry, we moesten je back-ups pauzeren", + "clickToInstallOurBestVersionYet": "Klik om onze beste versie tot nu toe te installeren", + "onThisDayNotificationExplanation": "Ontvang meldingen over herinneringen op deze dag door de jaren heen.", + "addMemoriesWidgetPrompt": "Voeg een widget toe aan je beginscherm en kom hier terug om aan te passen.", + "addAlbumWidgetPrompt": "Voeg een widget toe aan je beginscherm en kom hier terug om aan te passen.", + "addPeopleWidgetPrompt": "Voeg een widget toe aan je beginscherm en kom hier terug om aan te passen.", + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_no.arb b/mobile/lib/l10n/intl_no.arb index 0ca7508080..17dbdffc72 100644 --- a/mobile/lib/l10n/intl_no.arb +++ b/mobile/lib/l10n/intl_no.arb @@ -476,7 +476,7 @@ } }, "showMemories": "Vis minner", - "yearsAgo": "{count, plural, one{{count} år siden} other{{count} år siden}}", + "yearsAgo": "{count, plural, other{{count} år siden}}", "backupSettings": "Sikkerhetskopier innstillinger", "backupStatus": "Status for sikkerhetskopi", "backupStatusDescription": "Elementer som har blitt sikkerhetskopiert vil vises her", @@ -1699,11 +1699,5 @@ "cLFamilyPlan": "Begrensninger for familieabonnement", "cLFamilyPlanDesc": "Du kan nå sette grenser for hvor mye lagringsplass familiemedlemmer kan bruke.", "cLBulkEdit": "Masseendring av datoer", - "cLBulkEditDesc": "Du kan nå velge flere bilder, og redigere dato/klokkeslett for alle med en rask handling. Forskyving av datoer støttes også.", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "cLBulkEditDesc": "Du kan nå velge flere bilder, og redigere dato/klokkeslett for alle med en rask handling. Forskyving av datoer støttes også." } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_or.arb b/mobile/lib/l10n/intl_or.arb index 00a3e71e90..bfa658ba0d 100644 --- a/mobile/lib/l10n/intl_or.arb +++ b/mobile/lib/l10n/intl_or.arb @@ -1,9 +1,4 @@ { "@@locale ": "en", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_pl.arb b/mobile/lib/l10n/intl_pl.arb index 97c4cad584..b2186f028b 100644 --- a/mobile/lib/l10n/intl_pl.arb +++ b/mobile/lib/l10n/intl_pl.arb @@ -443,8 +443,8 @@ "selectAll": "Zaznacz wszystko", "skip": "Pomiń", "updatingFolderSelection": "Aktualizowanie wyboru folderu...", - "itemCount": "{count, plural, one{{count} element} few {{count} elementy} many {{count} elementów} other{{count} elementu}}", - "deleteItemCount": "{count, plural, =1 {Usuń {count} element} few {Usuń {count} elementy} many {Usuń {count} elementów} other{Usuń {count} elementu}}", + "itemCount": "{count, plural, one{{count} element} other{{count} elementu}}", + "deleteItemCount": "{count, plural, =1 {Usuń {count} element} other{Usuń {count} elementu}}", "duplicateItemsGroup": "{count} plików, każdy po {formattedSize}", "@duplicateItemsGroup": { "description": "Display the number of duplicate files and their size", @@ -461,7 +461,7 @@ } }, "showMemories": "Pokaż wspomnienia", - "yearsAgo": "{count, plural, one{{count} rok temu} few {{count} lata temu} many {{count} lat temu} other{{count} lata temu}}", + "yearsAgo": "{count, plural, one{{count} rok temu} other{{count} lata temu}}", "backupSettings": "Ustawienia kopii zapasowej", "backupStatus": "Status kopii zapasowej", "backupStatusDescription": "Elementy, których kopia zapasowa została utworzona, zostaną wyświetlone w tym miejscu", @@ -800,7 +800,7 @@ "referFriendsAnd2xYourPlan": "Poleć znajomym i podwój swój plan", "shareAlbumHint": "Otwórz album i dotknij przycisk udostępniania w prawym górnym rogu, aby udostępnić.", "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": "Elementy pokazują liczbę dni pozostałych przed trwałym usunięciem", - "trashDaysLeft": "{count, plural, =0 {Wkrótce} =1{1 dzień} few {{count} dni} other{{count} dni}}", + "trashDaysLeft": "{count, plural, =0 {Wkrótce} =1{1 dzień} other{{count} dni}}", "@trashDaysLeft": { "description": "Text to indicate number of days remaining before permanent deletion", "placeholders": { @@ -1177,7 +1177,7 @@ "searchHint4": "Lokalizacja", "searchHint5": "Wkrótce: Twarze i magiczne wyszukiwanie ✨", "addYourPhotosNow": "Dodaj swoje zdjęcia teraz", - "searchResultCount": "{count, plural, one{Znaleziono {count} wynik} few {Znaleziono {count} wyniki} other{Znaleziono {count} wyników}}", + "searchResultCount": "{count, plural, one{Znaleziono {count} wynik} other{Znaleziono {count} wyników}}", "@searchResultCount": { "description": "Text to tell user how many results were found for their search query", "placeholders": { @@ -1534,10 +1534,5 @@ "join": "Dołącz", "linkEmail": "Połącz adres e-mail", "noEnteAccountExclamation": "Brak konta Ente!", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_pt.arb b/mobile/lib/l10n/intl_pt.arb index e88e9351f7..cfbf47aaeb 100644 --- a/mobile/lib/l10n/intl_pt.arb +++ b/mobile/lib/l10n/intl_pt.arb @@ -1681,5 +1681,10 @@ "newPhotosEmoji": " new 📸", "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years.", + "birhtdayNotifications": "Birhtday notifications", + "receiveRemindersOnBirthdays": "Receive reminders when it's someone's birthday. Tapping on the notification will take you to photos of the birthday person.", + "happyBirthday": "Happy birthday! 🥳", + "birthdays": "Birthdays", + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_pt_BR.arb b/mobile/lib/l10n/intl_pt_BR.arb index 53874b4faf..8197622f41 100644 --- a/mobile/lib/l10n/intl_pt_BR.arb +++ b/mobile/lib/l10n/intl_pt_BR.arb @@ -1,14 +1,15 @@ { "@@locale ": "en", - "enterYourEmailAddress": "Insira seu endereço de e-mail", + "enterYourEmailAddress": "Insira seu e-mail", + "enterYourNewEmailAddress": "Insira seu novo e-mail", "accountWelcomeBack": "Bem-vindo(a) de volta!", "emailAlreadyRegistered": "E-mail já registrado.", "emailNotRegistered": "E-mail não registrado.", "email": "E-mail", "cancel": "Cancelar", "verify": "Verificar", - "invalidEmailAddress": "Endereço de e-mail inválido", - "enterValidEmail": "Insira um endereço de e-mail válido.", + "invalidEmailAddress": "E-mail inválido", + "enterValidEmail": "Insira um e-mail válido.", "deleteAccount": "Excluir conta", "askDeleteReason": "Por que você quer excluir sua conta?", "deleteAccountFeedbackPrompt": "Lamentamos você ir. Compartilhe seu feedback para ajudar-nos a melhorar.", @@ -25,7 +26,7 @@ "deleteReason4": "Meu motivo não está listado", "sendEmail": "Enviar e-mail", "deleteRequestSLAText": "Sua solicitação será revisada em até 72 horas.", - "deleteEmailRequest": "Por favor, envie um e-mail a account-deletion@ente.io do seu endereço de e-mail registrado.", + "deleteEmailRequest": "Por favor, envie um e-mail a account-deletion@ente.io do seu e-mail registrado.", "entePhotosPerm": "Ente precisa de permissão para preservar suas fotos", "ok": "OK", "createAccount": "Criar conta", @@ -120,7 +121,7 @@ "recoveryKeyCopiedToClipboard": "Chave de recuperação copiada para a área de transferência", "recoverAccount": "Recuperar conta", "recover": "Recuperar", - "dropSupportEmail": "Envie um e-mail para {supportEmail} a partir do seu endereço de e-mail registrado", + "dropSupportEmail": "Envie um e-mail para {supportEmail} a partir do e-mail registrado", "@dropSupportEmail": { "placeholders": { "supportEmail": { @@ -131,13 +132,13 @@ } }, "twofactorSetup": "Configuração de dois fatores", - "enterCode": "Insira o código", + "enterCode": "Inserir código", "scanCode": "Escanear código", "codeCopiedToClipboard": "Código copiado para a área de transferência", - "copypasteThisCodentoYourAuthenticatorApp": "Copie e cole este código\npara o aplicativo autenticador", + "copypasteThisCodentoYourAuthenticatorApp": "Copie e cole o código no aplicativo autenticador", "tapToCopy": "toque para copiar", "scanThisBarcodeWithnyourAuthenticatorApp": "Escaneie este código de barras com\no aplicativo autenticador", - "enterThe6digitCodeFromnyourAuthenticatorApp": "Digite o código de 6 dígitos do\naplicativo de autenticador", + "enterThe6digitCodeFromnyourAuthenticatorApp": "Digite o código de 6 dígitos do\naplicativo autenticador", "confirm": "Confirmar", "setupComplete": "Configuração concluída", "saveYourRecoveryKeyIfYouHaventAlready": "Salve sua chave de recuperação, se você ainda não fez", @@ -146,7 +147,7 @@ "lostDevice": "Perdeu o dispositivo?", "verifyingRecoveryKey": "Verificando chave de recuperação...", "recoveryKeyVerified": "Chave de recuperação verificada", - "recoveryKeySuccessBody": "Ótimo! Sua chave de recuperação é válida. Obrigada por verificar.\n\nLembre-se de manter sua chave de recuperação copiada com segurança.", + "recoveryKeySuccessBody": "Ótimo! Sua chave de recuperação é válida. Obrigada por verificar.\n\nLembre-se de manter sua chave de recuperação salva em segurança.", "invalidRecoveryKey": "A chave de recuperação que você inseriu não é válida. Certifique-se de conter 24 caracteres, e verifique a ortografia de cada um deles.\n\nSe você inseriu um código de recuperação mais antigo, verifique se ele tem 64 caracteres e verifique cada um deles.", "invalidKey": "Chave inválida", "tryAgain": "Tente novamente", @@ -252,7 +253,7 @@ }, "thisIsYourVerificationId": "Este é o seu ID de verificação", "someoneSharingAlbumsWithYouShouldSeeTheSameId": "Alguém compartilhando álbuns com você deve ver o mesmo ID no dispositivo.", - "howToViewShareeVerificationID": "Peça-os para manterem pressionado no endereço de e-mail na tela de opções, e verifique-se os IDs de ambos os dispositivos correspondem.", + "howToViewShareeVerificationID": "Peça-os para pressionarem no e-mail a partir das Opções, e verifique-se os IDs de ambos os dispositivos correspondem.", "thisIsPersonVerificationId": "Este é o ID de verificação de {email}", "@thisIsPersonVerificationId": { "placeholders": { @@ -272,7 +273,7 @@ "shareTextRecommendUsingEnte": "Baixe o Ente para que nós possamos compartilhar com facilidade fotos e vídeos de qualidade original\n\nhttps://ente.io", "done": "Concluído", "applyCodeTitle": "Aplicar código", - "enterCodeDescription": "Insira o código fornecido pelo seu amigo para reivindicar o armazenamento grátis para os dois", + "enterCodeDescription": "Insira o código fornecido por um amigo para reivindicar armazenamento grátis para ambos", "apply": "Aplicar", "failedToApplyCode": "Falhou ao aplicar código", "enterReferralCode": "Inserir código de referência", @@ -290,14 +291,14 @@ "details": "Detalhes", "claimMore": "Reivindique mais!", "theyAlsoGetXGb": "Eles também recebem {storageAmountInGB} GB", - "freeStorageOnReferralSuccess": "{storageAmountInGB} GB cada vez que alguém se inscrever a um plano pago e aplicar seu código", - "shareTextReferralCode": "Código de referência do Ente: {referralCode} \n\nAplique-o em Configurações → Geral → Referências para obter {referralStorageInGB} GB grátis após a sua inscrição num plano pago\n\nhttps://ente.io", + "freeStorageOnReferralSuccess": "{storageAmountInGB} GB toda vez que alguém utilizar seu código num plano pago", + "shareTextReferralCode": "Código de referência Ente: {referralCode} \n\nAplique-o em Opções → Geral → Referências para obter {referralStorageInGB} GB grátis após a inscrição num plano pago\n\nhttps://ente.io", "claimFreeStorage": "Reivindique armaz. grátis", "inviteYourFriends": "Convide seus amigos", "failedToFetchReferralDetails": "Não foi possível buscar os detalhes de referência. Tente novamente mais tarde.", "referralStep1": "1. Envie este código aos seus amigos", "referralStep2": "2. Eles então se inscrevem num plano pago", - "referralStep3": "3. Ambos os dois ganham {storageInGB} GB* grátis", + "referralStep3": "3. Ambos ganham {storageInGB} GB* grátis", "referralsAreCurrentlyPaused": "As referências estão atualmente pausadas", "youCanAtMaxDoubleYourStorage": "* Você pode duplicar seu armazenamento ao máximo", "claimedStorageSoFar": "{isFamilyMember, select,true {Sua família reinvidicou {storageAmountInGb} GB até então}false {Você reinvindicou {storageAmountInGb} GB até então}other {Você reinvindicou {storageAmountInGb} GB até então!}}", @@ -316,13 +317,13 @@ "faq": "Perguntas frequentes", "help": "Ajuda", "oopsSomethingWentWrong": "Ops, algo deu errado", - "peopleUsingYourCode": "Pessoas que usam seu código", + "peopleUsingYourCode": "Pessoas que usou o código", "eligible": "elegível", "total": "total", "codeUsedByYou": "Código usado por você", "freeStorageClaimed": "Armaz. grátis reivindicado", "freeStorageUsable": "Armazenamento disponível", - "usableReferralStorageInfo": "O armazenamento disponível é limitado pelo seu plano atual. O excesso de armazenamento reivindicado tornará automaticamente útil quando você atualizar seu plano.", + "usableReferralStorageInfo": "O armazenamento disponível é limitado devido ao seu plano atual. O armazenamento adicional será aplicado quando você atualizar seu plano.", "removeFromAlbumTitle": "Remover do álbum?", "removeFromAlbum": "Remover do álbum", "itemsWillBeRemovedFromAlbum": "Os itens selecionados serão removidos deste álbum", @@ -349,7 +350,7 @@ "disableLinkMessage": "Isso removerá o link público para acessar \"{albumName}\".", "sharing": "Compartilhando...", "youCannotShareWithYourself": "Não é possível compartilhar consigo mesmo", - "archive": "Arquive", + "archive": "Arquivo", "createAlbumActionHint": "Pressione para selecionar fotos e clique em + para criar um álbum", "importing": "Importando....", "failedToLoadAlbums": "Falhou ao carregar álbuns", @@ -421,7 +422,7 @@ "manageDeviceStorageDesc": "Reveja e limpe o armazenamento de cache local.", "machineLearning": "Aprendizado automático", "mlConsent": "Ativar o aprendizado automático", - "mlConsentTitle": "Ativar aprendizado automático?", + "mlConsentTitle": "Ativar aprendizado auto.?", "mlConsentDescription": "Se ativar o aprendizado automático, Ente extrairá informações de geometria facial dos arquivos, incluindo aqueles compartilhados consigo.\n\nIsso acontecerá em seu dispositivo, e qualquer informação biométrica gerada será criptografada de ponta a ponta.", "mlConsentPrivacy": "Clique aqui para mais detalhes sobre este recurso na política de privacidade", "mlConsentConfirmation": "Concordo e desejo ativá-lo", @@ -452,8 +453,8 @@ "indexedItems": "Itens indexados", "pendingItems": "Itens pendentes", "clearIndexes": "Limpar índices", - "selectFoldersForBackup": "Selecionar pastas para copiar com segurança", - "selectedFoldersWillBeEncryptedAndBackedUp": "As pastas selecionadas serão criptografadas e armazenadas em copiadas com segurança", + "selectFoldersForBackup": "Selecione as pastas para salvá-las", + "selectedFoldersWillBeEncryptedAndBackedUp": "As pastas selecionadas serão criptografadas e salvas em segurança", "unselectAll": "Desmarcar tudo", "selectAll": "Selecionar tudo", "skip": "Pular", @@ -477,13 +478,13 @@ }, "showMemories": "Mostrar memórias", "yearsAgo": "{count, plural, one{{count} ano atrás} other{{count} anos atrás}}", - "backupSettings": "Opções de cópia de segurança", - "backupStatus": "Status da cópia de segurança", - "backupStatusDescription": "Os itens que foram salvos com segurança aparecerão aqui", - "backupOverMobileData": "Salvamento com segurança usando dados móveis", - "backupVideos": "Cópia de segurança de vídeos", + "backupSettings": "Ajustes de salvar em segurança", + "backupStatus": "Estado das mídias salvas", + "backupStatusDescription": "Os itens salvos em segurança aparecerão aqui", + "backupOverMobileData": "Salvar fotos com dados móveis", + "backupVideos": "Salvar vídeos em segurança", "disableAutoLock": "Desativar bloqueio automático", - "deviceLockExplanation": "Desativa o bloqueio de tela quando o Ente está de fundo e têm uma cópia de segurança sendo feita. Isso normalmente não é necessário, no entanto, ajuda a envios grandes e importações iniciais de bibliotecas maiores concluírem mais rápido.", + "deviceLockExplanation": "Desativa o bloqueio de tela se o Ente estiver de fundo e uma cópia de segurança ainda estiver em andamento. Às vezes, isso não é necessário, mas ajuda a agilizar envios grandes e importações iniciais de bibliotecas maiores.", "about": "Sobre", "weAreOpenSource": "Nós somos de código aberto!", "privacy": "Privacidade", @@ -514,8 +515,8 @@ "cannotDeleteSharedFiles": "Não é possível excluir arquivos compartilhados", "theDownloadCouldNotBeCompleted": "A instalação não pôde ser concluída", "retry": "Tentar novamente", - "backedUpFolders": "Pastas copiadas com segurança", - "backup": "Cópia de segurança", + "backedUpFolders": "Pastas salvas em segurança", + "backup": "Salvar em segurança", "freeUpDeviceSpace": "Liberar espaço no dispositivo", "freeUpDeviceSpaceDesc": "Economize espaço em seu dispositivo por limpar arquivos já salvos com segurança.", "allClear": "✨ Tudo limpo", @@ -528,7 +529,7 @@ "youveNoDuplicateFilesThatCanBeCleared": "Você não possui nenhum arquivo duplicado que possa ser excluído", "success": "Sucesso", "rateUs": "Avaliar", - "remindToEmptyDeviceTrash": "Também vazio \"Excluído recentemente\" de \"Opções\" -> \"Armazenamento\" para reivindicar espaço liberado", + "remindToEmptyDeviceTrash": "Também esvazie o \"Excluído Recentemente\" das \"Opções\" -> \"Armazenamento\" para liberar espaço", "youHaveSuccessfullyFreedUp": "Você liberou {storageSaved} com sucesso!", "@youHaveSuccessfullyFreedUp": { "description": "The text to display when the user has successfully freed up storage", @@ -690,12 +691,12 @@ "areYouSureThatYouWantToLeaveTheFamily": "Você tem certeza que queira sair do plano familiar?", "leave": "Sair", "rateTheApp": "Avalie o aplicativo", - "startBackup": "Iniciar cópia de segurança", - "noPhotosAreBeingBackedUpRightNow": "No momento não há fotos sendo copiadas com segurança", + "startBackup": "Iniciar a salvar em segurança", + "noPhotosAreBeingBackedUpRightNow": "No momento não há fotos sendo salvas em segurança", "preserveMore": "Preservar mais", "grantFullAccessPrompt": "Permita o acesso a todas as fotos nas opções do aplicativo", "allowPermTitle": "Permita acesso às Fotos", - "allowPermBody": "Permita o acesso a suas fotos das Configurações para que Ente possa exibir e copiar com segurança sua biblioteca.", + "allowPermBody": "Permita o acesso a suas fotos nas Opções para que Ente exiba e salva em segurança sua fototeca.", "openSettings": "Abrir opções", "selectMorePhotos": "Selecionar mais fotos", "existingUser": "Usuário existente", @@ -704,7 +705,7 @@ "endtoendEncryptedByDefault": "Criptografado de ponta a ponta por padrão", "safelyStored": "Armazenado com segurança", "atAFalloutShelter": "em um abrigo avançado", - "designedToOutlive": "Feito para ter longevidade", + "designedToOutlive": "Feito para reviver memórias", "available": "Disponível", "everywhere": "em todas as partes", "androidIosWebDesktop": "Android, iOS, Web, Computador", @@ -720,9 +721,9 @@ "description": "Button text for raising a support tickets in case of unhandled errors during backup", "type": "text" }, - "backupFailed": "Falhou ao copiar com segurança", - "sorryBackupFailedDesc": "Desculpe, não podemos fazer cópia de segurança deste arquivo no momento, nós tentaremos mais tarde.", - "couldNotBackUpTryLater": "Nós não podemos copiar com segurança seus dados.\nNós tentaremos novamente mais tarde.", + "backupFailed": "Falhou ao salvar em segurança", + "sorryBackupFailedDesc": "Desculpe, não podemos salvar em segurança este arquivo no momento, nós tentaremos mais tarde.", + "couldNotBackUpTryLater": "Nós não podemos salvar seus dados.\nNós tentaremos novamente mais tarde.", "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": "Ente pode criptografar e preservar arquivos apenas se você conceder acesso a eles", "pleaseGrantPermissions": "Por favor, conceda as permissões", "grantPermission": "Conceder permissões", @@ -854,7 +855,7 @@ "ignoredFolderUploadReason": "Alguns arquivos neste álbum são ignorados do envio porque eles foram anteriormente excluídos do Ente.", "resetIgnoredFiles": "Redefinir arquivos ignorados", "deviceFilesAutoUploading": "Arquivos adicionados ao álbum do dispositivo serão automaticamente enviados para o Ente.", - "turnOnBackupForAutoUpload": "Ative a cópia de segurança para automaticamente enviar arquivos adicionados à pasta do dispositivo para o Ente.", + "turnOnBackupForAutoUpload": "Ative o salvamento em segurança para automaticamente enviar arquivos adicionados à pasta do dispositivo para o Ente.", "noHiddenPhotosOrVideos": "Sem fotos ou vídeos ocultos", "toHideAPhotoOrVideo": "Para ocultar uma foto ou vídeo", "openTheItem": "• Abra a foto ou vídeo", @@ -898,8 +899,8 @@ "authToViewYourMemories": "Autentique-se para ver suas memórias", "unlock": "Desbloquear", "freeUpSpace": "Liberar espaço", - "freeUpSpaceSaving": "{count, plural, =1 {Ele pode excluído para liberar {formattedSize}} other {Eles podem ser excluídos do dispositivo para liberar {formattedSize}}}", - "filesBackedUpInAlbum": "{count, plural, one {1 arquivo} other {{formattedNumber} arquivos}} deste álbum foi copiado com segurança", + "freeUpSpaceSaving": "{count, plural, =1 {Ele pode excluído do dispositivo para liberar {formattedSize}} other {Eles podem ser excluídos do dispositivo para liberar {formattedSize}}}", + "filesBackedUpInAlbum": "{count, plural, one {1 arquivo} other {{formattedNumber} arquivos}} deste álbum foi(ram) salvo(s) em segurança", "@filesBackedUpInAlbum": { "description": "Text to tell user how many files have been backed up in the album", "placeholders": { @@ -914,7 +915,7 @@ } } }, - "filesBackedUpFromDevice": "{count, plural, one {1 arquivo} other {{formattedNumber} arquivos}} deste dispositivo foi copiado com segurança", + "filesBackedUpFromDevice": "{count, plural, one {1 arquivo} other {{formattedNumber} arquivos}} deste dispositivo foi(ram) salvos em segurança", "@filesBackedUpFromDevice": { "description": "Text to tell user how many files have been backed up from this device", "placeholders": { @@ -962,7 +963,7 @@ "allMemoriesPreserved": "Todas as memórias preservadas", "loadingGallery": "Carregando galeria...", "syncing": "Sincronizando...", - "encryptingBackup": "Criptografando cópia de segurança...", + "encryptingBackup": "Criptografando salvar em segurança...", "syncStopped": "Sincronização interrompida", "syncProgress": "{completed}/{total} memórias preservadas", "uploadingMultipleMemories": "Preservando {count} memórias...", @@ -1023,7 +1024,7 @@ "preparingLogs": "Preparando registros...", "emailYourLogs": "Enviar registros por e-mail", "pleaseSendTheLogsTo": "Envie os registros para \n{toEmail}", - "copyEmailAddress": "Copiar endereço de e-mail", + "copyEmailAddress": "Copiar e-mail", "exportLogs": "Exportar registros", "pleaseEmailUsAt": "Envie-nos um e-mail para {toEmail}", "dismiss": "Descartar", @@ -1035,7 +1036,7 @@ "loadMessage4": "Todos os nossos aplicativos são de código aberto", "loadMessage5": "Nosso código-fonte e criptografia foram auditadas externamente", "loadMessage6": "Você pode compartilhar links para seus álbuns com seus entes queridos", - "loadMessage7": "Nossos aplicativos móveis são executados em segundo plano para criptografar e copiar com segurança quaisquer fotos novas que você acessar", + "loadMessage7": "Nossos aplicativos móveis são executados em segundo plano para criptografar e salvar em segurança quaisquer fotos novas que você acessar", "loadMessage8": "web.ente.io tem um enviador mais rápido", "loadMessage9": "Nós usamos Xchacha20Poly1305 para criptografar seus dados com segurança", "photoDescriptions": "Descrições das fotos", @@ -1522,7 +1523,7 @@ "faceNotClusteredYet": "Rosto não agrupado ainda, volte aqui mais tarde", "theLinkYouAreTryingToAccessHasExpired": "O link que você está tentando acessar já expirou.", "openFile": "Abrir arquivo", - "backupFile": "Copiar arquivo com segurança", + "backupFile": "Salvar arquivo em segurança", "openAlbumInBrowser": "Abrir álbum no navegador", "openAlbumInBrowserTitle": "Use o aplicativo da web para adicionar fotos a este álbum", "allow": "Permitir", @@ -1588,7 +1589,7 @@ }, "legacyInvite": "{email} convidou você para ser um contato confiável", "authToManageLegacy": "Autentique-se para gerenciar seus contatos confiáveis", - "useDifferentPlayerInfo": "Enfrentando problemas ao reproduzir este vídeo? Mantenha pressionado aqui ou tente outro reprodutor de vídeo", + "useDifferentPlayerInfo": "Enfrentando problemas ao reproduzir este vídeo? Mantenha pressionado aqui para tentar outro reprodutor de vídeo", "hideSharedItemsFromHomeGallery": "Ocultar itens compartilhados da galeria inicial", "gallery": "Galeria", "joinAlbum": "Unir-se ao álbum", @@ -1727,23 +1728,46 @@ "city": "Na cidade", "moon": "Na luz do luar", "onTheRoad": "Na estrada novamente", - "food": "Amor por culinária", + "food": "Delícias de cozinha", "pets": "Companhias peludas", - "cLIcon": "Novo Ícone", - "cLIconDesc": "Finalmente, um novo ícone para o ente que acreditamos que represente melhor nosso trabalho. Também, adicionamos um alterador de ícone para que você ainda consiga utilizar o ícone antigo.", - "cLMemories": "Memórias", - "cLMemoriesDesc": "Relembre momentos especiais - destaque pessoas favoritas, suas viagens e feriados, melhores fotos, e muito mais. Ative o aprendizado automático, marque-se e nomeie seus amigos para melhorar a experiência.", - "cLWidgets": "Widgets", - "cLWidgetsDesc": "Widgets integrados com memórias já estão disponíveis. Eles apareceram com seus melhores momentos sem precisar abrir o ente.", - "cLFamilyPlan": "Limites de planos familiares", - "cLFamilyPlanDesc": "Agora você pode definir um limite de quanto armazenamento os seus entes queridos podem usar.", - "cLBulkEdit": "Editar todas as datas", - "cLBulkEditDesc": "Agora você pode selecionar várias fotos, editar data e hora de todos com um só clique. Alternar datas também são suportados.", "curatedMemories": "Memórias restauradas", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "widgets": "Widgets", + "memories": "Memórias", + "peopleWidgetDesc": "Selecione as pessoas que deseje vê-las na sua tela inicial.", + "albumsWidgetDesc": "Selecione os álbuns que deseje vê-los na sua tela inicial.", + "memoriesWidgetDesc": "Selecione os tipos de memórias que deseje vê-las na sua tela inicial.", + "smartMemories": "Memórias inteligentes", + "pastYearsMemories": "Memórias dos anos passados", + "deleteMultipleAlbumDialog": "E também excluir todas as fotos (e vídeos) presente dentro desses {count} álbuns e de todos os álbuns que eles fazem parte?", + "addParticipants": "Adicionar participante", + "selectedAlbums": "{count} selecionado(s)", + "actionNotSupportedOnFavouritesAlbum": "Ação não suportada em álbum favorito", + "onThisDayMemories": "Memórias deste dia", + "onThisDay": "Neste dia", + "lookBackOnYourMemories": "Revise suas memórias 🌄", + "newPhotosEmoji": " novo 📸", + "sorryWeHadToPauseYourBackups": "Desculpe, tivemos que pausar os salvamentos em segurança", + "clickToInstallOurBestVersionYet": "Clique para instalar a nossa melhor versão até então", + "onThisDayNotificationExplanation": "Receba lembretes de memórias deste dia em anos passados.", + "addMemoriesWidgetPrompt": "Adicione um widget de memória a sua tela inicial e volte aqui para personalizar.", + "addAlbumWidgetPrompt": "Adicione um widget de álbum a sua tela inicial e volte aqui para personalizar.", + "addPeopleWidgetPrompt": "Adicione um widget de pessoas a sua tela inicial e volte aqui para personalizar.", + "birthdayNotifications": "Notificações de aniversário", + "receiveRemindersOnBirthdays": "Receba notificações quando alguém fizer um aniversário. Tocar na notificação o levará às fotos do aniversariante.", + "happyBirthday": "Feliz aniversário! 🥳", + "happyBirthdayToPerson": "Feliz aniversário a {name}! 🎉", + "birthdays": "Aniversários", + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉", + "cLTitle1": "Upload de arquivos de vídeo grandes", + "cLDesc1": "Com a versão beta de streaming de vídeo e o trabalho em uploads e downloads resumíveis, agora aumentamos o limite de upload de arquivos para 10GB. Isso já está disponível nos aplicativos desktop e móvel.", + "cLTitle2": "Upload em segundo plano", + "cLDesc2": "Os uploads em segundo plano agora também são suportados no iOS, além dos dispositivos Android. Não é necessário abrir o aplicativo para fazer backup de suas fotos e vídeos mais recentes.", + "cLTitle3": "Reprodução automática de memórias", + "cLDesc3": "Fizemos melhorias significativas em nossa experiência de memórias, incluindo reprodução automática, deslizar para a próxima memória e muito mais.", + "cLTitle4": "Reconhecimento facial aprimorado", + "cLDesc4": "Junto com várias melhorias internas, agora é muito mais fácil ver todos os rostos detectados, fornecer feedback sobre rostos similares e adicionar/remover rostos de uma única foto.", + "cLTitle5": "Notificações de aniversário", + "cLDesc5": "Agora você receberá uma notificação opcional para todos os aniversários que salvou no Ente, junto com uma coleção de suas melhores fotos.", + "cLTitle6": "Uploads e downloads resumíveis", + "cLDesc6": "Não é mais necessário esperar que uploads/downloads sejam concluídos antes de fechar o aplicativo. Todos os uploads e downloads agora podem ser pausados no meio do caminho e retomados de onde você parou." } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_pt_PT.arb b/mobile/lib/l10n/intl_pt_PT.arb index 1a2549bd3f..9ca28bf1af 100644 --- a/mobile/lib/l10n/intl_pt_PT.arb +++ b/mobile/lib/l10n/intl_pt_PT.arb @@ -1,7 +1,10 @@ { "@@locale ": "en", - "enterYourEmailAddress": "Insira o seu endereço de email", + "enterYourEmailAddress": "Introduza o seu e-mail", + "enterYourNewEmailAddress": "Introduza o seu novo e-mail", "accountWelcomeBack": "Bem-vindo de volta!", + "emailAlreadyRegistered": "E-mail já em utilização.", + "emailNotRegistered": "E-mail não em utilização.", "email": "Email", "cancel": "Cancelar", "verify": "Verificar", @@ -185,6 +188,8 @@ }, "allowAddPhotosDescription": "Permitir que pessoas com o link também adicionem fotos ao álbum compartilhado.", "passwordLock": "Bloqueio da palavra-passe", + "canNotOpenTitle": "Não pôde abrir este álbum", + "canNotOpenBody": "Perdão, portanto o álbum não pode ser aberto na aplicação.", "disableDownloadWarningTitle": "Por favor, observe", "disableDownloadWarningBody": "Visualizadores ainda podem fazer capturas de tela ou salvar uma cópia das suas fotos usando ferramentas externas", "allowDownloads": "Permitir downloads", @@ -351,6 +356,7 @@ "failedToLoadAlbums": "Falha ao carregar álbuns", "hidden": "Oculto", "authToViewYourHiddenFiles": "Por favor, autentique para ver seus arquivos ocultos", + "authToViewTrashedFiles": "Autentica-se para visualizar os ficheiros na lata de lixo", "trash": "Lixo", "uncategorized": "Sem categoria", "videoSmallCase": "vídeo", @@ -366,6 +372,21 @@ "deleteFromBoth": "Apagar de ambos", "newAlbum": "Novo álbum", "albums": "Álbuns", + "memoryCount": "{count, plural, =0{não há memórias} one{{formattedCount} memória} other{{formattedCount} memórias}}", + "@memoryCount": { + "description": "The text to display the number of memories", + "type": "text", + "placeholders": { + "count": { + "example": "1", + "type": "int" + }, + "formattedCount": { + "type": "String", + "example": "11.513, 11,511" + } + } + }, "selectedPhotos": "{count} selecionado(s)", "@selectedPhotos": { "description": "Display the number of selected photos", @@ -397,6 +418,7 @@ "description": "The text to display in the advanced settings section" }, "photoGridSize": "Tamanho da grelha de fotos", + "manageDeviceStorage": "Gerir cache do aparelho", "manageDeviceStorageDesc": "Reveja e limpe o armazenamento de cache local.", "machineLearning": "Aprendizagem automática", "mlConsent": "Ativar aprendizagem automática", @@ -504,6 +526,7 @@ "viewLargeFiles": "Ficheiros grandes", "viewLargeFilesDesc": "Ver os ficheiros que estão a consumir a maior quantidade de armazenamento.", "noDuplicates": "✨ Sem duplicados", + "youveNoDuplicateFilesThatCanBeCleared": "Não tem nenhum ficheiro duplicado que possa ser eliminado", "success": "Sucesso", "rateUs": "Avalie-nos", "remindToEmptyDeviceTrash": "Esvazie também a opção “Eliminados recentemente” em “Definições” -> “Armazenamento” para reclamar o espaço libertado", @@ -672,6 +695,8 @@ "noPhotosAreBeingBackedUpRightNow": "No momento não há backup de fotos sendo feito", "preserveMore": "Preservar mais", "grantFullAccessPrompt": "Por favor, permita o acesso a todas as fotos nas definições do aplicativo", + "allowPermTitle": "Garanta acesso às fotos", + "allowPermBody": "Por favor, permita o acesso às suas fotos para que Ente possa mostrá-las e fazer backup na Fototeca.", "openSettings": "Abrir Definições", "selectMorePhotos": "Selecionar mais fotos", "existingUser": "Utilizador existente", @@ -697,6 +722,7 @@ "type": "text" }, "backupFailed": "Backup falhou", + "sorryBackupFailedDesc": "Perdão, mas não podemos fazer backup deste ficheiro agora, tentaremos mais tarde.", "couldNotBackUpTryLater": "Não foi possível fazer o backup de seus dados.\nTentaremos novamente mais tarde.", "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": "Ente pode criptografar e preservar arquivos apenas se você conceder acesso a eles", "pleaseGrantPermissions": "Por favor, conceda as permissões", @@ -768,6 +794,14 @@ "share": "Partilhar", "unhideToAlbum": "Mostrar para o álbum", "restoreToAlbum": "Restaurar para álbum", + "moveItem": "{count, plural, =1 {Mover item} other {Mover itens}}", + "@moveItem": { + "description": "Page title while moving one or more items to an album" + }, + "addItem": "{count, plural,=1 {Adicionar item} other {Adicionar itens}}", + "@addItem": { + "description": "Page title while adding one or more items to album" + }, "createOrSelectAlbum": "Criar ou selecionar álbum", "selectAlbum": "Selecionar álbum", "searchByAlbumNameHint": "Nome do álbum", @@ -865,6 +899,7 @@ "authToViewYourMemories": "Por favor, autentique-se para ver suas memórias", "unlock": "Desbloquear", "freeUpSpace": "Libertar espaço", + "freeUpSpaceSaving": "{count, plural, =1 {Pode eliminá-lo do aparelho para esvaziar {formattedSize}} other {Pode eliminá-los do aparelho para esvaziar {formattedSize}}}", "filesBackedUpInAlbum": "{count, plural, one {1 arquivo} other {{formattedNumber} arquivos}} neste álbum teve um backup seguro", "@filesBackedUpInAlbum": { "description": "Text to tell user how many files have been backed up in the album", @@ -895,6 +930,18 @@ } } }, + "@freeUpSpaceSaving": { + "description": "Text to tell user how much space they can free up by deleting items from the device" + }, + "freeUpAccessPostDelete": "Ainda pode acessá{count, plural, =1 {-lo} other {-los}} no Ente contanto que tenha uma subscrição ativa", + "@freeUpAccessPostDelete": { + "placeholders": { + "count": { + "example": "1", + "type": "int" + } + } + }, "freeUpAmount": "Libertar {sizeInMBorGB}", "thisEmailIsAlreadyInUse": "Este email já está em uso", "incorrectCode": "Código incorrecto", @@ -984,6 +1031,7 @@ "didYouKnow": "Você sabia?", "loadingMessage": "Carregar as suas fotos...", "loadMessage1": "Pode partilhar a sua subscrição com a sua família", + "loadMessage2": "Já contivemos 200 milhões de memórias até o momento", "loadMessage3": "Mantemos 3 cópias dos seus dados, uma em um abrigo subterrâneo", "loadMessage4": "Todos os nossos aplicativos são de código aberto", "loadMessage5": "Nosso código-fonte e criptografia foram auditadas externamente", @@ -1221,6 +1269,8 @@ "description": "Subtitle to indicate that the user can find people quickly by name" }, "findPeopleByName": "Encontrar pessoas rapidamente pelo nome", + "addViewers": "{count, plural, =0 {Adicionar visualizador} =1 {Adicionar visualizador} other {Adicionar vizualizadores}}", + "addCollaborators": "{count, plural, =0 {Adicionar colaborador} =1 {Adicionar colaborador} other {Adicionar colaboradores}}", "longPressAnEmailToVerifyEndToEndEncryption": "Pressione e segure um e-mail para verificar a criptografia de ponta a ponta.", "developerSettingsWarning": "Tem a certeza de que pretende modificar as definições de programador?", "developerSettings": "Definições do programador", @@ -1232,6 +1282,8 @@ "createCollaborativeLink": "Criar link colaborativo", "search": "Pesquisar", "enterPersonName": "Inserir nome da pessoa", + "editEmailAlreadyLinked": "Este e-mail já está ligado a {name}.", + "viewPersonToUnlink": "Ver {name} para desligar", "enterName": "Inserir nome", "savePerson": "Guardar pessoa", "editPerson": "Editar pessoa", @@ -1342,6 +1394,7 @@ "extraPhotosFound": "Fotos adicionais encontradas", "configuration": "Configuração", "localIndexing": "Indexação local", + "processed": "Processado", "resetPerson": "Remover", "areYouSureYouWantToResetThisPerson": "Tens a certeza de que queres repor esta pessoa?", "allPersonGroupingWillReset": "Todos os agrupamentos para esta pessoa serão reiniciados e perderá todas as sugestões feitas para esta pessoa", @@ -1349,6 +1402,18 @@ "onlyThem": "Apenas eles", "checkingModels": "A verificar modelos...", "enableMachineLearningBanner": "Habilitar aprendizagem automática para pesquisa mágica e reconhecimento de rosto", + "searchDiscoverEmptySection": "As imagens aparecerão aqui caso o processamento e sincronização for concluído", + "searchPersonsEmptySection": "As pessoas aparecerão aqui caso o processamento e sincronização for concluído", + "viewersSuccessfullyAdded": "{count, plural, =0 {Adicionado 0 vizualizadores} =1 {Adicionado 1 visualizador} other {Adicionado {count} visualizadores}}", + "@viewersSuccessfullyAdded": { + "placeholders": { + "count": { + "type": "int", + "example": "2" + } + }, + "description": "Number of viewers that were successfully added to an album." + }, "collaboratorsSuccessfullyAdded": "{count, plural, =0 {Adicionado 0 colaboradores} =1 {Adicionado 1 colaborador} other {Adicionado {count} colaboradores}}", "@collaboratorsSuccessfullyAdded": { "placeholders": { @@ -1388,10 +1453,321 @@ } } }, - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "tapToUploadIsIgnoredDue": "Clique para enviar, o envio foi ignorado devido a {ignoreReason}", + "@tapToUploadIsIgnoredDue": { + "description": "Shown in upload icon widet, inside a tooltip.", + "placeholders": { + "ignoreReason": { + "type": "String", + "example": "no network" + } + } + }, + "tapToUpload": "Clique para enviar", + "@tapToUpload": { + "description": "Shown in upload icon widet, inside a tooltip." + }, + "info": "Info", + "addFiles": "Adicionar Ficheiros", + "castAlbum": "Transfere Álbum", + "imageNotAnalyzed": "Imagem sem análise", + "noFacesFound": "Nenhum rosto foi detetado", + "fileNotUploadedYet": "Ficheiro não enviado ainda", + "noSuggestionsForPerson": "Sem sugestões para {personName}", + "@noSuggestionsForPerson": { + "placeholders": { + "personName": { + "type": "String", + "example": "Alice" + } + } + }, + "month": "mês", + "yearShort": "ano", + "@yearShort": { + "description": "Appears in pricing page (/yr)" + }, + "currentlyRunning": "em execução", + "ignored": "ignorado", + "photosCount": "{count, plural, =0 {0 fotos} =1 {1 foto} other {{count} fotos}}", + "@photosCount": { + "placeholders": { + "count": { + "type": "int", + "example": "2" + } + } + }, + "file": "Ficheiro", + "searchSectionsLengthMismatch": "Desigualdade de Largura entre Seções: {snapshotLength} != {searchLength}", + "@searchSectionsLengthMismatch": { + "description": "Appears in search tab page", + "placeholders": { + "snapshotLength": { + "type": "int", + "example": "1" + }, + "searchLength": { + "type": "int", + "example": "2" + } + } + }, + "selectMailApp": "Selecione Aplicação de Correios", + "selectAllShort": "Tudo", + "@selectAllShort": { + "description": "Text that appears in bottom right when you start to select multiple photos. When clicked, it selects all photos." + }, + "selectCoverPhoto": "Selecione Foto para Capa", + "newLocation": "Novo Lugar", + "faceNotClusteredYet": "Rosto não aglomerado ainda, retome mais tarde", + "theLinkYouAreTryingToAccessHasExpired": "A ligação que está a tentar acessar já expirou.", + "openFile": "Abrir o Ficheiro", + "backupFile": "Backup de Ficheiro", + "openAlbumInBrowser": "Abrir o Álbum em Navegador", + "openAlbumInBrowserTitle": "Utilize a Aplicação de Web Sítio para adicionar fotos ao álbum", + "allow": "Permitir", + "allowAppToOpenSharedAlbumLinks": "Permitir Aplicação Abrir Ligações Partilhadas", + "seePublicAlbumLinksInApp": "Ver Ligações Públicas na Aplicação", + "emergencyContacts": "Contactos de Emergência", + "acceptTrustInvite": "Aceite o Convite", + "declineTrustInvite": "Dispense o Convite", + "removeYourselfAsTrustedContact": "Retirar convosco dos contactos de confiança", + "legacy": "Revivência", + "legacyPageDesc": "A Revivência permite que contactos de confiança acessem a sua conta na sua inatividade.", + "legacyPageDesc2": "Contactos de confiança podem restaurar a sua conta, e se não lhes impedir em 30 dias, redefine a sua palavra-passe e acesse a sua conta.", + "legacyAccounts": "Contas revividas", + "trustedContacts": "Contactos de Confiança", + "addTrustedContact": "Adicionar Contacto de Confiança", + "removeInvite": "Retirar convite", + "recoveryWarning": "Um contacto de confiança está a tentar acessar a sua conta", + "rejectRecovery": "Recusar recuperação", + "recoveryInitiated": "Recuperação iniciada", + "recoveryInitiatedDesc": "Pode acessar a conta após {days} dias. Uma notificação será enviada para {email}.", + "@recoveryInitiatedDesc": { + "placeholders": { + "days": { + "type": "int", + "example": "30" + }, + "email": { + "type": "String", + "example": "me@example.com" + } + } + }, + "cancelAccountRecovery": "Cancelar recuperação", + "recoveryAccount": "Recuperar Conta", + "cancelAccountRecoveryBody": "Quer mesmo cancelar a recuperação?", + "startAccountRecoveryTitle": "Começar Recuperação", + "whyAddTrustContact": "O contacto de confiança pode ajudar na recuperação dos seus dados.", + "recoveryReady": "Agora pode recuperar a conta de {email} definindo uma nova palavra-passe.", + "@recoveryReady": { + "placeholders": { + "email": { + "type": "String", + "example": "me@example.com" + } + } + }, + "recoveryWarningBody": "{email} está a tentar recuperar a sua conta.", + "trustedInviteBody": "Foste convidado para ser um contacto revivido de {email}.", + "warning": "Alerta", + "proceed": "Continuar", + "confirmAddingTrustedContact": "Está prestes a adicionar {email} como contacto de confiança. Eles poderão recuperar a sua conta caso esteja inativo por {numOfDays} dias.", + "@confirmAddingTrustedContact": { + "placeholders": { + "email": { + "type": "String", + "example": "me@example.com" + }, + "numOfDays": { + "type": "int", + "example": "30" + } + } + }, + "legacyInvite": "{email} convidou-lhe a ser um contacto de confiança", + "authToManageLegacy": "Autentica-se para gerir os seus contactos de confiança", + "useDifferentPlayerInfo": "A ter problemas reproduzindo este vídeo? Prima aqui para tentar outro reprodutor.", + "hideSharedItemsFromHomeGallery": "Esconder Itens Partilhados da Galeria Inicial", + "gallery": "Galeria", + "joinAlbum": "Aderir ao Álbum", + "joinAlbumSubtext": "para ver e adicionar as suas fotos", + "joinAlbumSubtextViewer": "para adicionar isto aos álbuns partilhados", + "join": "Aderir", + "linkEmail": "Ligar e-mail", + "link": "Ligar", + "noEnteAccountExclamation": "Nenhuma conta do Ente!", + "orPickFromYourContacts": "ou selecione dos seus contactos", + "emailDoesNotHaveEnteAccount": "{email} não há uma conta no Ente.", + "@emailDoesNotHaveEnteAccount": { + "description": "Shown when email doesn't have an Ente account", + "placeholders": { + "email": { + "type": "String" + } + } + }, + "accountOwnerPersonAppbarTitle": "{title} (Eu)", + "@accountOwnerPersonAppbarTitle": { + "description": "Title of appbar for account owner person", + "placeholders": { + "title": { + "type": "String" + } + } + }, + "reassignMe": "Retribua \"Mim\"", + "me": "Eu", + "linkEmailToContactBannerCaption": "para partilha ágil", + "@linkEmailToContactBannerCaption": { + "description": "Caption for the 'Link email' title. It should be a continuation of the 'Link email' title. Just like how 'Link email' + 'for faster sharing' forms a proper sentence in English, the combination of these two strings should also be a proper sentence in other languages." + }, + "selectPersonToLink": "Selecione uma pessoa para ligar-se", + "linkPersonToEmail": "Ligar pessoa a {email}", + "@linkPersonToEmail": { + "placeholders": { + "email": { + "type": "String" + } + } + }, + "linkPersonToEmailConfirmation": "Isto ligará {personName} a {email}", + "@linkPersonToEmailConfirmation": { + "description": "Confirmation message when linking a person to an email", + "placeholders": { + "personName": { + "type": "String" + }, + "email": { + "type": "String" + } + } + }, + "selectYourFace": "Selecionar o seu rosto", + "reassigningLoading": "A retribuir...", + "reassignedToName": "Retribuiu tu a {name}", + "@reassignedToName": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "saveChangesBeforeLeavingQuestion": "Guardar as alterações antes de sair?", + "dontSave": "Não guarde", + "thisIsMeExclamation": "Este sou eu!", + "linkPerson": "Ligar pessoa", + "linkPersonCaption": "para melhor experiência de partilha", + "@linkPersonCaption": { + "description": "Caption for the 'Link person' title. It should be a continuation of the 'Link person' title. Just like how 'Link person' + 'for better sharing experience' forms a proper sentence in English, the combination of these two strings should also be a proper sentence in other languages." + }, + "videoStreaming": "Vídeos transmissíveis", + "processingVideos": "A processar vídeos", + "streamDetails": "Detalhes do em direto", + "processing": "A processar", + "queued": "Em fila", + "ineligible": "Inelegível", + "failed": "Falha", + "playStream": "Ver em direto", + "playOriginal": "Ver original", + "joinAlbumConfirmationDialogBody": "Aderir a um álbum fará o seu e-mail visível aos participantes.", + "pleaseWaitThisWillTakeAWhile": "Espera um pouco, isto deve levar um tempo.", + "editTime": "Editar tempo", + "selectTime": "Selecionar tempo", + "selectDate": "Selecionar data", + "previous": "Anterior", + "selectOneDateAndTimeForAll": "Selecionar uma data e hora a todos", + "selectStartOfRange": "Selecionar início de intervalo", + "thisWillMakeTheDateAndTimeOfAllSelected": "Isto fará a data e hora de todas as fotos o mesmo.", + "allWillShiftRangeBasedOnFirst": "Este é o primeiro neste grupo. Outras fotos selecionadas serão automaticamente alteradas para a nova data", + "newRange": "Novo intervalo", + "selectOneDateAndTime": "Selecione uma Data e Hora", + "moveSelectedPhotosToOneDate": "Alterar datas de Fotos ao Selecionado", + "shiftDatesAndTime": "Mude as Datas e Horas", + "photosKeepRelativeTimeDifference": "As Fotos continuam com uma diferença de horário relativo", + "photocountPhotos": "{count, plural, =0 {Sem fotos} =1 {1 foto} other {{count} fotos}}", + "@photocountPhotos": { + "placeholders": { + "count": { + "type": "int", + "example": "2" + } + } + }, + "appIcon": "Ícone da Aplicação", + "notThisPerson": "Não é esta pessoa?", + "selectedItemsWillBeRemovedFromThisPerson": "Os itens em seleção serão removidos desta pessoa, mas não da sua biblioteca.", + "throughTheYears": "{dateFormat} com o avanço dos anos", + "thisWeekThroughTheYears": "Esta semana com o avanço dos anos", + "thisWeekXYearsAgo": "{count, plural, =1 {Esta semana, {count} ano atrás} other {Esta semana, {count} anos atrás}}", + "youAndThem": "Tu e {name}", + "admiringThem": "A admirar {name}", + "embracingThem": "A abraçar {name}", + "partyWithThem": "Tendo uma festa com {name}", + "hikingWithThem": "Passeando com {name}", + "feastingWithThem": "A comer com {name}", + "selfiesWithThem": "A captar selfies com {name}", + "posingWithThem": "A posicionar com {name}", + "backgroundWithThem": "Vistas deslumbrantes com {name}", + "sportsWithThem": "A praticar esportes com {name}", + "roadtripWithThem": "A viajar na rua com {name}", + "spotlightOnYourself": "A dar destaque em vos", + "spotlightOnThem": "A dar destaque em {name}", + "personIsAge": "{name} tem {age} anos!", + "personTurningAge": "{name} fará {age} anos em breve", + "lastTimeWithThem": "Últimos momentos com {name}", + "tripToLocation": "Viagem para {location}", + "tripInYear": "Viajem em {year}", + "lastYearsTrip": "Viagem do ano passado", + "sunrise": "No horizonte", + "mountains": "Sobre as colinas", + "greenery": "A vida esverdeada", + "beach": "A areia e o mar", + "city": "Na cidade", + "moon": "Na luz da lua", + "onTheRoad": "Na rua de novo", + "food": "Culinária saborosa", + "pets": "Acompanhantes peludos", + "curatedMemories": "Memórias curadas", + "widgets": "Widgets", + "memories": "Memórias", + "peopleWidgetDesc": "Seleciona as pessoas que adoraria ver no seu ecrã inicial.", + "albumsWidgetDesc": "Seleciona os álbuns que adoraria ver no seu ecrã inicial.", + "memoriesWidgetDesc": "Seleciona os tipos de memórias que adoraria ver no seu ecrã inicial.", + "smartMemories": "Memórias inteligentes", + "pastYearsMemories": "Memórias de anos passados", + "deleteMultipleAlbumDialog": "Também eliminar fotos (e vídeos) presentes em {count} álbuns e de todos os outros álbuns que fazem parte?", + "addParticipants": "Adicionar participante", + "selectedAlbums": "{count} selecionado(s)", + "actionNotSupportedOnFavouritesAlbum": "Ação não suportada no álbum de Preferidos", + "onThisDayMemories": "Memórias deste dia", + "onThisDay": "Neste dia", + "lookBackOnYourMemories": "Revê as suas memórias 🌄", + "newPhotosEmoji": " novo 📸", + "sorryWeHadToPauseYourBackups": "Perdão, precisamos parar seus backups", + "clickToInstallOurBestVersionYet": "Clica para transferir a melhor versão", + "onThisDayNotificationExplanation": "Obtém lembretes de memórias deste dia em anos passados.", + "addMemoriesWidgetPrompt": "Adiciona um widget de memórias no seu ecrã inicial e volte aqui para personalizar.", + "addAlbumWidgetPrompt": "Adiciona um widget de álbum no seu ecrã inicial e volte aqui para personalizar.", + "addPeopleWidgetPrompt": "Adiciona um widget de pessoas no seu ecrã inicial e volte aqui para personalizar.", + "birthdayNotifications": "Notificações de felicidades", + "receiveRemindersOnBirthdays": "Obtém lembretes de quando é aniversário de alguém. Apertar na notificação o levará às fotos do aniversariante.", + "happyBirthday": "Felicidades! 🥳", + "happyBirthdayToPerson": "Felicidades para {name}! 🎉", + "birthdays": "Aniversários", + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉", + "cLTitle1": "Envio de ficheiros de vídeo grandes", + "cLDesc1": "Na sequência da versão beta de transmissão de vídeo e do trabalho em envios e transferências retomáveis, agora aumentámos o limite de envio de ficheiros para 10GB. Isto está agora disponível tanto nas aplicações de computador como móveis.", + "cLTitle2": "Envio em segundo plano", + "cLDesc2": "Os envios em segundo plano agora também são suportados no iOS, além dos dispositivos Android. Não é necessário abrir a aplicação para fazer uma cópia de segurança das suas fotografias e vídeos mais recentes.", + "cLTitle3": "Reprodução automática de memórias", + "cLDesc3": "Fizemos melhorias significativas na nossa experiência de memórias, incluindo reprodução automática, deslizar para a próxima memória e muito mais.", + "cLTitle4": "Reconhecimento facial melhorado", + "cLDesc4": "Juntamente com várias melhorias internas, agora é muito mais fácil ver todas as faces detectadas, fornecer comentários sobre faces similares e adicionar/remover faces de uma única fotografia.", + "cLTitle5": "Notificações de aniversário", + "cLDesc5": "Agora receberá uma notificação opcional para todos os aniversários que guardou no Ente, juntamente com uma colecção das suas melhores fotografias.", + "cLTitle6": "Envios e transferências retomáveis", + "cLDesc6": "Já não é necessário esperar que os envios/transferências sejam concluídos antes de poder fechar a aplicação. Todos os envios e transferências têm agora a capacidade de serem pausados a meio e retomados de onde parou." } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ro.arb b/mobile/lib/l10n/intl_ro.arb index 685c7bbf87..3845e966ca 100644 --- a/mobile/lib/l10n/intl_ro.arb +++ b/mobile/lib/l10n/intl_ro.arb @@ -443,7 +443,7 @@ "selectAll": "Selectare totală", "skip": "Omiteți", "updatingFolderSelection": "Se actualizează selecția dosarelor...", - "itemCount": "{count, plural, one{{count} articol} few {{count} articole} other{{count} de articole}}", + "itemCount": "{count, plural, one{{count} articol} other{{count} de articole}}", "deleteItemCount": "{count, plural, =1 {Ștergeți {count} articol} other {Ștergeți {count} de articole}}", "duplicateItemsGroup": "{count} fișiere, {formattedSize} fiecare", "@duplicateItemsGroup": { @@ -461,7 +461,7 @@ } }, "showMemories": "Afișare amintiri", - "yearsAgo": "{count, plural, one{acum {count} an} few {acum {count} ani} other{acum {count} de ani}}", + "yearsAgo": "{count, plural, one{acum {count} an} other{acum {count} de ani}}", "backupSettings": "Setări copie de rezervă", "backupStatus": "Stare copie de rezervă", "backupStatusDescription": "Articolele care au fost salvate vor apărea aici", @@ -526,7 +526,7 @@ }, "remindToEmptyEnteTrash": "De asemenea, goliți „Coșul de gunoi” pentru a revendica spațiul eliberat", "sparkleSuccess": "✨ Succes", - "duplicateFileCountWithStorageSaved": "Ați curățat {count, plural, one{{count} dublură} few {{count} dubluri} other{{count} de dubluri}}, economisind ({storageSaved}!)", + "duplicateFileCountWithStorageSaved": "Ați curățat {count, plural, one{{count} dublură} other{{count} de dubluri}}, economisind ({storageSaved}!)", "@duplicateFileCountWithStorageSaved": { "description": "The text to display when the user has successfully cleaned up duplicate files", "type": "text", @@ -873,7 +873,7 @@ "authToViewYourMemories": "Vă rugăm să vă autentificați pentru a vă vizualiza amintirile", "unlock": "Deblocare", "freeUpSpace": "Eliberați spațiu", - "filesBackedUpInAlbum": "{count, plural, one {Un fișier din acest album a fost deja salvat în siguranță} few {{formattedNumber} fișiere din acest album au fost deja salvate în siguranță} other {{formattedNumber} de fișiere din acest album au fost deja salvate în siguranță}}", + "filesBackedUpInAlbum": "{count, plural, one {Un fișier din acest album a fost deja salvat în siguranță} other {{formattedNumber} de fișiere din acest album au fost deja salvate în siguranță}}", "@filesBackedUpInAlbum": { "description": "Text to tell user how many files have been backed up in the album", "placeholders": { @@ -888,7 +888,7 @@ } } }, - "filesBackedUpFromDevice": "{count, plural, one {Un fișier de pe acest dispozitiv a fost deja salvat în siguranță} few {{formattedNumber} fișiere de pe acest dispozitiv au fost deja salvate în siguranță} other {{formattedNumber} de fișiere de pe acest dispozitiv fost deja salvate în siguranță}}", + "filesBackedUpFromDevice": "{count, plural, one {Un fișier de pe acest dispozitiv a fost deja salvat în siguranță} other {{formattedNumber} de fișiere de pe acest dispozitiv fost deja salvate în siguranță}}", "@filesBackedUpFromDevice": { "description": "Text to tell user how many files have been backed up from this device", "placeholders": { @@ -1177,7 +1177,7 @@ "searchHint4": "Locație", "searchHint5": "În curând: chipuri și căutare magică ✨", "addYourPhotosNow": "Adăugați-vă fotografiile acum", - "searchResultCount": "{count, plural, one{{count} rezultat găsit} few {{count} rezultate găsite} other{{count} de rezultate găsite}}", + "searchResultCount": "{count, plural, one{{count} rezultat găsit} other{{count} de rezultate găsite}}", "@searchResultCount": { "description": "Text to tell user how many results were found for their search query", "placeholders": { @@ -1523,10 +1523,5 @@ "joinAlbumSubtext": "pentru a vedea și a adăuga fotografii", "joinAlbumSubtextViewer": "pentru a adăuga la albumele distribuite", "join": "Alăturare", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ru.arb b/mobile/lib/l10n/intl_ru.arb index fbc457de43..ab26a55420 100644 --- a/mobile/lib/l10n/intl_ru.arb +++ b/mobile/lib/l10n/intl_ru.arb @@ -476,7 +476,7 @@ } }, "showMemories": "Показывать воспоминания", - "yearsAgo": "{count, plural, one{{count} год назад} few{{count} года назад} other{{count} лет назад}}", + "yearsAgo": "{count, plural, one{{count} год назад} other{{count} лет назад}}", "backupSettings": "Настройки резервного копирования", "backupStatus": "Статус резервного копирования", "backupStatusDescription": "Элементы, сохранённые в резервной копии, появятся здесь", @@ -1724,21 +1724,18 @@ "onTheRoad": "Снова в пути", "food": "Кулинарное наслаждение", "pets": "Пушистые спутники", - "cLIcon": "Новая иконка", - "cLIconDesc": "Наконец-то новая иконка приложения, которая, как мы считаем, лучше всего отражает нашу работу. Мы также добавили переключатель иконок, чтобы вы могли продолжать использовать старую иконку.", - "cLMemories": "Воспоминания", - "cLMemoriesDesc": "Откройте заново свои особенные моменты — в центре внимания ваши любимые люди, поездки и праздники, лучшие снимки и многое другое. Для наилучших впечатлений включите машинное обучение и отметьте себя и своих друзей.", - "cLWidgets": "Виджеты", - "cLWidgetsDesc": "Теперь доступны виджеты домашнего экрана, интегрированные с воспоминаниями. Они покажут ваши особенные моменты, не открывая приложения.", - "cLFamilyPlan": "Ограничения семейного тарифа", - "cLFamilyPlanDesc": "Теперь вы можете установить ограничения на объём хранилища, которое могут использовать члены вашей семьи.", - "cLBulkEdit": "Массовое редактирование дат", - "cLBulkEditDesc": "Теперь вы можете выбрать несколько фото и отредактировать дату/время быстро и сразу для всех. Также поддерживается смещение дат.", "curatedMemories": "Отобранные воспоминания", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉", + "cLTitle1": "Загрузка больших видеофайлов", + "cLDesc1": "Вслед за бета-версией потокового видео и работой над возобновляемыми загрузками и скачиваниями, мы увеличили лимит загрузки файлов до 10ГБ. Это теперь доступно как в настольных, так и в мобильных приложениях.", + "cLTitle2": "Фоновая загрузка", + "cLDesc2": "Фоновые загрузки теперь также поддерживаются на iOS, в дополнение к устройствам Android. Больше не нужно открывать приложение для резервного копирования ваших последних фото и видео.", + "cLTitle3": "Автовоспроизведение воспоминаний", + "cLDesc3": "Мы внесли значительные улучшения в наш опыт воспоминаний, включая автовоспроизведение, пролистывание к следующему воспоминанию и многое другое.", + "cLTitle4": "Улучшенное распознавание лиц", + "cLDesc4": "Наряду с множеством внутренних улучшений, теперь гораздо проще увидеть все обнаруженные лица, предоставить обратную связь о похожих лицах и добавить/удалить лица с одной фотографии.", + "cLTitle5": "Уведомления о днях рождения", + "cLDesc5": "Теперь вы будете получать опциональные уведомления обо всех днях рождения, которые вы сохранили в Ente, вместе с коллекцией их лучших фотографий.", + "cLTitle6": "Возобновляемые загрузки и скачивания", + "cLDesc6": "Больше не нужно ждать завершения загрузок/скачиваний перед закрытием приложения. Все загрузки и скачивания теперь могут быть приостановлены на полпути и возобновлены с того места, где вы остановились." } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_sl.arb b/mobile/lib/l10n/intl_sl.arb index 00a3e71e90..bfa658ba0d 100644 --- a/mobile/lib/l10n/intl_sl.arb +++ b/mobile/lib/l10n/intl_sl.arb @@ -1,9 +1,4 @@ { "@@locale ": "en", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_sr.arb b/mobile/lib/l10n/intl_sr.arb new file mode 100644 index 0000000000..1a228916bb --- /dev/null +++ b/mobile/lib/l10n/intl_sr.arb @@ -0,0 +1,11 @@ +{ + "@@locale ": "en", + "showMoreFaces": "Show more faces", + "showLessFaces": "Show less faces", + "otherDetectedFaces": "Other detected faces", + "areYouSureRemoveThisFaceFromPerson": "Are you sure you want to remove this face from this person?", + "areThey": "Are they ", + "questionmark": "?", + "saveAsAnotherPerson": "Save as another person", + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_sv.arb b/mobile/lib/l10n/intl_sv.arb index e208dc1ed5..eb2db61ecc 100644 --- a/mobile/lib/l10n/intl_sv.arb +++ b/mobile/lib/l10n/intl_sv.arb @@ -364,7 +364,7 @@ "selectAll": "Markera allt", "skip": "Hoppa över", "updatingFolderSelection": "Uppdaterar mappval...", - "itemCount": "{count, plural, one{{count} objekt} other{{count} objekt}}", + "itemCount": "{count, plural, other{{count} objekt}}", "deleteItemCount": "{count, plural, =1 {Radera {count} objekt} other {Radera {count} objekt}}", "duplicateItemsGroup": "{count} filer, {formattedSize} vardera", "@duplicateItemsGroup": { @@ -382,7 +382,7 @@ } }, "showMemories": "Visa minnen", - "yearsAgo": "{count, plural, one{{count} år sedan} other{{count} år sedan}}", + "yearsAgo": "{count, plural, other{{count} år sedan}}", "backupSettings": "Säkerhetskopieringsinställningar", "backupStatus": "Säkerhetskopieringsstatus", "about": "Om", @@ -496,7 +496,7 @@ "viewAll": "Visa alla", "inviteYourFriendsToEnte": "Bjud in dina vänner till Ente", "fileTypes": "Filtyper", - "searchResultCount": "{count, plural, one{{count} resultat hittades} other{{count} resultat hittades}}", + "searchResultCount": "{count, plural, other{{count} resultat hittades}}", "@searchResultCount": { "description": "Text to tell user how many results were found for their search query", "placeholders": { @@ -532,10 +532,12 @@ "newPerson": "Ny person", "addName": "Lägg till namn", "add": "Lägg till", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉", + "showMoreFaces": "Show more faces", + "showLessFaces": "Show less faces", + "otherDetectedFaces": "Other detected faces", + "areYouSureRemoveThisFaceFromPerson": "Are you sure you want to remove this face from this person?", + "areThey": "Are they ", + "questionmark": "?", + "saveAsAnotherPerson": "Save as another person" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ta.arb b/mobile/lib/l10n/intl_ta.arb index cbe223602b..980f0a9544 100644 --- a/mobile/lib/l10n/intl_ta.arb +++ b/mobile/lib/l10n/intl_ta.arb @@ -20,10 +20,5 @@ "yourAccountHasBeenDeleted": "உங்கள் கணக்கு நீக்கப்பட்டது", "selectReason": "காரணத்தைத் தேர்ந்தெடுக்கவும்", "deleteReason1": "எனக்கு தேவையான ஒரு முக்கிய அம்சம் இதில் இல்லை", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_te.arb b/mobile/lib/l10n/intl_te.arb index 00a3e71e90..bfa658ba0d 100644 --- a/mobile/lib/l10n/intl_te.arb +++ b/mobile/lib/l10n/intl_te.arb @@ -1,9 +1,4 @@ { "@@locale ": "en", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_th.arb b/mobile/lib/l10n/intl_th.arb index a81dd7d64b..499066e239 100644 --- a/mobile/lib/l10n/intl_th.arb +++ b/mobile/lib/l10n/intl_th.arb @@ -288,10 +288,5 @@ }, "maps": "แผนที่", "enableMaps": "เปิดใช้งานแผนที่", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ti.arb b/mobile/lib/l10n/intl_ti.arb index 00a3e71e90..bfa658ba0d 100644 --- a/mobile/lib/l10n/intl_ti.arb +++ b/mobile/lib/l10n/intl_ti.arb @@ -1,9 +1,4 @@ { "@@locale ": "en", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_tr.arb b/mobile/lib/l10n/intl_tr.arb index f41b273729..353915d16e 100644 --- a/mobile/lib/l10n/intl_tr.arb +++ b/mobile/lib/l10n/intl_tr.arb @@ -1,6 +1,7 @@ { "@@locale ": "en", "enterYourEmailAddress": "E-posta adresinizi girin", + "enterYourNewEmailAddress": "Yeni e-posta adresinizi girin", "accountWelcomeBack": "Tekrar hoş geldiniz!", "emailAlreadyRegistered": "Bu e-posta adresi zaten kayıtlı.", "emailNotRegistered": "Bu e-posta adresi sistemde kayıtlı değil.", @@ -340,7 +341,7 @@ "deleteSharedAlbumDialogBody": "Albüm herkes için silinecek\n\nBu albümdeki başkalarına ait paylaşılan fotoğraflara erişiminizi kaybedeceksiniz", "yesRemove": "Evet, sil", "creatingLink": "Bağlantı oluşturuluyor...", - "removeWithQuestionMark": "Kaldır?", + "removeWithQuestionMark": "Kaldırılsın mı?", "removeParticipantBody": "{userEmail} bu paylaşılan albümden kaldırılacaktır\n\nOnlar tarafından eklenen tüm fotoğraflar da albümden kaldırılacaktır", "keepPhotos": "Fotoğrafları sakla", "deletePhotos": "Fotoğrafları sil", @@ -371,7 +372,7 @@ "deleteFromBoth": "Her ikisinden de sil", "newAlbum": "Yeni albüm", "albums": "Albümler", - "memoryCount": "{count, plural, =0{hiç anı yok} one{{formattedCount} anı} other{{formattedCount} anı}}", + "memoryCount": "{count, plural, =0{hiç anı yok} other{{formattedCount} anı}}", "@memoryCount": { "description": "The text to display the number of memories", "type": "text", @@ -476,7 +477,7 @@ } }, "showMemories": "Anıları göster", - "yearsAgo": "{count, plural, one{{count} yıl önce} other{{count} yıl önce}}", + "yearsAgo": "{count, plural, other{{count} yıl önce}}", "backupSettings": "Yedekleme seçenekleri", "backupStatus": "Yedekleme durumu", "backupStatusDescription": "Eklenen öğeler burada görünecek", @@ -655,7 +656,7 @@ "askCancelReason": "Aboneliğiniz iptal edilmiştir. Bunun sebebini paylaşmak ister misiniz?", "thankYouForSubscribing": "Abone olduğunuz için teşekkürler!", "yourPurchaseWasSuccessful": "Satın alım başarılı", - "yourPlanWasSuccessfullyUpgraded": "Planınız başarılı şekilde yükseltildi", + "yourPlanWasSuccessfullyUpgraded": "Planınız başarıyla yükseltildi", "yourPlanWasSuccessfullyDowngraded": "Planınız başarıyla düşürüldü", "yourSubscriptionWasUpdatedSuccessfully": "Aboneliğiniz başarıyla güncellendi", "googlePlayId": "Google Play ID", @@ -700,7 +701,7 @@ "selectMorePhotos": "Daha Fazla Fotoğraf Seç", "existingUser": "Mevcut kullanıcı", "privateBackups": "Özel yedeklemeler", - "forYourMemories": "anıların için", + "forYourMemories": "anılarınız için", "endtoendEncryptedByDefault": "Varsayılan olarak uçtan uca şifrelenmiş", "safelyStored": "Güvenle saklanır", "atAFalloutShelter": "serpinti sığınağında", @@ -1216,7 +1217,7 @@ "searchHint4": "Konum", "searchHint5": "Çok yakında: Yüzler ve sihirli arama ✨", "addYourPhotosNow": "Fotoğraflarınızı şimdi ekleyin", - "searchResultCount": "{count, plural, one{{count} yıl önce} other{{count} yıl önce}}", + "searchResultCount": "{count, plural, other{{count} yıl önce}}", "@searchResultCount": { "description": "Text to tell user how many results were found for their search query", "placeholders": { @@ -1729,21 +1730,11 @@ "onTheRoad": "Yeniden yollarda", "food": "Yemek keyfi", "pets": "Tüylü dostlar", - "cLIcon": "Yeni Simge", - "cLIconDesc": "Son olarak, çalışmalarımızı en iyi şekilde temsil ettiğini düşündüğümüz yeni bir uygulama simgesi. Eski simgeyi kullanmaya devam edebilmeniz için bir simge değiştirici de ekledik.", - "cLMemories": "Anılar", - "cLMemoriesDesc": "Özel anlarınızı yeniden keşfedin - en sevdiğiniz kişilere, seyahatlerinize ve tatillerinize, en iyi tıklamalarınıza ve çok daha fazlasına odaklanın. En iyi deneyim için makine öğrenimini açın, kendinizi etiketleyin ve arkadaşlarınızı adlandırın.", - "cLWidgets": "Widget'lar", - "cLWidgetsDesc": "Anılarla entegre edilmiş ana ekran widget'ları artık kullanılabilir. Uygulamayı açmadan özel anlarınızı gösterir.", - "cLFamilyPlan": "Aile Planı Sınırları", - "cLFamilyPlanDesc": "Artık aile üyelerinizin ne kadar depolama alanı kullanabileceğine dair sınırlar belirleyebilirsiniz.", - "cLBulkEdit": "Tarihleri toplu düzenle", - "cLBulkEditDesc": "Artık birden fazla fotoğraf seçebilir ve tek bir hızlı işlemle hepsi için tarih/saat düzenleyebilirsiniz. Tarih kaydırma da desteklenmektedir.", "curatedMemories": "Seçilmiş anılar", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "deleteMultipleAlbumDialog": "Ayrıca bu {count} albümde bulunan fotoğrafları (ve videoları) parçası oldukları tüm diğer albümlerden silmek istiyor musunuz?", + "addParticipants": "Katılımcı ekle", + "selectedAlbums": "{count} seçildi", + "actionNotSupportedOnFavouritesAlbum": "Favoriler albümünde eylem desteklenmiyor", + "onThisDay": "Bu günde", + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_uk.arb b/mobile/lib/l10n/intl_uk.arb index e4829020f1..09a016b224 100644 --- a/mobile/lib/l10n/intl_uk.arb +++ b/mobile/lib/l10n/intl_uk.arb @@ -438,7 +438,7 @@ "selectAll": "Вибрати все", "skip": "Пропустити", "updatingFolderSelection": "Оновлення вибору теки...", - "itemCount": "{count, plural, one{{count} елемент} few {{count} елементи} many {{count} елементів} other{{count} елементів}}", + "itemCount": "{count, plural, one{{count} елемент} other{{count} елементів}}", "deleteItemCount": "{count, plural, =1 {Видалено {count} елемент} other {Видалено {count} елементів}}", "duplicateItemsGroup": "{count} файлів, кожен по {formattedSize}", "@duplicateItemsGroup": { @@ -1172,7 +1172,7 @@ "searchHint4": "Розташування", "searchHint5": "Незабаром: Обличчя і магічний пошук ✨", "addYourPhotosNow": "Додайте свої фотографії", - "searchResultCount": "{count, plural, one{Знайдено {count} результат} few {Знайдено {count} результати} many {Знайдено {count} результатів} other{Знайдено {count} результати}}", + "searchResultCount": "{count, plural, one{Знайдено {count} результат} other{Знайдено {count} результати}}", "@searchResultCount": { "description": "Text to tell user how many results were found for their search query", "placeholders": { @@ -1511,10 +1511,5 @@ "legacyInvite": "{email} запросив вас стати довіреною особою", "authToManageLegacy": "Авторизуйтесь, щоби керувати довіреними контактами", "useDifferentPlayerInfo": "Виникли проблеми з відтворенням цього відео? Натисніть і утримуйте тут, щоб спробувати інший плеєр.", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_vi.arb b/mobile/lib/l10n/intl_vi.arb index 3513147fac..eda98f49d6 100644 --- a/mobile/lib/l10n/intl_vi.arb +++ b/mobile/lib/l10n/intl_vi.arb @@ -443,7 +443,7 @@ "selectAll": "Chọn tất cả", "skip": "Bỏ qua", "updatingFolderSelection": "Đang cập nhật lựa chọn thư mục...", - "itemCount": "{count, plural, one{{count} mục} other{{count} mục}}", + "itemCount": "{count, plural, other{{count} mục}}", "deleteItemCount": "{count, plural, =1 {Xóa {count} mục} other {Xóa {count} mục}}", "duplicateItemsGroup": "{count} tệp, {formattedSize} mỗi tệp", "@duplicateItemsGroup": { @@ -461,7 +461,7 @@ } }, "showMemories": "Hiển thị kỷ niệm", - "yearsAgo": "{count, plural, one{{count} năm trước} other{{count} năm trước}}", + "yearsAgo": "{count, plural, other{{count} năm trước}}", "backupSettings": "Cài đặt sao lưu", "backupStatus": "Trạng thái sao lưu", "backupStatusDescription": "Các mục đã được sao lưu sẽ hiển thị ở đây", @@ -526,7 +526,7 @@ }, "remindToEmptyEnteTrash": "Cũng hãy xóa \"Thùng rác\" của bạn để chiếm không gian đã giải phóng", "sparkleSuccess": "✨ Thành công", - "duplicateFileCountWithStorageSaved": "Bạn đã dọn dẹp {count, plural, one{{count} tệp trùng lặp} other{{count} tệp trùng lặp}}, tiết kiệm ({storageSaved}!)", + "duplicateFileCountWithStorageSaved": "Bạn đã dọn dẹp {count, plural, other{{count} tệp trùng lặp}}, tiết kiệm ({storageSaved}!)", "@duplicateFileCountWithStorageSaved": { "description": "The text to display when the user has successfully cleaned up duplicate files", "type": "text", @@ -873,6 +873,7 @@ "authToViewYourMemories": "Vui lòng xác thực để xem kỷ niệm của bạn", "unlock": "Mở khóa", "freeUpSpace": "Giải phóng không gian", + "freeUpSpaceSaving": "{count, plural, =1 {Nó có thể được xóa khỏi thiết bị để giải phóng {formattedSize}} other {Chúng có thể được xóa khỏi thiết bị để giải phóng {formattedSize}}}", "filesBackedUpInAlbum": "{count, plural, one {1 tệp} other {{formattedNumber} tệp}} trong album này đã được sao lưu an toàn", "@filesBackedUpInAlbum": { "description": "Text to tell user how many files have been backed up in the album", @@ -903,6 +904,9 @@ } } }, + "@freeUpSpaceSaving": { + "description": "Text to tell user how much space they can free up by deleting items from the device" + }, "freeUpAmount": "Giải phóng {sizeInMBorGB}", "thisEmailIsAlreadyInUse": "Email này đã được sử dụng", "incorrectCode": "Mã không chính xác", @@ -1177,7 +1181,7 @@ "searchHint4": "Vị trí", "searchHint5": "Sắp có: Nhận diện khuôn mặt & tìm kiếm ma thuật ✨", "addYourPhotosNow": "Thêm ảnh của bạn ngay bây giờ", - "searchResultCount": "{count, plural, one{{count} kết quả được tìm thấy} other{{count} kết quả được tìm thấy}}", + "searchResultCount": "{count, plural, other{{count} kết quả được tìm thấy}}", "@searchResultCount": { "description": "Text to tell user how many results were found for their search query", "placeholders": { @@ -1533,10 +1537,5 @@ "joinAlbumSubtext": "để xem và thêm ảnh của bạn", "joinAlbumSubtextViewer": "thêm vào album được chia sẻ", "join": "Tham gia", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_zh.arb b/mobile/lib/l10n/intl_zh.arb index 9a26183f57..3da8ee7ff3 100644 --- a/mobile/lib/l10n/intl_zh.arb +++ b/mobile/lib/l10n/intl_zh.arb @@ -458,7 +458,7 @@ "selectAll": "全选", "skip": "跳过", "updatingFolderSelection": "正在更新文件夹选择...", - "itemCount": "{count, plural, one{{count} 个项目} other{{count} 个项目}}", + "itemCount": "{count, plural, other{{count} 个项目}}", "deleteItemCount": "{count, plural, =1 {删除 {count} 个项目} other {删除 {count} 个项目}}", "duplicateItemsGroup": "{count} 个文件,每个文件 {formattedSize}", "@duplicateItemsGroup": { @@ -476,7 +476,7 @@ } }, "showMemories": "显示回忆", - "yearsAgo": "{count, plural, one{{count} 年前} other{{count} 年前}}", + "yearsAgo": "{count, plural, other{{count} 年前}}", "backupSettings": "备份设置", "backupStatus": "备份状态", "backupStatusDescription": "已备份的项目将显示在此处", @@ -1724,20 +1724,5 @@ "onTheRoad": "再次踏上旅途", "food": "美食盛宴", "pets": "毛茸茸的伙伴", - "cLIcon": "新图标", - "cLIconDesc": "终于迎来了一个全新的应用图标,我们认为它最能代表我们的作品。同时,我们还添加了图标切换功能,所以您可以继续使用旧图标。", - "cLMemories": "回忆", - "cLMemoriesDesc": "重新发现你的珍贵时刻——聚焦你最爱的亲友、旅行与假期、美妙瞬间等精彩回忆。启用机器学习,标记自己并为朋友命名,享受最佳体验。", - "cLWidgets": "小组件", - "cLWidgetsDesc": "全新首页小组件,与回忆深度集成。无需打开应用,即可在主屏幕上查看你的特别时刻。", - "cLFamilyPlan": "家庭计划存储限制", - "cLFamilyPlanDesc": "你现在可以为家庭成员设置存储空间使用上限。", - "cLBulkEdit": "批量编辑日期", - "cLBulkEditDesc": "你现在可以选择多张照片,一键批量修改日期/时间,并支持日期顺移。", - "onThisDay": "On this day", - "lookBackOnYourMemories": "Look back on your memories 🌄", - "newPhotosEmoji": " new 📸", - "sorryWeHadToPauseYourBackups": "Sorry, we had to pause your backups", - "clickToInstallOurBestVersionYet": "Click to install our best version yet", - "onThisDayNotificationExplanation": "Receive reminders about memories from this day in previous years." + "wishThemAHappyBirthday": "Wish ${name} a happy birthday! 🎉" } \ No newline at end of file diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index d92305c9ac..426c75237c 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -1,8 +1,8 @@ import 'dart:async'; +import "dart:core"; import 'dart:io'; import "package:adaptive_theme/adaptive_theme.dart"; -import 'package:background_fetch/background_fetch.dart'; import "package:computer/computer.dart"; import 'package:ente_crypto/ente_crypto.dart'; import 'package:flutter/foundation.dart'; @@ -10,6 +10,7 @@ import 'package:flutter/material.dart'; import "package:flutter/rendering.dart"; import "package:flutter/services.dart"; import "package:flutter_displaymode/flutter_displaymode.dart"; +import "package:intl/date_symbol_data_local.dart"; import 'package:logging/logging.dart'; import "package:media_kit/media_kit.dart"; import "package:package_info_plus/package_info_plus.dart"; @@ -21,7 +22,6 @@ import 'package:photos/core/error-reporting/super_logging.dart'; import 'package:photos/core/errors.dart'; import 'package:photos/core/network/network.dart'; import "package:photos/db/ml/db.dart"; -import 'package:photos/db/upload_locks_db.dart'; import 'package:photos/ente_theme_data.dart'; import "package:photos/extensions/stop_watch.dart"; import "package:photos/l10n/l10n.dart"; @@ -30,19 +30,17 @@ import "package:photos/services/account/user_service.dart"; import 'package:photos/services/app_lifecycle_service.dart'; import 'package:photos/services/collections_service.dart'; import 'package:photos/services/favorites_service.dart'; -import "package:photos/services/filedata/filedata_service.dart"; import 'package:photos/services/home_widget_service.dart'; import 'package:photos/services/local_file_update_service.dart'; import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; import 'package:photos/services/machine_learning/ml_service.dart'; import 'package:photos/services/machine_learning/semantic_search/semantic_search_service.dart'; import "package:photos/services/notification_service.dart"; -// import 'package:photos/services/push_service.dart'; -import "package:photos/services/preview_video_store.dart"; import 'package:photos/services/search_service.dart'; import 'package:photos/services/sync/local_sync_service.dart'; import 'package:photos/services/sync/remote_sync_service.dart'; import "package:photos/services/sync/sync_service.dart"; +import "package:photos/services/video_preview_service.dart"; import "package:photos/services/wake_lock_service.dart"; import 'package:photos/ui/tools/app_lock.dart'; import 'package:photos/ui/tools/lock_screen.dart'; @@ -53,13 +51,12 @@ import 'package:shared_preferences/shared_preferences.dart'; final _logger = Logger("main"); -bool _isProcessRunning = false; const kLastBGTaskHeartBeatTime = "bg_task_hb_time"; const kLastFGTaskHeartBeatTime = "fg_task_hb_time"; const kHeartBeatFrequency = Duration(seconds: 1); const kFGSyncFrequency = Duration(minutes: 5); const kFGHomeWidgetSyncFrequency = Duration(minutes: 15); -const kBGTaskTimeout = Duration(seconds: 25); +const kBGTaskTimeout = Duration(seconds: 28); const kBGPushTimeout = Duration(seconds: 28); const kFGTaskDeathTimeoutInMicroseconds = 5000000; @@ -71,7 +68,6 @@ void main() async { final savedThemeMode = await AdaptiveTheme.getThemeMode(); await _runInForeground(savedThemeMode); - unawaited(BackgroundFetch.registerHeadlessTask(_headlessTaskHandler)); if (Platform.isAndroid) FlutterDisplayMode.setHighRefreshRate().ignore(); SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle( @@ -87,14 +83,13 @@ void main() async { } Future _runInForeground(AdaptiveThemeMode? savedThemeMode) async { - return await _runWithLogs(() async { + return await runWithLogs(() async { _logger.info("Starting app in foreground"); await _init(false, via: 'mainMethod'); final Locale? locale = await getLocale(noFallback: true); runApp( AppLock( - builder: (args) => - EnteApp(_runBackgroundTask, _killBGTask, locale, savedThemeMode), + builder: (args) => EnteApp(locale, savedThemeMode), lockScreen: const LockScreen(), enabled: await Configuration.instance.shouldShowLockScreen() || localSettings.isOnGuestView(), @@ -115,67 +110,77 @@ ThemeMode _themeMode(AdaptiveThemeMode? savedThemeMode) { return ThemeMode.system; } -Future _homeWidgetSync() async { +Future _homeWidgetSync([bool isBackground = false]) async { + if (isBackground && Platform.isIOS) { + _logger.info("Home widget sync skipped in background on iOS"); + return; + } + + if (isBackground) { + final locale = await getLocale(); + await initializeDateFormatting(locale?.languageCode ?? "en"); + } + try { - await HomeWidgetService.instance.initHomeWidget(); + await HomeWidgetService.instance.initHomeWidget(isBackground); } catch (e, s) { _logger.severe("Error in syncing home widget", e, s); } } -Future _runBackgroundTask(String taskId, {String mode = 'normal'}) async { - if (_isProcessRunning) { - _logger.info("Background task triggered when process was already running"); - await _sync('bgTaskActiveProcess'); - await BackgroundFetch.finish(taskId); - } else { - _runWithLogs( - () async { - _logger.info("Starting background task in $mode mode"); - // ignore: unawaited_futures - _runInBackground(taskId); - }, - prefix: "[bg]", - ).ignore(); - } +Future runBackgroundTask( + String taskId, + TimeLogger tlog, { + String mode = 'normal', +}) async { + await _runMinimally(taskId, tlog); } -Future _runInBackground(String taskId) async { - await Future.delayed(const Duration(seconds: 3)); - if (await _isRunningInForeground()) { - _logger.info("FG task running, skipping BG taskID: $taskId"); - await BackgroundFetch.finish(taskId); - return; - } else { - _logger.info("FG task is not running"); - } - _logger.info("[BackgroundFetch] Event received: $taskId"); - _scheduleBGTaskKill(taskId); - if (Platform.isIOS) { - _scheduleSuicide(kBGTaskTimeout, taskId); // To prevent OS from punishing us - } - await _init(true, via: 'runViaBackgroundTask'); - await Future.wait( - [ - _homeWidgetSync(), - () async { - updateService.showUpdateNotification().ignore(); - await _sync('bgSync'); - }(), - ], +Future _runMinimally(String taskId, TimeLogger tlog) async { + final PackageInfo packageInfo = await PackageInfo.fromPlatform(); + final SharedPreferences prefs = await SharedPreferences.getInstance(); + + await Configuration.instance.init(); + + // App LifeCycle + AppLifecycleService.instance.init(prefs); + AppLifecycleService.instance.onAppInBackground('init via: WorkManager $tlog'); + + // Crypto rel. + await Computer.shared().turnOn(workersCount: 4); + CryptoUtil.init(); + + // Init Network Utils + await NetworkClient.instance.init(packageInfo); + + // Global Services + ServiceLocator.instance.init( + prefs, + NetworkClient.instance.enteDio, + NetworkClient.instance.getDio(), + packageInfo, ); - await BackgroundFetch.finish(taskId); -} -// https://stackoverflow.com/a/73796478/546896 -@pragma('vm:entry-point') -void _headlessTaskHandler(HeadlessTask task) { - debugPrint("_headlessTaskHandler"); - if (task.timeout) { - BackgroundFetch.finish(task.taskId); - } else { - _runBackgroundTask(task.taskId, mode: "headless"); - } + await CollectionsService.instance.init(prefs); + + // Upload & Sync Related + await FileUploader.instance.init(prefs, true); + LocalFileUpdateService.instance.init(prefs); + await LocalSyncService.instance.init(prefs); + RemoteSyncService.instance.init(prefs); + await SyncService.instance.init(prefs); + + // Misc Services + await UserService.instance.init(); + NotificationService.instance.init(prefs); + if (Platform.isAndroid) HomeWidgetService.instance.init(prefs); + + // Begin Execution + // only runs for android + updateService.showUpdateNotification().ignore(); + await _sync('bgTaskActiveProcess'); + // only runs for android + await _homeWidgetSync(true); } Future _init(bool isBackground, {String via = ''}) async { @@ -193,7 +198,6 @@ Future _init(bool isBackground, {String via = ''}) async { } }); if (!isBackground) _heartBeatOnInit(0); - _isProcessRunning = true; _logger.info("Initializing... inBG =$isBackground via: $via $tlog"); final SharedPreferences preferences = await SharedPreferences.getInstance(); final PackageInfo packageInfo = await PackageInfo.fromPlatform(); @@ -222,8 +226,12 @@ Future _init(bool isBackground, {String via = ''}) async { await NetworkClient.instance.init(packageInfo); _logger.info("NetworkClient init done $tlog"); - ServiceLocator.instance - .init(preferences, NetworkClient.instance.enteDio, packageInfo); + ServiceLocator.instance.init( + preferences, + NetworkClient.instance.enteDio, + NetworkClient.instance.getDio(), + packageInfo, + ); _logger.info("UserService init $tlog"); await UserService.instance.init(); @@ -236,7 +244,6 @@ Future _init(bool isBackground, {String via = ''}) async { FavoritesService.instance.initFav().ignore(); LocalFileUpdateService.instance.init(preferences); SearchService.instance.init(); - FileDataService.instance.init(preferences); _logger.info("FileUploader init $tlog"); await FileUploader.instance.init(preferences, isBackground); @@ -268,7 +275,7 @@ Future _init(bool isBackground, {String via = ''}) async { // }); } _logger.info("PushService/HomeWidget done $tlog"); - PreviewVideoStore.instance.init(preferences); + VideoPreviewService.instance.init(preferences); unawaited(SemanticSearchService.instance.init()); unawaited(MLService.instance.init()); await PersonService.init( @@ -299,7 +306,7 @@ void logLocalSettings() { ); _logger.info("Gallery grid size: ${localSettings.getPhotoGridSize()}"); _logger.info( - "Video streaming is enalbed: ${PreviewVideoStore.instance.isVideoStreamingEnabled}", + "Video streaming is enalbed: ${VideoPreviewService.instance.isVideoStreamingEnabled}", ); } @@ -327,7 +334,7 @@ Future _sync(String caller) async { } } -Future _runWithLogs(Function() function, {String prefix = ""}) async { +Future runWithLogs(Function() function, {String prefix = ""}) async { await SuperLogging.main( LogConfig( body: function, @@ -375,17 +382,6 @@ Future _scheduleFGSync(String caller) async { }); } -void _scheduleBGTaskKill(String taskId) async { - if (await _isRunningInForeground()) { - _logger.info("Found app in FG, committing seppuku. $taskId"); - await _killBGTask(taskId); - return; - } - Future.delayed(kHeartBeatFrequency, () async { - _scheduleBGTaskKill(taskId); - }); -} - Future _isRunningInForeground() async { final prefs = await SharedPreferences.getInstance(); await prefs.reload(); @@ -397,18 +393,6 @@ Future _isRunningInForeground() async { (currentTime - kFGTaskDeathTimeoutInMicroseconds); } -Future _killBGTask([String? taskId]) async { - await UploadLocksDB.instance.releaseLocksAcquiredByOwnerBefore( - ProcessType.background.toString(), - DateTime.now().microsecondsSinceEpoch, - ); - final prefs = await SharedPreferences.getInstance(); - await prefs.remove(kLastBGTaskHeartBeatTime); - if (taskId != null) { - await BackgroundFetch.finish(taskId); - } -} - Future _logFGHeartBeatInfo(SharedPreferences prefs) async { final bool isRunningInFG = await _isRunningInForeground(); await prefs.reload(); @@ -418,12 +402,3 @@ Future _logFGHeartBeatInfo(SharedPreferences prefs) async { : DateTime.fromMicrosecondsSinceEpoch(lastFGTaskHeartBeatTime).toString(); _logger.info('isAlreadyRunningFG: $isRunningInFG, last Beat: $lastRun'); } - -void _scheduleSuicide(Duration duration, [String? taskID]) { - final taskIDVal = taskID ?? 'no taskID'; - _logger.warning("Schedule seppuku taskID: $taskIDVal"); - Future.delayed(duration, () { - _logger.warning("TLE, committing seppuku for taskID: $taskIDVal"); - _killBGTask(taskID); - }); -} diff --git a/mobile/lib/models/base_location.dart b/mobile/lib/models/base_location.dart index 7bdbb7eaec..d98152dad3 100644 --- a/mobile/lib/models/base_location.dart +++ b/mobile/lib/models/base_location.dart @@ -1,19 +1,18 @@ import "dart:convert"; -import "package:photos/models/file/file.dart"; import "package:photos/models/location/location.dart"; const baseRadius = 0.6; class BaseLocation { - final List files; + final List fileIDs; int? firstCreationTime; int? lastCreationTime; final Location location; final bool isCurrentBase; BaseLocation( - this.files, + this.fileIDs, this.location, this.isCurrentBase, { this.firstCreationTime, @@ -22,12 +21,9 @@ class BaseLocation { static List decodeJsonToList( String jsonString, - Map filesMap, ) { final jsonList = jsonDecode(jsonString) as List; - return jsonList - .map((json) => BaseLocation.fromJson(json, filesMap)) - .toList(); + return jsonList.map((json) => BaseLocation.fromJson(json)).toList(); } static String encodeListToJson(List baseLocations) { @@ -38,13 +34,9 @@ class BaseLocation { static BaseLocation fromJson( Map json, - Map filesMap, ) { return BaseLocation( - (json['fileIDs'] as List) - .where((uploadID) => filesMap[uploadID] != null) - .map((uploadID) => filesMap[uploadID]!) - .toList(), + (json['fileIDs'] as List).cast(), Location( latitude: json['location']['latitude'], longitude: json['location']['longitude'], @@ -57,10 +49,7 @@ class BaseLocation { Map toJson() { return { - 'fileIDs': files - .where((file) => file.uploadedFileID != null) - .map((file) => file.uploadedFileID!) - .toList(), + 'fileIDs': fileIDs, 'location': { 'latitude': location.latitude!, 'longitude': location.longitude!, @@ -71,32 +60,15 @@ class BaseLocation { }; } - int averageCreationTime() { - if (firstCreationTime != null && lastCreationTime != null) { - return (firstCreationTime! + lastCreationTime!) ~/ 2; - } - final List creationTimes = files - .where((file) => file.creationTime != null) - .map((file) => file.creationTime!) - .toList(); - if (creationTimes.length < 2) { - return creationTimes.isEmpty ? 0 : creationTimes.first; - } - creationTimes.sort(); - firstCreationTime ??= creationTimes.first; - lastCreationTime ??= creationTimes.last; - return (firstCreationTime! + lastCreationTime!) ~/ 2; - } - BaseLocation copyWith({ - List? files, + List? files, int? firstCreationTime, int? lastCreationTime, Location? location, bool? isCurrentBase, }) { return BaseLocation( - files ?? this.files, + files ?? fileIDs, location ?? this.location, isCurrentBase ?? this.isCurrentBase, firstCreationTime: firstCreationTime ?? this.firstCreationTime, diff --git a/mobile/lib/models/filters/gallery_items_filter.dart b/mobile/lib/models/filters/gallery_items_filter.dart deleted file mode 100644 index 8c717846ea..0000000000 --- a/mobile/lib/models/filters/gallery_items_filter.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:photos/models/file/file.dart'; - -class GalleryItemsFilter { - bool shouldInclude(EnteFile file) { - return true; - } -} diff --git a/mobile/lib/models/filters/important_items_filter.dart b/mobile/lib/models/filters/important_items_filter.dart deleted file mode 100644 index 06376e99db..0000000000 --- a/mobile/lib/models/filters/important_items_filter.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'dart:io'; - -import 'package:path/path.dart'; -import 'package:photos/core/configuration.dart'; -import 'package:photos/models/file/file.dart'; -import 'package:photos/models/filters/gallery_items_filter.dart'; - -class ImportantItemsFilter implements GalleryItemsFilter { - final _importantPaths = Configuration.instance.getPathsToBackUp(); - - @override - bool shouldInclude(EnteFile file) { - if (file.uploadedFileID != null) { - return true; - } - if (file.deviceFolder == null) { - return false; - } - final String folder = basename(file.deviceFolder!); - if (_importantPaths.isEmpty && Platform.isAndroid) { - return folder == "Camera" || - folder == "Recents" || - folder == "DCIM" || - folder == "Download" || - folder == "Screenshot"; - } - return _importantPaths.contains(folder); - } -} diff --git a/mobile/lib/models/memories/memories_cache.dart b/mobile/lib/models/memories/memories_cache.dart index 8257224fe7..949107901d 100644 --- a/mobile/lib/models/memories/memories_cache.dart +++ b/mobile/lib/models/memories/memories_cache.dart @@ -2,7 +2,6 @@ import "dart:convert"; import "package:photos/models/base/id.dart"; import "package:photos/models/base_location.dart"; -import "package:photos/models/file/file.dart"; import "package:photos/models/location/location.dart"; import "package:photos/models/memories/clip_memory.dart"; import "package:photos/models/memories/people_memory.dart"; @@ -39,7 +38,6 @@ class MemoriesCache { factory MemoriesCache.fromJson( Map json, - Map filesMap, ) { return MemoriesCache( toShowMemories: ToShowMemory.decodeJsonToList(json['toShowMemories']), @@ -47,10 +45,7 @@ class MemoriesCache { clipShownLogs: ClipShownLog.decodeJsonToList(json['clipShownLogs']), tripsShownLogs: TripsShownLog.decodeJsonToList(json['tripsShownLogs']), baseLocations: json['baseLocations'] != null - ? BaseLocation.decodeJsonToList( - json['baseLocations'], - filesMap, - ) + ? BaseLocation.decodeJsonToList(json['baseLocations']) : [], ); } @@ -71,9 +66,8 @@ class MemoriesCache { static MemoriesCache decodeFromJsonString( String jsonString, - Map filesMap, ) { - return MemoriesCache.fromJson(jsonDecode(jsonString), filesMap); + return MemoriesCache.fromJson(jsonDecode(jsonString)); } } diff --git a/mobile/lib/models/metadata/file_magic.dart b/mobile/lib/models/metadata/file_magic.dart index 02f6188a9d..53627aafbc 100644 --- a/mobile/lib/models/metadata/file_magic.dart +++ b/mobile/lib/models/metadata/file_magic.dart @@ -9,6 +9,7 @@ const captionKey = "caption"; const uploaderNameKey = "uploaderName"; const widthKey = 'w'; const heightKey = 'h'; +const streamVersionKey = 'sv'; const mediaTypeKey = 'mediaType'; const latKey = "lat"; const longKey = "long"; @@ -48,6 +49,10 @@ class PubMagicMetadata { double? lat; double? long; + // Indicates streaming version of the file. + // If this is set, then the file is a streaming version of the original file. + int? sv; + // ISO 8601 datetime without timezone. This contains the date and time of the photo in the original tz // where the photo was taken. String? dateTime; @@ -83,6 +88,7 @@ class PubMagicMetadata { this.mediaType, this.dateTime, this.offsetTime, + this.sv, }); factory PubMagicMetadata.fromEncodedJson(String encodedJson) => @@ -107,6 +113,7 @@ class PubMagicMetadata { mediaType: map[mediaTypeKey], dateTime: map[dateTimeKey], offsetTime: map[offsetTimeKey], + sv: safeParseInt(map[streamVersionKey], streamVersionKey), ); } diff --git a/mobile/lib/models/search/file_search_result.dart b/mobile/lib/models/search/file_search_result.dart deleted file mode 100644 index 53582e034c..0000000000 --- a/mobile/lib/models/search/file_search_result.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:photos/models/file/file.dart'; -import "package:photos/models/search/hierarchical/hierarchical_search_filter.dart"; -import 'package:photos/models/search/search_result.dart'; -import "package:photos/models/search/search_types.dart"; - -class FileSearchResult extends SearchResult { - final EnteFile file; - - FileSearchResult(this.file); - - @override - String name() { - return file.displayName; - } - - @override - ResultType type() { - return ResultType.file; - } - - @override - EnteFile previewThumbnail() { - return file; - } - - @override - List resultFiles() { - // for fileSearchResult, the file detailed page view will be opened - throw UnimplementedError(); - } - - @override - HierarchicalSearchFilter getHierarchicalSearchFilter() { - throw UnimplementedError(); - } -} diff --git a/mobile/lib/models/search/generic_search_result.dart b/mobile/lib/models/search/generic_search_result.dart index 1786120815..e38442c6ad 100644 --- a/mobile/lib/models/search/generic_search_result.dart +++ b/mobile/lib/models/search/generic_search_result.dart @@ -46,6 +46,10 @@ class GenericSearchResult extends SearchResult { return _files; } + int fileCount() { + return _files.length; + } + @override HierarchicalSearchFilter getHierarchicalSearchFilter() { return hierarchicalSearchFilter; diff --git a/mobile/lib/models/search/search_types.dart b/mobile/lib/models/search/search_types.dart index 3b82b87d20..2a209cafc9 100644 --- a/mobile/lib/models/search/search_types.dart +++ b/mobile/lib/models/search/search_types.dart @@ -279,6 +279,8 @@ extension SectionTypeExtensions on SectionType { return [Bus.instance.on()]; case SectionType.magic: return [Bus.instance.on()]; + case SectionType.contacts: + return [Bus.instance.on()]; default: return []; } diff --git a/mobile/lib/module/download/file_url.dart b/mobile/lib/module/download/file_url.dart index eed4398cec..e5faced127 100644 --- a/mobile/lib/module/download/file_url.dart +++ b/mobile/lib/module/download/file_url.dart @@ -7,6 +7,7 @@ enum FileUrlType { publicDownload, thumbnail, publicThumbnail, + directDownload, } class FileUrl { @@ -16,6 +17,8 @@ class FileUrl { endpoint != kDefaultProductionEndpoint || flagService.disableCFWorker; switch (type) { + case FileUrlType.directDownload: + return "$endpoint/files/download/$fileID"; case FileUrlType.download: return disableWorker ? "$endpoint/files/download/$fileID" diff --git a/mobile/lib/module/download/manager.dart b/mobile/lib/module/download/manager.dart new file mode 100644 index 0000000000..1b92a431a4 --- /dev/null +++ b/mobile/lib/module/download/manager.dart @@ -0,0 +1,417 @@ +import "dart:async"; +import "dart:io"; + +import "package:dio/dio.dart"; +import "package:logging/logging.dart"; +import "package:photos/core/configuration.dart"; + +import "package:photos/module/download/file_url.dart"; +import "package:photos/module/download/task.dart"; + +class DownloadManager { + final _logger = Logger('DownloadManager'); + static const int downloadChunkSize = 40 * 1024 * 1024; + + final Dio _dio; + + // In-memory storage for download tasks + final Map _tasks = {}; + + // Active downloads with their completers and streams + final Map> _completers = {}; + final Map> _streams = {}; + final Map _cancelTokens = {}; + final Map _downloadStartTimes = {}; + + DownloadManager(this._dio); + + /// Subscribe to download progress updates for a specific file ID + Stream watchDownload(int fileId) { + _streams[fileId] ??= StreamController.broadcast(); + return _streams[fileId]!.stream; + } + + bool enableResumableDownload(int? size) { + if (size == null) return false; + //todo: Use FileUrlType.direct instead of FileUrlType.directDownload + return size > downloadChunkSize; + } + + /// Start download and return a Future that completes when download finishes + /// If download was paused, calling this again will resume it + Future download( + int fileId, + String filename, + int totalBytes, + ) async { + _downloadStartTimes[fileId] = DateTime.now().microsecondsSinceEpoch; + // If already downloading, return existing future + if (_completers.containsKey(fileId)) { + return _completers[fileId]!.future; + } + + final completer = Completer(); + _completers[fileId] = completer; + + // Get or create task + final existingTask = _tasks[fileId]; + final task = existingTask ?? + DownloadTask( + id: fileId, + filename: filename, + totalBytes: totalBytes, + ); + + // Store task in memory + _tasks[fileId] = task; + + // Don't restart if already completed + if (task.isCompleted) { + // ensure that the file exists + final filePath = task.filePath; + if (filePath == null || !(await File(filePath).exists())) { + // If the file doesn't exist, mark the task as error + _logger.warning( + 'File not found for ${task.filename} (${task.bytesDownloaded}/${task.totalBytes} bytes)', + ); + final updatedTask = task.copyWith( + status: DownloadStatus.error, + error: 'File not found', + filePath: null, + ); + _updateTask(updatedTask); + final result = DownloadResult(updatedTask, false); + completer.complete(result); + return result; + } else { + _logger.info( + 'Download already completed for ${task.filename} (${task.bytesDownloaded}/${task.totalBytes} bytes)', + ); + final result = DownloadResult(task, true); + completer.complete(result); + return result; + } + } + unawaited(_startDownload(task, completer)); + return completer.future; + } + + /// Pause download + Future pause(int fileId) async { + // ignore cancel if download started less than 1 second ago, + // this is to avoid cancellination due to different type of video players, where dispose is called + // little later after other video player operations + final startTime = _downloadStartTimes[fileId]; + if (startTime == null || + DateTime.now().microsecondsSinceEpoch - startTime < 1e6) { + _logger.info('Download paused too soon, ignoring pause request'); + return; + } + final token = _cancelTokens[fileId]; + if (token != null && !token.isCancelled) { + token.cancel('paused'); + } + + final task = _tasks[fileId]; + if (task != null && task.isActive) { + _updateTask(task.copyWith(status: DownloadStatus.paused)); + } + + // Clean up streams if no listeners + final stream = _streams[fileId]; + if (stream != null && !stream.hasListener) { + await stream.close(); + _streams.remove(fileId); + } + } + + /// Cancel and delete download + Future cancel(int fileId) async { + final token = _cancelTokens[fileId]; + if (token != null && !token.isCancelled) { + token.cancel('cancelled'); + } + + final task = _tasks[fileId]; + if (task != null) { + await _deleteFiles(task); + _updateTask(task.copyWith(status: DownloadStatus.cancelled)); + _tasks.remove(fileId); + } + _cleanup(fileId); + } + + /// Get current download status + Future getDownload(int fileId) async => _tasks[fileId]; + + /// Get all downloads + Future> getAllDownloads() async => _tasks.values.toList(); + + Future _startDownload( + DownloadTask task, + Completer completer, + ) async { + try { + task = task.copyWith(status: DownloadStatus.downloading); + _updateTask(task); + + final cancelToken = CancelToken(); + _cancelTokens[task.id] = cancelToken; + + final directory = Configuration.instance.getTempDirectory(); + final basePath = '$directory${task.id}.encrypted'; + + // check if base file already exists and is of correct size + final baseFile = File(basePath); + if (await baseFile.exists()) { + final existingSize = await baseFile.length(); + if (existingSize == task.totalBytes) { + _logger.info( + 'Download already exists for ${task.filename} (${existingSize}/${task.totalBytes} bytes)', + ); + task = task.copyWith( + status: DownloadStatus.completed, + filePath: basePath, + bytesDownloaded: existingSize, + ); + _updateTask(task); + completer.complete(DownloadResult(task, true)); + return; + } else { + _logger.warning( + 'Existing file size mismatch for ${task.filename}: ' + 'expected ${task.totalBytes}, but got $existingSize', + ); + await baseFile.delete(); // Remove corrupted file + } + } + + // Check existing chunks and calculate progress + final totalChunks = (task.totalBytes / downloadChunkSize).ceil(); + final existingChunks = + await _validateExistingChunks(basePath, task.totalBytes, totalChunks); + + task = task.copyWith( + bytesDownloaded: _calculateDownloadedBytes( + existingChunks, + task.totalBytes, + totalChunks, + ), + ); + _updateTask(task); + + _logger.info( + 'Resuming download for ${task.filename} (${task.bytesDownloaded}/${task.totalBytes} bytes)', + ); + for (int i = 0; i < totalChunks; i++) { + if (existingChunks[i]) { + continue; + } + if (cancelToken.isCancelled) { + _logger.info('Download cancelled for ${task.filename}'); + break; + } + await _downloadChunk(task, basePath, i, totalChunks, cancelToken); + existingChunks[i] = true; + } + + if (!cancelToken.isCancelled) { + final finalPath = await _combineChunks(basePath, totalChunks); + task = task.copyWith( + status: DownloadStatus.completed, + filePath: finalPath, + bytesDownloaded: task.totalBytes, + ); + _updateTask(task); + completer.complete(DownloadResult(task, true)); + } + } catch (e) { + if (e is DioException && e.type == DioExceptionType.cancel) { + _logger.info('Download cancelled for ${task.filename}'); + // Complete future with current task state (paused or cancelled) + final currentTask = _tasks[task.id]; + if (currentTask != null && !completer.isCompleted) { + completer.complete(DownloadResult(currentTask, false)); + } + return; + } + _logger.warning('Error downloading ${task.filename}', e); + task = task.copyWith(status: DownloadStatus.error, error: e.toString()); + _updateTask(task); + if (!completer.isCompleted) { + completer.complete(DownloadResult(task, false)); + } + } finally { + _cleanup(task.id); + } + } + + String _getChunkPath(String basePath, int part) { + return '$basePath.${part}_part'; + } + + Future> _validateExistingChunks( + String basePath, + int totalBytes, + int totalChunks, + ) async { + final existingChunks = List.filled(totalChunks, false); + + for (int i = 0; i < totalChunks; i++) { + final chunkFile = File(_getChunkPath(basePath, i + 1)); + if (!await chunkFile.exists()) continue; + + final expectedSize = i == totalChunks - 1 + ? totalBytes - (i * downloadChunkSize) + : downloadChunkSize; + + final actualSize = await chunkFile.length(); + if (actualSize == expectedSize) { + _logger.info('existing chunk ${i + 1} is valid'); + existingChunks[i] = true; + } else { + _logger.warning( + 'Chunk ${i + 1} is corrupted: expected $expectedSize bytes, ' + 'but got $actualSize bytes', + ); + existingChunks[i] = false; + // await chunkFile.delete(); // Remove corrupted chunk + } + } + + return existingChunks; + } + + int _calculateDownloadedBytes( + List existingChunks, + int totalBytes, + int totalChunks, + ) { + int bytes = 0; + for (int i = 0; i < existingChunks.length; i++) { + if (existingChunks[i]) { + bytes += i == totalChunks - 1 + ? totalBytes - (i * downloadChunkSize) + : downloadChunkSize; + } + } + return bytes; + } + + Future _downloadChunk( + DownloadTask task, + String basePath, + int chunkIndex, + int totalChunks, + CancelToken cancelToken, + ) async { + final chunkPath = _getChunkPath(basePath, chunkIndex + 1); + final startByte = chunkIndex * downloadChunkSize; + final endByte = chunkIndex == totalChunks - 1 + ? task.totalBytes - 1 + : (startByte + downloadChunkSize) - 1; + _logger.info('Downloading chunk ${chunkIndex + 1}/$totalChunks'); + await _dio.download( + FileUrl.getUrl(task.id, FileUrlType.directDownload), + chunkPath, + queryParameters: { + "token": Configuration.instance.getToken(), + }, + options: Options( + headers: { + "Range": "bytes=$startByte-$endByte", + }, + ), + cancelToken: cancelToken, + onReceiveProgress: (received, total) async { + final updatedTask = task.copyWith( + bytesDownloaded: (chunkIndex) * downloadChunkSize + received, + ); + _notifyProgress(updatedTask); + }, + ); + // Update progress after chunk completion + final chunkFileSize = await File(chunkPath).length(); + task = task.copyWith( + bytesDownloaded: (chunkIndex) * downloadChunkSize + chunkFileSize, + ); + _updateTask(task); + } + + Future _combineChunks(String basePath, int totalChunks) async { + final finalFile = File(basePath); + final sink = finalFile.openWrite(); + try { + for (int i = 1; i <= totalChunks; i++) { + final chunkFile = File(_getChunkPath(basePath, i)); + await sink.addStream(chunkFile.openRead()); + await chunkFile.delete(); + } + } finally { + await sink.close(); + } + return finalFile.path; + } + + Future _deleteFiles(DownloadTask task) async { + try { + final directory = Configuration.instance.getTempDirectory(); + final basePath = '$directory${task.id}.encrypted'; + final finalFile = File(basePath); + if (await finalFile.exists()) await finalFile.delete(); + + // Delete chunk files + final totalChunks = (task.totalBytes / downloadChunkSize).ceil(); + for (int i = 1; i <= totalChunks; i++) { + final chunkFile = File(_getChunkPath(basePath, i)); + if (await chunkFile.exists()) await chunkFile.delete(); + } + } catch (e) { + _logger.warning('Error deleting files: $e'); + } + } + + void _updateTask(DownloadTask task) { + _tasks[task.id] = task; + _notifyProgress(task); + } + + void _notifyProgress(DownloadTask task) { + final stream = _streams[task.id]; + if (stream != null && !stream.isClosed) { + stream.add(task); + } + } + + void _cleanup(int fileId) { + _completers.remove(fileId); + _cancelTokens.remove(fileId); + + final stream = _streams[fileId]; + if (stream != null && !stream.hasListener) { + stream.close(); + _streams.remove(fileId); + } + } + + Future dispose() async { + for (final completer in _completers.values) { + if (!completer.isCompleted) { + completer.completeError('Disposed'); + } + } + _completers.clear(); + + for (final token in _cancelTokens.values) { + token.cancel('Disposed'); + } + _cancelTokens.clear(); + + for (final stream in _streams.values) { + await stream.close(); + } + _streams.clear(); + + _tasks.clear(); + } +} diff --git a/mobile/lib/module/download/task.dart b/mobile/lib/module/download/task.dart new file mode 100644 index 0000000000..1bd96ca295 --- /dev/null +++ b/mobile/lib/module/download/task.dart @@ -0,0 +1,80 @@ +enum DownloadStatus { + pending, + downloading, + paused, + completed, + error, + cancelled +} + +class DownloadTask { + final int id; + final String filename; + final int totalBytes; + int bytesDownloaded; + DownloadStatus status; + String? error; + String? filePath; + + DownloadTask({ + required this.id, + required this.filename, + required this.totalBytes, + this.bytesDownloaded = 0, + this.status = DownloadStatus.pending, + this.error, + this.filePath, + }); + + double get progress => totalBytes > 0 ? bytesDownloaded / totalBytes : 0.0; + bool get isCompleted => status == DownloadStatus.completed; + bool get isActive => status == DownloadStatus.downloading; + bool get isFinished => [ + DownloadStatus.completed, + DownloadStatus.error, + DownloadStatus.cancelled, + ].contains(status); + + Map toMap() => { + 'id': id, + 'filename': filename, + 'totalBytes': totalBytes, + 'bytesDownloaded': bytesDownloaded, + 'status': status.name, + 'error': error, + 'filePath': filePath, + }; + + static DownloadTask fromMap(Map map) => DownloadTask( + id: map['id'], + filename: map['filename'], + totalBytes: map['totalBytes'], + bytesDownloaded: map['bytesDownloaded'] ?? 0, + status: DownloadStatus.values.byName(map['status']), + error: map['error'], + filePath: map['filePath'], + ); + + DownloadTask copyWith({ + int? bytesDownloaded, + DownloadStatus? status, + String? error, + String? filePath, + }) => + DownloadTask( + id: id, + filename: filename, + totalBytes: totalBytes, + bytesDownloaded: bytesDownloaded ?? this.bytesDownloaded, + status: status ?? this.status, + error: error ?? this.error, + filePath: filePath ?? this.filePath, + ); +} + +class DownloadResult { + final DownloadTask task; + final bool success; + + DownloadResult(this.task, this.success); +} diff --git a/mobile/lib/module/upload/service/multipart.dart b/mobile/lib/module/upload/service/multipart.dart index f4ecf3b3c4..ad429e5e77 100644 --- a/mobile/lib/module/upload/service/multipart.dart +++ b/mobile/lib/module/upload/service/multipart.dart @@ -54,7 +54,7 @@ class MultiPartUploader { return multipartPartSize; } - Future calculatePartCount(int fileSize) async { + int calculatePartCount(int fileSize) { // If the feature flag is disabled, return 1 if (!_featureFlagService.enableMobMultiPart) return 1; if (!localSettings.userEnabledMultiplePart) return 1; @@ -236,6 +236,7 @@ class MultiPartUploader { options: Options( headers: { Headers.contentLengthHeader: fileSize, + Headers.contentTypeHeader: "application/octet-stream", }, ), ); diff --git a/mobile/lib/service_locator.dart b/mobile/lib/service_locator.dart index 57728a7a26..bc96877eb2 100644 --- a/mobile/lib/service_locator.dart +++ b/mobile/lib/service_locator.dart @@ -4,11 +4,13 @@ import "package:ente_cast_normal/ente_cast_normal.dart"; import "package:ente_feature_flag/ente_feature_flag.dart"; import "package:package_info_plus/package_info_plus.dart"; import "package:photos/gateways/entity_gw.dart"; +import "package:photos/module/download/manager.dart"; import "package:photos/services/account/billing_service.dart"; import "package:photos/services/entity_service.dart"; +import "package:photos/services/filedata/filedata_service.dart"; import "package:photos/services/location_service.dart"; +import "package:photos/services/machine_learning/compute_controller.dart"; import "package:photos/services/machine_learning/face_ml/face_recognition_service.dart"; -import "package:photos/services/machine_learning/machine_learning_controller.dart"; import "package:photos/services/magic_cache_service.dart"; import "package:photos/services/memories_cache_service.dart"; import "package:photos/services/permission/service.dart"; @@ -22,6 +24,7 @@ import "package:shared_preferences/shared_preferences.dart"; class ServiceLocator { late final SharedPreferences prefs; late final Dio enteDio; + late final Dio nonEnteDio; late final PackageInfo packageInfo; // instance @@ -29,9 +32,15 @@ class ServiceLocator { static final ServiceLocator instance = ServiceLocator._privateConstructor(); - init(SharedPreferences prefs, Dio enteDio, PackageInfo packageInfo) { + init( + SharedPreferences prefs, + Dio enteDio, + Dio nonEnteDio, + PackageInfo packageInfo, + ) { this.prefs = prefs; this.enteDio = enteDio; + this.nonEnteDio = nonEnteDio; this.packageInfo = packageInfo; } } @@ -133,10 +142,10 @@ BillingService get billingService { return _billingService!; } -MachineLearningController? _machineLearningController; -MachineLearningController get machineLearningController { - _machineLearningController ??= MachineLearningController(); - return _machineLearningController!; +ComputeController? _computeController; +ComputeController get computeController { + _computeController ??= ComputeController(); + return _computeController!; } FaceRecognitionService? _faceRecognitionService; @@ -150,3 +159,20 @@ PermissionService get permissionService { _permissionService ??= PermissionService(ServiceLocator.instance.prefs); return _permissionService!; } + +FileDataService? _fileDataService; +FileDataService get fileDataService { + _fileDataService ??= FileDataService( + ServiceLocator.instance.prefs, + ServiceLocator.instance.enteDio, + ); + return _fileDataService!; +} + +DownloadManager? _downloadManager; +DownloadManager get downloadManager { + _downloadManager ??= DownloadManager( + ServiceLocator.instance.nonEnteDio, + ); + return _downloadManager!; +} diff --git a/mobile/lib/services/account/billing_service.dart b/mobile/lib/services/account/billing_service.dart index 2d3d7317c7..baa27c6ad9 100644 --- a/mobile/lib/services/account/billing_service.dart +++ b/mobile/lib/services/account/billing_service.dart @@ -33,7 +33,7 @@ class BillingService { Future? _future; BillingService(this._enteDio) { - _logger.finest("BillingService constructor"); + _logger.info("BillingService constructor"); init(); } diff --git a/mobile/lib/services/account/user_service.dart b/mobile/lib/services/account/user_service.dart index 00f6842d97..d3673603a5 100644 --- a/mobile/lib/services/account/user_service.dart +++ b/mobile/lib/services/account/user_service.dart @@ -693,19 +693,19 @@ class UserService { ProgressDialog dialog, ) async { late Uint8List keyEncryptionKey; - _logger.finest('Start deriving key'); + _logger.info('Start deriving key'); keyEncryptionKey = await CryptoUtil.deriveKey( utf8.encode(userPassword), CryptoUtil.base642bin(srpAttributes.kekSalt), srpAttributes.memLimit, srpAttributes.opsLimit, ); - _logger.finest('keyDerivation done, derive LoginKey'); + _logger.info('keyDerivation done, derive LoginKey'); final loginKey = await CryptoUtil.deriveLoginKey(keyEncryptionKey); final Uint8List identity = Uint8List.fromList( utf8.encode(srpAttributes.srpUserID), ); - _logger.finest('loginKey derivation done'); + _logger.info('loginKey derivation done'); final Uint8List salt = base64Decode(srpAttributes.srpSalt); final Uint8List password = loginKey; final SecureRandom random = _getSecureRandom(); diff --git a/mobile/lib/services/album_home_widget_service.dart b/mobile/lib/services/album_home_widget_service.dart index 4bf8864940..9513427e1f 100644 --- a/mobile/lib/services/album_home_widget_service.dart +++ b/mobile/lib/services/album_home_widget_service.dart @@ -1,3 +1,4 @@ +import "dart:async"; import 'dart:convert'; import "dart:math"; @@ -19,7 +20,6 @@ import "package:photos/ui/viewer/file/detail_page.dart"; import 'package:photos/ui/viewer/gallery/collection_page.dart'; import 'package:photos/utils/navigation_util.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:synchronized/synchronized.dart'; class AlbumHomeWidgetService { // Constants @@ -40,8 +40,6 @@ class AlbumHomeWidgetService { // Properties final Logger _logger = Logger((AlbumHomeWidgetService).toString()); late final SharedPreferences _prefs; - final _albumsForceRefreshLock = Lock(); - bool _hasSyncedAlbums = false; // Initialization void init(SharedPreferences prefs) { @@ -49,40 +47,14 @@ class AlbumHomeWidgetService { } // Public methods - Future initHomeWidget(bool? forceFetchNewAlbums) async { - if (await _hasAnyBlockers()) { - await clearWidget(); - return; - } - - await _albumsForceRefreshLock.synchronized(() async { - if (await _hasAnyBlockers()) { - await clearWidget(); - return; - } - - final isWidgetEmpty = await _isWidgetEmpty(); - forceFetchNewAlbums ??= await _shouldForceFetchAlbums(isWidgetEmpty); - - _logger.warning( - "Initializing albums widget: forceFetch: $forceFetchNewAlbums, isEmpty: $isWidgetEmpty", - ); - - if (forceFetchNewAlbums!) { - await _forceAlbumsUpdate(); - } else if (!isWidgetEmpty) { - await _syncExistingAlbums(); - } - }); - } - List? getSelectedAlbumIds() { final selectedAlbums = _prefs.getStringList(SELECTED_ALBUMS_KEY); return selectedAlbums?.map((id) => int.tryParse(id) ?? 0).toList(); } - Future setSelectedAlbums(List selectedAlbums) async { + Future updateSelectedAlbums(List selectedAlbums) async { await _prefs.setStringList(SELECTED_ALBUMS_KEY, selectedAlbums); + unawaited(_refreshOnSelection()); } String? getAlbumsLastHash() { @@ -93,31 +65,44 @@ class AlbumHomeWidgetService { await _prefs.setString(ALBUMS_LAST_HASH_KEY, hash); } - Future countHomeWidgets() async { - return await HomeWidgetService.instance.countHomeWidgets( - ANDROID_CLASS_NAME, - IOS_CLASS_NAME, - ); + Future initAlbumHomeWidget(bool isBg) async { + await HomeWidgetService.instance.computeLock.synchronized(() async { + if (await _hasAnyBlockers(isBg)) { + await clearWidget(); + return; + } + + _logger.info("Initializing albums widget"); + + final bool forceFetchNewAlbums = await _shouldUpdateWidgetCache(); + + if (forceFetchNewAlbums) { + await _updateAlbumsWidgetCache(); + await setSelectionChange(false); + _logger.info("Force fetch new albums complete"); + } else { + await _refreshAlbumsWidget(); + _logger.info("Refresh albums widget complete"); + } + }); } Future clearWidget() async { - if (await _isWidgetEmpty()) { - _logger.info("Widget already empty, nothing to clear"); + if (getAlbumsStatus() == WidgetStatus.syncedEmpty) { return; } - _logger.info("Clearing AlbumsHomeWidget"); + await setAlbumsLastHash(""); await _setTotalAlbums(null); await updateAlbumsStatus(WidgetStatus.syncedEmpty); - _hasSyncedAlbums = false; await _refreshWidget(message: "AlbumsHomeWidget cleared & updated"); } - bool getAlbumsChanged() { - return _prefs.getBool(ALBUMS_CHANGED_KEY) ?? false; + bool? hasSelectionChanged() { + return _prefs.getBool(ALBUMS_CHANGED_KEY); } - Future updateAlbumsChanged(bool value) async { + Future setSelectionChange(bool value) async { _logger.info("Updating albums changed flag to $value"); await _prefs.setBool(ALBUMS_CHANGED_KEY, value); } @@ -133,35 +118,36 @@ class AlbumHomeWidgetService { await _prefs.setInt(ALBUMS_STATUS_KEY, value.index); } - Future checkPendingAlbumsSync({bool addDelay = true}) async { - if (addDelay) { - await Future.delayed(const Duration(seconds: 5)); - } + Future countHomeWidgets() async { + return await HomeWidgetService.instance.countHomeWidgets( + ANDROID_CLASS_NAME, + IOS_CLASS_NAME, + ); + } - final isWidgetEmpty = await _isWidgetEmpty(); - final shouldForceFetch = await _shouldForceFetchAlbums(isWidgetEmpty); - - if (_hasSyncedAlbums && !shouldForceFetch) { - _logger.info("Albums already synced, no action needed"); + Future checkPendingAlbumsSync() async { + if (await _hasAnyBlockers()) { + await clearWidget(); return; } - await initHomeWidget(shouldForceFetch); + _logger.info("Checking pending albums sync"); + if (await _shouldUpdateWidgetCache()) { + await initAlbumHomeWidget(false); + } } - Future albumsChanged() async { + Future _refreshOnSelection() async { final lastHash = getAlbumsLastHash(); - final selectedAlbumIds = await _getEffectiveSelectedAlbumIds(); + final selectedAlbumIds = await _getEffectiveSelectedAlbumIds(false); final currentHash = _calculateHash(selectedAlbumIds); - - if (selectedAlbumIds.isEmpty || currentHash == lastHash) { + if (lastHash != null && currentHash == lastHash) { _logger.info("No changes detected in albums"); return; } - _logger.info("Albums changed, updating widget"); - await updateAlbumsChanged(true); - await initHomeWidget(true); + await setSelectionChange(true); + await initAlbumHomeWidget(false); } List getAlbumsByIds(List albumIds) { @@ -169,7 +155,9 @@ class AlbumHomeWidgetService { for (final albumId in albumIds) { final collection = CollectionsService.instance.getCollectionByID(albumId); - if (collection != null) { + if (collection != null && + !collection.isDeleted && + !collection.isHidden()) { albums.add(collection); } } @@ -177,31 +165,11 @@ class AlbumHomeWidgetService { return albums; } - String _calculateHash(List albumIds) { - String updationTimestamps = ""; - - for (final albumId in albumIds) { - final collection = CollectionsService.instance.getCollectionByID(albumId); - if (collection != null) { - updationTimestamps += "${collection.updationTime.toString()}_"; - } - } - - final hash = md5 - .convert(utf8.encode(updationTimestamps)) - .toString() - .substring(0, 10); - return hash; - } - Future onLaunchFromWidget( int fileId, int collectionId, BuildContext context, ) async { - _hasSyncedAlbums = true; - await _syncExistingAlbums(); - final collection = CollectionsService.instance.getCollectionByID(collectionId); if (collection == null) { @@ -229,7 +197,7 @@ class AlbumHomeWidgetService { return; } - await routeToPage( + routeToPage( context, DetailPage( DetailPageConfiguration( @@ -239,62 +207,66 @@ class AlbumHomeWidgetService { ), ), forceCustomPageRoute: true, - ); + ).ignore(); + await _refreshAlbumsWidget(); } // Private methods - Future _hasAnyBlockers() async { + String _calculateHash(List albumIds) { + String updationTimestamps = ""; + + // TODO: This can be done in one shot by querying the database directly + for (final albumId in albumIds) { + final collection = CollectionsService.instance.getCollectionByID(albumId); + if (collection != null) { + updationTimestamps += "$albumId:${collection.updationTime.toString()}_"; + } + } + + if (updationTimestamps.isEmpty) return ""; + + final hash = md5 + .convert(utf8.encode(updationTimestamps)) + .toString() + .substring(0, 10); + return hash; + } + + Future _hasAnyBlockers([bool isBg = false]) async { // Check if first import is completed final hasCompletedFirstImport = LocalSyncService.instance.hasCompletedFirstImport(); if (!hasCompletedFirstImport) { - _logger.warning("First import not completed"); return true; } // Check if selected albums exist - final selectedAlbumIds = getSelectedAlbumIds(); - final albums = getAlbumsByIds(selectedAlbumIds ?? []); + final selectedAlbumIds = await _getEffectiveSelectedAlbumIds(isBg); + final albums = getAlbumsByIds(selectedAlbumIds); - if ((selectedAlbumIds?.isNotEmpty ?? false) && albums.isEmpty) { - _logger.warning("Selected albums not found"); + if (albums.isEmpty) { + _logger.info("Selected albums are empty or do not exist"); return true; } return false; } - Future _forceAlbumsUpdate() async { - await _loadAndRenderAlbums(); - await updateAlbumsChanged(false); - } - - Future _syncExistingAlbums() async { - final homeWidgetCount = await countHomeWidgets(); - if (homeWidgetCount == 0) { - _logger.warning("No active home widgets found"); - return; - } - + Future _refreshAlbumsWidget() async { + // only refresh if widget was synced without issues + if (await countHomeWidgets() == 0) return; await _refreshWidget(message: "Refreshing from existing album set"); } - Future _isWidgetEmpty() async { - final totalAlbums = await _getTotalAlbums(); - return totalAlbums == 0 || totalAlbums == null; - } - - Future _shouldForceFetchAlbums(bool isWidgetEmpty) async { + Future _shouldUpdateWidgetCache() async { // Check if albums changed flag is set - final albumsChanged = _prefs.getBool(ALBUMS_CHANGED_KEY); - if (albumsChanged == true) { + if (hasSelectionChanged() == true) { return true; } // Check if we have any albums selected final selectedAlbumIds = await _getEffectiveSelectedAlbumIds(); if (selectedAlbumIds.isEmpty) { - _logger.warning("No albums selected"); return false; } @@ -304,7 +276,6 @@ class AlbumHomeWidgetService { if (currentHash == lastHash) { final saveStatus = getAlbumsStatus(); - switch (saveStatus) { case WidgetStatus.syncedPartially: return await countHomeWidgets() > 0; @@ -318,14 +289,18 @@ class AlbumHomeWidgetService { return true; } - Future> _getEffectiveSelectedAlbumIds() async { + Future> _getEffectiveSelectedAlbumIds([bool isBg = false]) async { final selectedAlbumIds = getSelectedAlbumIds(); // If no albums selected, use favorites as default if (selectedAlbumIds == null || selectedAlbumIds.isEmpty) { + if (isBg) { + await FavoritesService.instance.initFav(); + } final favoriteId = await FavoritesService.instance.getFavoriteCollectionID(); if (favoriteId != null) { + await updateSelectedAlbums([favoriteId.toString()]); return [favoriteId]; } } @@ -333,14 +308,6 @@ class AlbumHomeWidgetService { return selectedAlbumIds ?? []; } - Future _getTotalAlbums() async { - return HomeWidgetService.instance.getData(TOTAL_ALBUMS_KEY); - } - - Future _setTotalAlbums(int? total) async { - await HomeWidgetService.instance.setData(TOTAL_ALBUMS_KEY, total); - } - Future _refreshWidget({String? message}) async { await HomeWidgetService.instance.updateWidget( androidClass: ANDROID_CLASS_NAME, @@ -378,25 +345,22 @@ class AlbumHomeWidgetService { } } - if (albumsWithFiles.isEmpty) { - _logger.warning("No albums with files found"); - } - return albumsWithFiles; } - Future _loadAndRenderAlbums() async { + Future _setTotalAlbums(int? total) async { + await HomeWidgetService.instance.setData(TOTAL_ALBUMS_KEY, total); + } + + Future _updateAlbumsWidgetCache() async { + final selectedAlbumIds = await _getEffectiveSelectedAlbumIds(); final albumsWithFiles = await _getAlbumsWithFiles(); if (albumsWithFiles.isEmpty) { - _logger.warning("No files found for any albums, clearing widget"); await clearWidget(); return; } - final currentTotal = await _getTotalAlbums(); - _logger.info("Current total albums in widget: $currentTotal"); - final bool isWidgetPresent = await countHomeWidgets() > 0; final limit = isWidgetPresent ? MAX_ALBUMS_LIMIT : 5; @@ -465,7 +429,6 @@ class AlbumHomeWidgetService { } // Update the hash to track changes - final selectedAlbumIds = await _getEffectiveSelectedAlbumIds(); final hash = _calculateHash(selectedAlbumIds); await setAlbumsLastHash(hash); diff --git a/mobile/lib/services/collections_service.dart b/mobile/lib/services/collections_service.dart index 27f1c53eb0..ee3d662a63 100644 --- a/mobile/lib/services/collections_service.dart +++ b/mobile/lib/services/collections_service.dart @@ -1180,7 +1180,7 @@ class CollectionsService { String passwordHash, int collectionID, ) async { - final authToken = await getSharedPublicAlbumToken(collectionID); + final authToken = getSharedPublicAlbumToken(collectionID); try { final response = await _enteDio.post( "/public-collection/verify-password", @@ -1212,9 +1212,7 @@ class CollectionsService { BuildContext context, int collectionID, ) async { - final authToken = await getSharedPublicAlbumToken(collectionID); - final jwtToken = await getSharedPublicAlbumTokenJWT(collectionID); - final key = await getSharedPublicAlbumKey(collectionID); + final key = getSharedPublicAlbumKey(collectionID); if (key.isEmpty) { throw Exception("Collection key not found"); } @@ -1231,36 +1229,32 @@ class CollectionsService { "encryptedKey": CryptoUtil.bin2base64(encryptedKey), }, options: Options( - headers: { - "X-Auth-Access-Token": authToken, - "X-Auth-Access-Token-JWT": jwtToken, - }, + headers: publicCollectionHeaders(collectionID), ), ); } - Future getSharedPublicAlbumKey(int collectionID) async { + String getSharedPublicAlbumKey(int collectionID) { if (_cachedPublicAlbumKey.containsKey(collectionID)) { return _cachedPublicAlbumKey[collectionID]!; } return ""; } - Future getSharedPublicAlbumToken(int collectionID) async { - if (_cachedPublicAlbumToken.containsKey(collectionID)) { - return _cachedPublicAlbumToken[collectionID]; - } - return null; + String? getSharedPublicAlbumToken(int collectionID) { + return _cachedPublicAlbumToken[collectionID]; } - Future getSharedPublicAlbumTokenJWT(int collectionID) async { - if (_cachedPublicAlbumJWT.containsKey(collectionID)) { - return _cachedPublicAlbumJWT[collectionID]; - } - return null; + Map publicCollectionHeaders(int collectionID) { + final String? albumToken = _cachedPublicAlbumToken[collectionID]; + final String? albumJwtToken = _cachedPublicAlbumJWT[collectionID]; + return { + if (albumToken != null) "X-Auth-Access-Token": albumToken, + if (albumJwtToken != null) "X-Auth-Access-Token-JWT": albumJwtToken, + }; } - /// Is a public link opened in the app + /// Is a public link opened in the app via deeplink bool isSharedPublicLink(int collectionID) { return _cachedPublicCollectionID.contains(collectionID); } @@ -1357,7 +1351,7 @@ class CollectionsService { Future fetchCollectionByID(int collectionID) async { try { - _logger.fine('fetching collectionByID $collectionID'); + _logger.info('fetching collectionByID $collectionID'); final response = await _enteDio.get( "/collections/$collectionID", ); diff --git a/mobile/lib/services/entity_service.dart b/mobile/lib/services/entity_service.dart index 2986a33ef5..6c317b1fe4 100644 --- a/mobile/lib/services/entity_service.dart +++ b/mobile/lib/services/entity_service.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:math'; +import "package:crypto/crypto.dart"; import "package:ente_crypto/ente_crypto.dart"; import 'package:flutter/foundation.dart'; import 'package:logging/logging.dart'; @@ -40,6 +41,13 @@ class EntityService { return "entity_last_sync_time_" + type.typeToString(); } + Future> getCertainEntities( + EntityType type, + List ids, + ) async { + return await _db.getCertainEntities(type, ids); + } + Future> getEntities(EntityType type) async { return await _db.getEntities(type); } @@ -109,6 +117,10 @@ class EntityService { } } + int lastSyncTime(EntityType type) { + return _prefs.getInt(_getEntityLastSyncTimePrefix(type)) ?? 0; + } + Future _remoteToLocalSync( EntityType type, { int prevFetchCount = 0, @@ -219,4 +231,22 @@ class EntityService { rethrow; } } + + Future getPreHashForEntities( + EntityType type, + List ids, + ) async { + return await _db.getPreHashForEntities(type, ids); + } + + Future getHashForIds(List personIds) async { + final preHash = await getPreHashForEntities(EntityType.cgroup, personIds); + + if (preHash == null) { + return ""; + } + + final hash = md5.convert(utf8.encode(preHash)).toString().substring(0, 10); + return hash; + } } diff --git a/mobile/lib/services/filedata/filedata_service.dart b/mobile/lib/services/filedata/filedata_service.dart index dd01fa36e4..5407011313 100644 --- a/mobile/lib/services/filedata/filedata_service.dart +++ b/mobile/lib/services/filedata/filedata_service.dart @@ -1,9 +1,9 @@ import "dart:async"; import "package:computer/computer.dart"; +import "package:dio/dio.dart"; import "package:flutter/foundation.dart" show Uint8List; import "package:logging/logging.dart"; -import "package:photos/core/network/network.dart"; import "package:photos/db/files_db.dart"; import "package:photos/db/ml/db.dart"; import "package:photos/db/ml/filedata.dart"; @@ -16,26 +16,23 @@ import "package:photos/utils/gzip.dart"; import "package:shared_preferences/shared_preferences.dart"; class FileDataService { - FileDataService._privateConstructor(); - static final Computer _computer = Computer.shared(); - static final FileDataService instance = FileDataService._privateConstructor(); final _logger = Logger("FileDataService"); - final _dio = NetworkClient.instance.enteDio; - late final SharedPreferences _prefs; - Map? previewIds; + final Dio _dio; + final SharedPreferences _prefs; + late Map previewIds; - void init(SharedPreferences prefs) { - _prefs = prefs; + FileDataService(this._prefs, this._dio) { + _logger.info("FileDataService constructor called"); + previewIds = {}; } /// Used to not sync preview ids everytime a chunking and preview /// upload is successful, instead update the local copy of those /// preview ids void appendPreview(int id, String objectId, int objectSize) { - if (previewIds?.containsKey(id) ?? false) return; - previewIds ??= {}; - previewIds?[id] = PreviewInfo( + if (previewIds.containsKey(id)) return; + previewIds[id] = PreviewInfo( objectId: objectId, objectSize: objectSize, ); @@ -152,6 +149,9 @@ class FileDataService { previewIds = await MLDataDB.instance.getFileIDsVidPreview(); } while (hasMoreData); } catch (e) { + if (previewIds.isEmpty) { + previewIds = await MLDataDB.instance.getFileIDsVidPreview(); + } _logger.severe("Failed to syncDiff", e); rethrow; } diff --git a/mobile/lib/services/hidden_service.dart b/mobile/lib/services/hidden_service.dart index b97695a62d..f7321b0670 100644 --- a/mobile/lib/services/hidden_service.dart +++ b/mobile/lib/services/hidden_service.dart @@ -138,7 +138,7 @@ extension HiddenService on CollectionsService { for (MapEntry> entry in collectionToFilesMap.entries) { if (entry.key == defaultHiddenCollection.id) { - _logger.finest('file already part of hidden collection'); + _logger.info('file already part of hidden collection'); continue; } final Collection? c = getCollectionByID(entry.key); diff --git a/mobile/lib/services/home_widget_service.dart b/mobile/lib/services/home_widget_service.dart index aac3853aad..3c86fbe51b 100644 --- a/mobile/lib/services/home_widget_service.dart +++ b/mobile/lib/services/home_widget_service.dart @@ -15,11 +15,18 @@ import 'package:photos/services/people_home_widget_service.dart'; import 'package:photos/services/smart_memories_service.dart'; import 'package:photos/utils/thumbnail_util.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import "package:synchronized/synchronized.dart"; enum WidgetStatus { + // notSynced means the widget is not initialized or has no data notSynced, + // partially synced means some images were synced but not all + // this can happen if some widgets were not installed but we did a sync regardless + // or if the sync fails midway syncedPartially, + // we purposefully set widget to empty, widget had data syncedEmpty, + // all widgets were synced successfully syncedAll, } @@ -47,6 +54,7 @@ class HomeWidgetService { HomeWidgetService._privateConstructor(); final Logger _logger = Logger((HomeWidgetService).toString()); + final computeLock = Lock(); void init(SharedPreferences prefs) { setAppGroupID(iOSGroupIDMemory); @@ -54,19 +62,19 @@ class HomeWidgetService { } void _initializeWidgetServices(SharedPreferences prefs) { - MemoryHomeWidgetService.instance.init(prefs); - PeopleHomeWidgetService.instance.init(prefs); AlbumHomeWidgetService.instance.init(prefs); + PeopleHomeWidgetService.instance.init(prefs); + MemoryHomeWidgetService.instance.init(prefs); } void setAppGroupID(String id) { hw.HomeWidget.setAppGroupId(id).ignore(); } - Future initHomeWidget() async { - await MemoryHomeWidgetService.instance.initMemoryHomeWidget(null); - await PeopleHomeWidgetService.instance.initHomeWidget(null); - await AlbumHomeWidgetService.instance.initHomeWidget(null); + Future initHomeWidget([bool isBg = false]) async { + await AlbumHomeWidgetService.instance.initAlbumHomeWidget(isBg); + await PeopleHomeWidgetService.instance.initPeopleHomeWidget(); + await MemoryHomeWidgetService.instance.initMemoryHomeWidget(); } Future updateWidget({ @@ -214,10 +222,21 @@ class HomeWidgetService { } await Future.wait([ - MemoryHomeWidgetService.instance.clearWidget(), - PeopleHomeWidgetService.instance.clearWidget(), AlbumHomeWidgetService.instance.clearWidget(), + PeopleHomeWidgetService.instance.clearWidget(), + MemoryHomeWidgetService.instance.clearWidget(), ]); + + try { + final String widgetParent = await _getWidgetStorageDirectory(); + final String widgetPath = '$widgetParent/$WIDGET_DIRECTORY'; + final dir = Directory(widgetPath); + + await dir.delete(recursive: true); + _logger.info("Widget directory cleared successfully"); + } catch (e) { + _logger.severe("Failed to clear widget directory", e); + } } /// Handle app launch from a widget diff --git a/mobile/lib/services/ignored_files_service.dart b/mobile/lib/services/ignored_files_service.dart index c03c624f74..22009d1835 100644 --- a/mobile/lib/services/ignored_files_service.dart +++ b/mobile/lib/services/ignored_files_service.dart @@ -98,7 +98,7 @@ class IgnoredFilesService { } Future> _loadIDsToReasonMap() async { - _logger.fine('loading existing IDs'); + _logger.info('loading existing IDs'); final dbResult = await _db.getAll(); final Map result = {}; for (IgnoredFile iFile in dbResult) { diff --git a/mobile/lib/services/isolate_functions.dart b/mobile/lib/services/isolate_functions.dart index 929790c588..ae4e1e8851 100644 --- a/mobile/lib/services/isolate_functions.dart +++ b/mobile/lib/services/isolate_functions.dart @@ -1,4 +1,3 @@ -import "dart:io" show File; import 'dart:typed_data' show Uint8List; import "package:ml_linalg/linalg.dart"; @@ -98,12 +97,11 @@ Future isolateFunction( /// MLComputer case IsolateOperation.generateFaceThumbnails: final imagePath = args['imagePath'] as String; - final Uint8List imageData = await File(imagePath).readAsBytes(); final faceBoxesJson = args['faceBoxesList'] as List>; final List faceBoxes = faceBoxesJson.map((json) => FaceBox.fromJson(json)).toList(); final List results = await generateFaceThumbnailsUsingCanvas( - imageData, + imagePath, faceBoxes, ); return List.from(results); diff --git a/mobile/lib/services/local_file_update_service.dart b/mobile/lib/services/local_file_update_service.dart index 0f9c48dcc0..56ef8514a2 100644 --- a/mobile/lib/services/local_file_update_service.dart +++ b/mobile/lib/services/local_file_update_service.dart @@ -3,12 +3,10 @@ import 'dart:core'; import 'dart:io'; import 'package:logging/logging.dart'; -import "package:photo_manager/photo_manager.dart"; import "package:photos/core/configuration.dart"; import 'package:photos/core/errors.dart'; import 'package:photos/db/file_updation_db.dart'; import 'package:photos/db/files_db.dart'; -import "package:photos/extensions/list.dart"; import 'package:photos/models/file/file.dart'; import 'package:photos/models/file/file_type.dart'; import 'package:photos/utils/file_uploader_util.dart'; @@ -21,10 +19,6 @@ class LocalFileUpdateService { late FileUpdationDB _fileUpdationDB; late SharedPreferences _prefs; late Logger _logger; - final String _androidMissingGPSImportDone = - 'fm_android_missing_gps_import_done'; - final String _androidMissingGPSCheckDone = - 'fm_android_missing_gps_check_done'; final List _oldMigrationKeys = [ 'fm_badCreationTime', @@ -37,6 +31,7 @@ class LocalFileUpdateService { 'fm_import_ios_live_photo_size', 'fm_ios_live_photo_check', 'fm_import_ios_live_photo_check', + 'fm_android_missing_gps_check_done', ]; Completer? _existingMigration; @@ -62,9 +57,6 @@ class LocalFileUpdateService { try { await _markFilesWhichAreActuallyUpdated(); _cleanUpOlderMigration().ignore(); - if (Platform.isAndroid) { - await _androidMissingGPSCheck(); - } } catch (e, s) { _logger.severe('failed to perform migration', e, s); } finally { @@ -90,6 +82,7 @@ class LocalFileUpdateService { 'badLocationCord', 'livePhotoSize', 'livePhotoCheck', + 'androidMissingGPS', ]); for (var element in _oldMigrationKeys) { await _prefs.remove(element); @@ -155,6 +148,11 @@ class LocalFileUpdateService { if (processedIDs.contains(file.localID)) { continue; } + if (!file.isUploaded) { + _logger.info("File ${file.tag} is not uploaded, skipping hash check"); + processedIDs.add(file.localID!); + continue; + } MediaUploadData uploadData; try { uploadData = await getUploadData(file); @@ -197,13 +195,13 @@ class LocalFileUpdateService { file.modificationTime!, fileType, ); - _logger.fine('fileType changed for ${file.tag} to ${e.reason} for '); + _logger.info('fileType changed for ${file.tag} to ${e.reason} for '); } else { _logger.severe("failed to check hash: invalid file ${file.tag}", e); } processedIDs.add(file.localID!); - } catch (e) { - _logger.severe("Failed to check hash", e); + } catch (e, s) { + _logger.severe("Failed to check hash", e, s); } finally {} } await _fileUpdationDB.deleteByLocalIDs( @@ -212,131 +210,6 @@ class LocalFileUpdateService { ); } - //#region Android Missing GPS specific methods ### - - Future _androidMissingGPSCheck() async { - if (_prefs.containsKey(_androidMissingGPSCheckDone)) { - return; - } - await _importAndroidBadGPSCandidate(); - // singleRunLimit indicates number of files to check during single - // invocation of this method. The limit act as a crude way to limit the - // resource consumed by the method - const int singleRunLimit = 500; - final localIDsToProcess = - await _fileUpdationDB.getLocalIDsForPotentialReUpload( - singleRunLimit, - FileUpdationDB.androidMissingGPS, - ); - if (localIDsToProcess.isNotEmpty) { - final chunksOf50 = localIDsToProcess.chunks(50); - for (final chunk in chunksOf50) { - final sTime = DateTime.now().microsecondsSinceEpoch; - final List futures = []; - final chunkOf10 = chunk.chunks(10); - for (final smallChunk in chunkOf10) { - futures.add(_checkForMissingGPS(smallChunk)); - } - await Future.wait(futures); - final eTime = DateTime.now().microsecondsSinceEpoch; - final d = Duration(microseconds: eTime - sTime); - _logger.info( - 'Performed missing GPS Location check for ${chunk.length} files ' - 'completed in ${d.inSeconds.toString()} secs', - ); - } - } else { - _logger.info('Completed android missing GPS check'); - await _prefs.setBool(_androidMissingGPSCheckDone, true); - } - } - - Future _checkForMissingGPS(List localIDs) async { - try { - final List localFiles = - await FilesDB.instance.getLocalFiles(localIDs); - final ownerID = Configuration.instance.getUserID()!; - final Set localIDsWithFile = {}; - final Set reuploadCandidate = {}; - final Set processedIDs = {}; - for (EnteFile file in localFiles) { - if (file.localID == null) continue; - // ignore files that are not uploaded or have different owner - if (!file.isUploaded || file.ownerID! != ownerID) { - processedIDs.add(file.localID!); - } - if (file.hasLocation) { - processedIDs.add(file.localID!); - } - } - for (EnteFile enteFile in localFiles) { - try { - if (enteFile.localID == null || - processedIDs.contains(enteFile.localID!)) { - continue; - } - - final localID = enteFile.localID!; - localIDsWithFile.add(localID); - final AssetEntity? entity = await AssetEntity.fromId(localID); - if (entity == null) { - processedIDs.add(localID); - } else { - final latLng = await entity.latlngAsync(); - if ((latLng.longitude ?? 0) == 0 || (latLng.latitude ?? 0) == 0) { - processedIDs.add(localID); - } else { - reuploadCandidate.add(localID); - processedIDs.add(localID); - } - } - } catch (e, s) { - processedIDs.add(enteFile.localID!); - _logger.severe('lat/long check file ${enteFile.toString()}', e, s); - } - } - for (String id in localIDs) { - // if the file with given localID doesn't exist, consider it as done. - if (!localIDsWithFile.contains(id)) { - processedIDs.add(id); - } - } - await FileUpdationDB.instance.insertMultiple( - reuploadCandidate.toList(), - FileUpdationDB.modificationTimeUpdated, - ); - await FileUpdationDB.instance.deleteByLocalIDs( - processedIDs.toList(), - FileUpdationDB.androidMissingGPS, - ); - } catch (e, s) { - _logger.severe('error while checking missing GPS', e, s); - } - } - - Future _importAndroidBadGPSCandidate() async { - if (_prefs.containsKey(_androidMissingGPSImportDone)) { - return; - } - final sTime = DateTime.now().microsecondsSinceEpoch; - _logger.info('importing files without missing GPS'); - final int ownerID = Configuration.instance.getUserID()!; - final fileLocalIDs = - await FilesDB.instance.getLocalFilesBackedUpWithoutLocation(ownerID); - await _fileUpdationDB.insertMultiple( - fileLocalIDs, - FileUpdationDB.androidMissingGPS, - ); - final eTime = DateTime.now().microsecondsSinceEpoch; - final d = Duration(microseconds: eTime - sTime); - _logger.info( - 'importing completed, total files count ${fileLocalIDs.length} and took ${d.inSeconds.toString()} seconds', - ); - await _prefs.setBool(_androidMissingGPSImportDone, true); - } - - //#endregion Android Missing GPS specific methods ### - Future getUploadData(EnteFile file) async { final mediaUploadData = await getUploadDataFromEnteFile(file); // delete the file from app's internal cache if it was copied to app diff --git a/mobile/lib/services/machine_learning/compute_controller.dart b/mobile/lib/services/machine_learning/compute_controller.dart new file mode 100644 index 0000000000..dfc663f85c --- /dev/null +++ b/mobile/lib/services/machine_learning/compute_controller.dart @@ -0,0 +1,247 @@ +import "dart:async"; +import "dart:io"; + +import "package:battery_info/battery_info_plugin.dart"; +import "package:battery_info/model/android_battery_info.dart"; +import "package:battery_info/model/iso_battery_info.dart"; +import "package:flutter/foundation.dart"; +import "package:logging/logging.dart"; +import "package:photos/core/event_bus.dart"; +import "package:photos/events/compute_control_event.dart"; +import "package:thermal/thermal.dart"; + +enum _ComputeRunState { + idle, + runningML, + generatingStream, +} + +class ComputeController { + final _logger = Logger("ComputeController"); + + static const kMaximumTemperatureAndroid = 42; // 42 degree celsius + static const kMinimumBatteryLevel = 20; // 20% + final kDefaultInteractionTimeout = Duration(seconds: Platform.isIOS ? 5 : 15); + static const kUnhealthyStates = ["over_heat", "over_voltage", "dead"]; + + static final _thermal = Thermal(); + IosBatteryInfo? _iosLastBatteryInfo; + AndroidBatteryInfo? _androidLastBatteryInfo; + ThermalStatus? _lastThermalStatus; + + bool _isDeviceHealthy = true; + bool _isUserInteracting = true; + bool _canRunCompute = false; + bool interactionOverride = false; + late Timer _userInteractionTimer; + + _ComputeRunState _currentRunState = _ComputeRunState.idle; + bool _waitingToRunML = false; + + bool get isDeviceHealthy => _isDeviceHealthy; + + ComputeController() { + _logger.info('ComputeController constructor'); + _startInteractionTimer(kDefaultInteractionTimeout); + if (Platform.isIOS) { + if (kDebugMode) { + _logger.info( + "iOS battery info stream is not available in simulator, disabling in debug mode", + ); + // if you need to test on physical device, uncomment this check + return; + } + BatteryInfoPlugin() + .iosBatteryInfoStream + .listen((IosBatteryInfo? batteryInfo) { + _oniOSBatteryStateUpdate(batteryInfo); + }); + } + if (Platform.isAndroid) { + BatteryInfoPlugin() + .androidBatteryInfoStream + .listen((AndroidBatteryInfo? batteryInfo) { + _onAndroidBatteryStateUpdate(batteryInfo); + }); + } + _thermal.onThermalStatusChanged.listen((ThermalStatus thermalState) { + _onThermalStateUpdate(thermalState); + }); + _logger.info('init done '); + } + + bool requestCompute({bool ml = false, bool stream = false}) { + _logger.info("Requesting compute: ml: $ml, stream: $stream"); + if (!_isDeviceHealthy || !_canRunGivenUserInteraction()) { + _logger.info("Device not healthy or user interacting, denying request."); + return false; + } + if (ml) { + return _requestML(); + } else if (stream) { + return _requestStream(); + } + _logger.severe("No compute request specified, denying request."); + return false; + } + + bool _requestML() { + if (_currentRunState == _ComputeRunState.idle) { + _currentRunState = _ComputeRunState.runningML; + _waitingToRunML = false; + _logger.info("ML request granted"); + return true; + } else if (_currentRunState == _ComputeRunState.runningML) { + return true; + } + _logger.info( + "ML request denied, current state: $_currentRunState, wants to run ML: $_waitingToRunML", + ); + _waitingToRunML = true; + return false; + } + + bool _requestStream() { + if (_currentRunState == _ComputeRunState.idle && !_waitingToRunML) { + _logger.info("Stream request granted"); + _currentRunState = _ComputeRunState.generatingStream; + return true; + } else if (_currentRunState == _ComputeRunState.generatingStream && + !_waitingToRunML) { + return true; + } + _logger.info( + "Stream request denied, current state: $_currentRunState, wants to run ML: $_waitingToRunML", + ); + return false; + } + + void releaseCompute({bool ml = false, bool stream = false}) { + _logger.info( + "Releasing compute: ml: $ml, stream: $stream, current state: $_currentRunState", + ); + + if (ml) { + if (_currentRunState == _ComputeRunState.runningML) { + _currentRunState = _ComputeRunState.idle; + } + _waitingToRunML = false; + } else if (stream) { + if (_currentRunState == _ComputeRunState.generatingStream) { + _currentRunState = _ComputeRunState.idle; + } + } + } + + void onUserInteraction() { + if (!_isUserInteracting) { + _logger.info("User is interacting with the app"); + _isUserInteracting = true; + _fireControlEvent(); + } + _resetTimer(); + } + + bool _canRunGivenUserInteraction() { + return !_isUserInteracting || interactionOverride; + } + + void forceOverrideML({required bool turnOn}) { + _logger.info("Forcing to turn on ML: $turnOn"); + interactionOverride = turnOn; + _fireControlEvent(); + } + + void _fireControlEvent() { + final shouldRunCompute = _isDeviceHealthy && _canRunGivenUserInteraction(); + if (shouldRunCompute != _canRunCompute) { + _canRunCompute = shouldRunCompute; + _logger.info( + "Firing event: $shouldRunCompute (device health: $_isDeviceHealthy, user interaction: $_isUserInteracting, mlInteractionOverride: $interactionOverride)", + ); + Bus.instance.fire(ComputeControlEvent(shouldRunCompute)); + } + } + + void _startInteractionTimer(Duration timeout) { + _userInteractionTimer = Timer(timeout, () { + _isUserInteracting = false; + _fireControlEvent(); + }); + } + + void _resetTimer() { + _userInteractionTimer.cancel(); + _startInteractionTimer(kDefaultInteractionTimeout); + } + + void _onAndroidBatteryStateUpdate(AndroidBatteryInfo? batteryInfo) { + _androidLastBatteryInfo = batteryInfo; + _logger.info("Battery info: ${batteryInfo!.toJson()}"); + _isDeviceHealthy = _computeIsAndroidDeviceHealthy(); + _fireControlEvent(); + } + + void _oniOSBatteryStateUpdate(IosBatteryInfo? batteryInfo) { + _iosLastBatteryInfo = batteryInfo; + _logger.info("Battery info: ${batteryInfo!.toJson()}"); + _isDeviceHealthy = _computeIsiOSDeviceHealthy(); + _fireControlEvent(); + } + + void _onThermalStateUpdate(ThermalStatus? thermalStatus) { + _lastThermalStatus = thermalStatus; + _logger.info("Thermal status: $thermalStatus"); + _isDeviceHealthy = Platform.isAndroid + ? _computeIsAndroidDeviceHealthy() + : _computeIsiOSDeviceHealthy(); + _fireControlEvent(); + } + + bool _computeIsAndroidDeviceHealthy() { + return _hasSufficientBattery( + _androidLastBatteryInfo?.batteryLevel ?? kMinimumBatteryLevel, + ) && + _isAcceptableTemperatureAndroid() && + _isBatteryHealthyAndroid() && + _isAcceptableThermalState(); + } + + bool _computeIsiOSDeviceHealthy() { + return _hasSufficientBattery( + _iosLastBatteryInfo?.batteryLevel ?? kMinimumBatteryLevel, + ) && + _isAcceptableThermalState(); + } + + bool _isAcceptableThermalState() { + switch (_lastThermalStatus) { + case null: + return true; + case ThermalStatus.none: + case ThermalStatus.light: + case ThermalStatus.moderate: + return true; + case ThermalStatus.severe: + case ThermalStatus.critical: + case ThermalStatus.emergency: + case ThermalStatus.shutdown: + _logger.warning("Thermal status is unacceptable: $_lastThermalStatus"); + return false; + } + } + + bool _hasSufficientBattery(int batteryLevel) { + return batteryLevel >= kMinimumBatteryLevel; + } + + bool _isAcceptableTemperatureAndroid() { + return (_androidLastBatteryInfo?.temperature ?? + kMaximumTemperatureAndroid) <= + kMaximumTemperatureAndroid; + } + + bool _isBatteryHealthyAndroid() { + return !kUnhealthyStates.contains(_androidLastBatteryInfo?.health ?? ""); + } +} diff --git a/mobile/lib/services/machine_learning/face_ml/face_detection/face_detection_postprocessing.dart b/mobile/lib/services/machine_learning/face_ml/face_detection/face_detection_postprocessing.dart index a01017559d..624181a669 100644 --- a/mobile/lib/services/machine_learning/face_ml/face_detection/face_detection_postprocessing.dart +++ b/mobile/lib/services/machine_learning/face_ml/face_detection/face_detection_postprocessing.dart @@ -2,95 +2,6 @@ import 'dart:math' as math show max, min; import 'package:photos/services/machine_learning/face_ml/face_detection/detection.dart'; -List yoloOnnxFilterExtractDetections( - double minScoreSigmoidThreshold, - int inputWidth, - int inputHeight, { - required List> results, // // [25200, 16] -}) { - final outputDetections = []; - final output = >[]; - - // Go through the raw output and check the scores - for (final result in results) { - // Filter out raw detections with low scores - if (result[4] < minScoreSigmoidThreshold) { - continue; - } - - // Get the raw detection - final rawDetection = List.from(result); - - // Append the processed raw detection to the output - output.add(rawDetection); - } - - if (output.isEmpty) { - double maxScore = 0; - for (final result in results) { - if (result[4] > maxScore) { - maxScore = result[4]; - } - } - } - - for (final List rawDetection in output) { - // Get absolute bounding box coordinates in format [xMin, yMin, xMax, yMax] https://github.com/deepcam-cn/yolov5-face/blob/eb23d18defe4a76cc06449a61cd51004c59d2697/utils/general.py#L216 - final xMinAbs = rawDetection[0] - rawDetection[2] / 2; - final yMinAbs = rawDetection[1] - rawDetection[3] / 2; - final xMaxAbs = rawDetection[0] + rawDetection[2] / 2; - final yMaxAbs = rawDetection[1] + rawDetection[3] / 2; - - // Get the relative bounding box coordinates in format [xMin, yMin, xMax, yMax] - final box = [ - xMinAbs / inputWidth, - yMinAbs / inputHeight, - xMaxAbs / inputWidth, - yMaxAbs / inputHeight, - ]; - - // Get the keypoints coordinates in format [x, y] - final allKeypoints = >[ - [ - rawDetection[5] / inputWidth, - rawDetection[6] / inputHeight, - ], - [ - rawDetection[7] / inputWidth, - rawDetection[8] / inputHeight, - ], - [ - rawDetection[9] / inputWidth, - rawDetection[10] / inputHeight, - ], - [ - rawDetection[11] / inputWidth, - rawDetection[12] / inputHeight, - ], - [ - rawDetection[13] / inputWidth, - rawDetection[14] / inputHeight, - ], - ]; - - // Get the score - final score = - rawDetection[4]; // Or should it be rawDetection[4]*rawDetection[15]? - - // Create the relative detection - final detection = FaceDetectionRelative( - score: score, - box: box, - allKeypoints: allKeypoints, - ); - - // Append the relative detection to the output - outputDetections.add(detection); - } - - return outputDetections; -} - List naiveNonMaxSuppression({ required List detections, required double iouThreshold, diff --git a/mobile/lib/services/machine_learning/face_ml/face_detection/face_detection_service.dart b/mobile/lib/services/machine_learning/face_ml/face_detection/face_detection_service.dart index 5f2458c629..43f971158c 100644 --- a/mobile/lib/services/machine_learning/face_ml/face_detection/face_detection_service.dart +++ b/mobile/lib/services/machine_learning/face_ml/face_detection/face_detection_service.dart @@ -8,6 +8,7 @@ import 'package:onnxruntime/onnxruntime.dart'; import "package:photos/models/ml/face/dimension.dart"; import 'package:photos/services/machine_learning/face_ml/face_detection/detection.dart'; import "package:photos/services/machine_learning/face_ml/face_detection/face_detection_postprocessing.dart"; +import "package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart"; import "package:photos/services/machine_learning/ml_model.dart"; import "package:photos/utils/image_ml_util.dart"; @@ -31,7 +32,7 @@ class FaceDetectionService extends MlModel { static const int kInputWidth = 640; static const int kInputHeight = 640; static const double kIouThreshold = 0.4; - static const double kMinScoreSigmoidThreshold = 0.7; + static const double kMinScoreSigmoidThreshold = kMinFaceDetectionScore; static const int kNumKeypoints = 5; // Singleton pattern @@ -82,7 +83,11 @@ class FaceDetectionService extends MlModel { 'Face detection is finished, in ${inferenceTime.difference(startTime).inMilliseconds} ms (preprocessing: $preprocessingMs ms, inference: $inferenceMs ms)', ); } catch (e, s) { - _logger.severe('Error while running inference (PlatformPlugin: ${MlModel.usePlatformPlugin})', e, s); + _logger.severe( + 'Error while running inference (PlatformPlugin: ${MlModel.usePlatformPlugin})', + e, + s, + ); throw YOLOFaceInterpreterRunException(); } try { diff --git a/mobile/lib/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart b/mobile/lib/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart index b97573fa60..b20af3a2e6 100644 --- a/mobile/lib/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart +++ b/mobile/lib/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart @@ -1,5 +1,3 @@ -import 'package:photos/services/machine_learning/face_ml/face_detection/face_detection_service.dart'; - /// Blur detection threshold const kLaplacianHardThreshold = 10; const kLaplacianSoftThreshold = 50; @@ -8,19 +6,19 @@ const kLaplacianVerySoftThreshold = 200; /// Default blur value const kLapacianDefault = 10000.0; +/// The minimum score for a face to be detected, regardless of quality. Use [kMinimumQualityFaceScore] for high quality faces. +const kMinFaceDetectionScore = 0.5; + /// The minimum score for a face to be shown as detected in the UI -const kMinimumFaceShowScore = 0.70; +const kMinimumFaceShowScore = 0.75; /// The minimum score for a face to be considered a high quality face for clustering and person detection const kMinimumQualityFaceScore = 0.80; const kMediumQualityFaceScore = 0.85; const kHighQualityFaceScore = 0.90; -/// The minimum score for a face to be detected, regardless of quality. Use [kMinimumQualityFaceScore] for high quality faces. -const kMinFaceDetectionScore = FaceDetectionService.kMinScoreSigmoidThreshold; - -/// The minimum cluster size for displaying a cluster in the UI +/// The minimum cluster size for displaying a cluster in the UI by default const kMinimumClusterSizeSearchResult = 10; -/// The minimum cluster sizes to try when the normal minimum doesn't return any results -const kLowerMinimumClusterSizes = [5, 3, 2, 1]; +/// The minimum cluster size for displaying a cluster when the user wants to see all faces +const kMinimumClusterSizeAllFaces = 2; diff --git a/mobile/lib/services/machine_learning/face_ml/face_recognition_service.dart b/mobile/lib/services/machine_learning/face_ml/face_recognition_service.dart index e653751f4f..2f59b4c363 100644 --- a/mobile/lib/services/machine_learning/face_ml/face_recognition_service.dart +++ b/mobile/lib/services/machine_learning/face_ml/face_recognition_service.dart @@ -18,7 +18,7 @@ class FaceRecognitionService { static final _logger = Logger("FaceRecognitionService"); FaceRecognitionService() { - _logger.finest("FaceRecognitionService constructor"); + _logger.info("FaceRecognitionService constructor"); init(); } diff --git a/mobile/lib/services/machine_learning/face_ml/feedback/cluster_feedback.dart b/mobile/lib/services/machine_learning/face_ml/feedback/cluster_feedback.dart index 8742970e33..2cefa84ac6 100644 --- a/mobile/lib/services/machine_learning/face_ml/feedback/cluster_feedback.dart +++ b/mobile/lib/services/machine_learning/face_ml/feedback/cluster_feedback.dart @@ -1,4 +1,4 @@ -import 'dart:developer' as dev; +import 'dart:developer' as dev show log; import "dart:math" show Random, min; import "package:computer/computer.dart"; @@ -11,6 +11,7 @@ import "package:photos/db/ml/db.dart"; import "package:photos/events/people_changed_event.dart"; import "package:photos/extensions/stop_watch.dart"; import "package:photos/generated/protos/ente/common/vector.pb.dart"; +import "package:photos/models/base/id.dart"; import "package:photos/models/file/file.dart"; import "package:photos/models/ml/face/person.dart"; import "package:photos/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart"; @@ -20,6 +21,7 @@ import "package:photos/services/machine_learning/ml_result.dart"; import "package:photos/services/search_service.dart"; class ClusterSuggestion { + final PersonEntity person; final String clusterIDToMerge; final double distancePersonToCluster; final bool usedOnlyMeanForSuggestion; @@ -27,6 +29,7 @@ class ClusterSuggestion { final List faceIDsInCluster; ClusterSuggestion( + this.person, this.clusterIDToMerge, this.distancePersonToCluster, this.usedOnlyMeanForSuggestion, @@ -53,11 +56,7 @@ class ClusterFeedbackService { lastViewedClusterID = ''; } - /// Returns a list of cluster suggestions for a person. Each suggestion is a tuple of the following elements: - /// 1. clusterID: the ID of the cluster - /// 2. distance: the distance between the person's cluster and the suggestion - /// 3. bool: whether the suggestion was found using the mean (true) or the median (false) - /// 4. List: the files in the cluster + /// Returns a list of cluster suggestions for a person. Future> getSuggestionForPerson( PersonEntity person, { bool extremeFilesFirst = true, @@ -105,6 +104,7 @@ class ClusterFeedbackService { if (clusterIDToFiles.containsKey(clusterSuggestion.$1)) { finalSuggestions.add( ClusterSuggestion( + person, clusterSuggestion.$1, clusterSuggestion.$2, clusterSuggestion.$3, @@ -140,7 +140,6 @@ class ClusterFeedbackService { PersonEntity p, ) async { try { - _logger.info('removeFilesFromPerson called'); // Get the relevant faces to be removed final faceIDs = await mlDataDB .getFaceIDsForPerson(p.remoteID) @@ -187,10 +186,9 @@ class ClusterFeedbackService { // Update remote so new sync does not undo this change await PersonService.instance - .removeFilesFromPerson(person: p, faceIDs: faceIDs.toSet()); + .removeFacesFromPerson(person: p, faceIDs: faceIDs.toSet()); Bus.instance.fire(PeopleChangedEvent()); - _logger.info('removeFilesFromPerson done'); return; } catch (e, s) { _logger.severe("Error in removeFilesFromPerson", e, s); @@ -198,6 +196,37 @@ class ClusterFeedbackService { } } + Future removeFaceFromPerson( + String faceID, + PersonEntity person, + ) async { + try { + final updatedClusterID = newClusterID(); + final newFaceIdToClusterID = {faceID: updatedClusterID}; + await mlDataDB.forceUpdateClusterIds(newFaceIdToClusterID); + + // Make sure the deleted faces don't get suggested in the future + final notClusterIdToPersonId = {updatedClusterID: person.remoteID}; + await mlDataDB.bulkCaptureNotPersonFeedback(notClusterIdToPersonId); + + // Update remote so new sync does not undo this change + await PersonService.instance + .removeFacesFromPerson(person: person, faceIDs: {faceID}); + + Bus.instance.fire( + PeopleChangedEvent( + type: PeopleEventType.removedFaceFromCluster, + relevantFaceIDs: [faceID], + source: person.remoteID, + ), + ); + return updatedClusterID; + } catch (e, s) { + _logger.severe("Error in removeFaceFromPerson", e, s); + rethrow; + } + } + Future removeFilesFromCluster( List files, String clusterID, @@ -256,6 +285,29 @@ class ClusterFeedbackService { } } + Future removeFaceFromCluster({ + required String faceID, + String? clusterID, + }) async { + try { + final updatedClusterID = newClusterID(); + final newFaceIdToClusterID = {faceID: updatedClusterID}; + await mlDataDB.forceUpdateClusterIds(newFaceIdToClusterID); + + Bus.instance.fire( + PeopleChangedEvent( + type: PeopleEventType.removedFaceFromCluster, + relevantFaceIDs: [faceID], + source: clusterID ?? "", + ), + ); + return updatedClusterID; + } catch (e, s) { + _logger.severe("Error in removeFaceFromCluster", e, s); + rethrow; + } + } + Future addFacesToCluster(List faceIDs, String clusterID) async { final faceIDToClusterID = {}; for (final faceID in faceIDs) { @@ -266,12 +318,122 @@ class ClusterFeedbackService { return; } + Future> getAllLargePersonSuggestions() async { + final personsMap = await PersonService.instance.getPersonsMap(); + if (personsMap.isEmpty) return []; + try { + final allClusterIdsToCountMap = await mlDataDB.clusterIdToFaceCount(); + final personToClusterIDs = await mlDataDB.getPersonToClusterIDs(); + final personIdToBiggestCluster = {}; + final biggestClusterToPersonID = {}; + final personIdToOtherPersonClusterIDs = >{}; + for (final person in personsMap.values) { + final personID = person.remoteID; + final personClusters = personToClusterIDs[personID] ?? {}; + int biggestClusterSize = 0; + String biggestClusterID = ''; + final Set otherPersonClusterIDs = {}; + for (final clusterID in personClusters) { + final clusterSize = allClusterIdsToCountMap[clusterID] ?? 0; + if (clusterSize > biggestClusterSize) { + if (biggestClusterSize > 0) { + otherPersonClusterIDs.add(biggestClusterID); + } + biggestClusterID = clusterID; + biggestClusterSize = clusterSize; + } else { + otherPersonClusterIDs.add(clusterID); + } + } + personIdToBiggestCluster[personID] = biggestClusterID; + biggestClusterToPersonID[biggestClusterID] = personID; + personIdToOtherPersonClusterIDs[personID] = otherPersonClusterIDs; + } + final allPersonClusters = biggestClusterToPersonID.keys.toSet(); + final allOtherPersonClustersToIgnore = + personIdToOtherPersonClusterIDs.values.reduce((a, b) => a.union(b)); + final Map clusterAvg = await _getUpdateClusterAvg( + allClusterIdsToCountMap, + allOtherPersonClustersToIgnore, + minClusterSize: kMinimumClusterSizeSearchResult, + ); + + final Map> personClusterToIgnoredClusters = {}; + final personToRejectedSuggestions = + await mlDataDB.getPersonToRejectedSuggestions(); + for (final personID in personToRejectedSuggestions.keys) { + final personCluster = personIdToBiggestCluster[personID]; + if (personCluster == null) continue; + final ignoredClusters = personToRejectedSuggestions[personID] ?? {}; + personClusterToIgnoredClusters[personCluster] = ignoredClusters; + } + + final List<(String, double, String)> foundSuggestions = + await calcSuggestionsMeanInComputer( + clusterAvg, + allPersonClusters, + allOtherPersonClustersToIgnore, + personClusterToIgnoredClusters: personClusterToIgnoredClusters, + 0.55, + ); + + // Get the files for the suggestions + final suggestionClusterIDs = foundSuggestions.map((e) => e.$1).toSet(); + final Map> fileIdToClusterID = + await mlDataDB.getFileIdToClusterIDSetForCluster( + suggestionClusterIDs, + ); + final clusterIdToFaceIDs = + await mlDataDB.getClusterToFaceIDs(suggestionClusterIDs); + final Map> clusterIDToFiles = {}; + final allFiles = await SearchService.instance.getAllFilesForSearch(); + for (final f in allFiles) { + if (!fileIdToClusterID.containsKey(f.uploadedFileID ?? -1)) { + continue; + } + final cluserIds = fileIdToClusterID[f.uploadedFileID ?? -1]!; + for (final cluster in cluserIds) { + if (clusterIDToFiles.containsKey(cluster)) { + clusterIDToFiles[cluster]!.add(f); + } else { + clusterIDToFiles[cluster] = [f]; + } + } + } + + final List finalSuggestions = []; + for (final clusterSuggestion in foundSuggestions) { + if (clusterIDToFiles.containsKey(clusterSuggestion.$1)) { + finalSuggestions.add( + ClusterSuggestion( + personsMap[biggestClusterToPersonID[clusterSuggestion.$3]]!, + clusterSuggestion.$1, + clusterSuggestion.$2, + true, + clusterIDToFiles[clusterSuggestion.$1]!, + clusterIdToFaceIDs[clusterSuggestion.$1]!.toList(), + ), + ); + } + } + try { + await _sortSuggestionsOnDistanceToPerson(null, finalSuggestions); + } catch (e, s) { + _logger.severe("Error in sorting suggestions", e, s); + } + return finalSuggestions; + } catch (e, s) { + _logger.severe("Error in getAllLargePersonSuggestions", e, s); + rethrow; + } + } + Future checkAndDoAutomaticMerges( PersonEntity p, { required String personClusterID, }) async { final faceIDs = await mlDataDB.getFaceIDsForCluster(personClusterID); - final ignoredClusters = await mlDataDB.getPersonIgnoredClusters(p.remoteID); + if (faceIDs.length < 2 * kMinimumClusterSizeSearchResult) { final fileIDs = faceIDs.map(getFileIdFromFaceId).toSet(); if (fileIDs.length < kMinimumClusterSizeSearchResult) { @@ -281,26 +443,10 @@ class ClusterFeedbackService { return false; } } - final allClusterIdsToCountMap = (await mlDataDB.clusterIdToFaceCount()); - _logger.info( - '${kDebugMode ? p.data.name : "private"} has existing clusterID $personClusterID, checking if we can automatically merge more', - ); - - // Get and update the cluster summary to get the avg (centroid) and count - final EnteWatch watch = EnteWatch("ClusterFeedbackService")..start(); - final Map clusterAvg = await _getUpdateClusterAvg( - allClusterIdsToCountMap, - ignoredClusters, - minClusterSize: kMinimumClusterSizeSearchResult, - ); - watch.log('computed avg for ${clusterAvg.length} clusters'); - - // Find the actual closest clusters for the person - final List<(String, double)> suggestions = - await calcSuggestionsMeanInComputer( - clusterAvg, - {personClusterID}, - ignoredClusters, + final List<(String, double, String)> suggestions = + await _getFastSuggestions( + p, + personClusterID, 0.24, ); @@ -350,14 +496,22 @@ class ClusterFeedbackService { personID: person.remoteID, clusterID: clusterID, ); - Bus.instance.fire(PeopleChangedEvent()); + Bus.instance.fire( + PeopleChangedEvent( + type: PeopleEventType.addedClusterToPerson, + source: clusterID, + ), + ); } Future ignoreCluster(String clusterID) async { - await PersonService.instance + final ignoredPerson = await PersonService.instance .addPerson(name: '', clusterID: clusterID, isHidden: true); - Bus.instance.fire(PeopleChangedEvent()); - return; + final mergedAndFired = await checkAndDoAutomaticMerges( + ignoredPerson, + personClusterID: clusterID, + ); + if (!mergedAndFired) Bus.instance.fire(PeopleChangedEvent()); } Future> checkForMixedClusters() async { @@ -548,7 +702,7 @@ class ClusterFeedbackService { w?.log( 'Calculate avg for ${clusterAvgBigClusters.length} clusters of min size $minimumSize', ); - final List<(String, double)> suggestionsMeanBigClusters = + final List<(String, double, String)> suggestionsMeanBigClusters = await calcSuggestionsMeanInComputer( clusterAvgBigClusters, personClusters, @@ -572,7 +726,7 @@ class ClusterFeedbackService { ); continue; } - suggestionsMean.add(suggestion); + suggestionsMean.add((suggestion.$1, suggestion.$2)); } if (suggestionsMean.isNotEmpty) { return suggestionsMean @@ -585,7 +739,7 @@ class ClusterFeedbackService { // Find the other cluster candidates based on the median final clusterAvg = clusterAvgBigClusters; - final List<(String, double)> moreSuggestionsMean = + final List<(String, double, String)> moreSuggestionsMean = await calcSuggestionsMeanInComputer( clusterAvg, personClusters, @@ -702,6 +856,44 @@ class ClusterFeedbackService { return finalSuggestionsMedian; } + /// Returns a list of suggestions. For each suggestion we return a record consisting of the following elements: + /// 1. clusterID: the ID of the cluster + /// 2. distance: the distance between the person's cluster and the suggestion + /// 3. personClusterID: the ID of the person's cluster + Future> _getFastSuggestions( + PersonEntity person, + String clusterID, + double threshold, { + Set? extraIgnoredClusters, + }) async { + final allClusterIdsToCountMap = (await mlDataDB.clusterIdToFaceCount()); + final personignoredClusters = + await mlDataDB.getPersonIgnoredClusters(person.remoteID); + final ignoredClusters = + personignoredClusters.union(extraIgnoredClusters ?? {}); + final startTime = DateTime.now(); + final Map clusterAvg = await _getUpdateClusterAvg( + allClusterIdsToCountMap, + ignoredClusters, + minClusterSize: kMinimumClusterSizeSearchResult, + ); + final avgCalcTime = DateTime.now(); + + // Returns a list of tuples containing the suggestion ID, distance, and personClusterID, respectively + final List<(String, double, String)> foundSuggestions = + await calcSuggestionsMeanInComputer( + clusterAvg, + {clusterID}, + ignoredClusters, + threshold, + ); + final suggestionCalcTime = DateTime.now(); + _logger.info( + "Calculated average vectors in ${avgCalcTime.difference(startTime).inMilliseconds}ms and suggestions in ${suggestionCalcTime.difference(avgCalcTime).inMilliseconds}ms", + ); + return foundSuggestions; + } + Future> _getUpdateClusterAvg( Map allClusterIdsToCountMap, Set ignoredClusters, { @@ -830,12 +1022,13 @@ class ClusterFeedbackService { return clusterAvg; } - Future> calcSuggestionsMeanInComputer( + Future> calcSuggestionsMeanInComputer( Map clusterAvg, Set personClusters, Set ignoredClusters, - double maxClusterDistance, - ) async { + double maxClusterDistance, { + Map>? personClusterToIgnoredClusters, + }) async { return await _computer.compute( _calcSuggestionsMean, param: { @@ -843,6 +1036,7 @@ class ClusterFeedbackService { 'personClusters': personClusters, 'ignoredClusters': ignoredClusters, 'maxClusterDistance': maxClusterDistance, + 'personClusterToIgnoredClusters': personClusterToIgnoredClusters, }, ); } @@ -878,7 +1072,7 @@ class ClusterFeedbackService { } Future _sortSuggestionsOnDistanceToPerson( - PersonEntity person, + PersonEntity? person, List suggestions, { bool onlySortBigSuggestions = true, }) async { @@ -898,44 +1092,14 @@ class ClusterFeedbackService { } } final startTime = DateTime.now(); - - // Get the cluster averages for the person's clusters and the suggestions' clusters - final personClusters = await mlDataDB.getPersonClusterIDs(person.remoteID); - final Map personClusterToSummary = - await mlDataDB.getClusterToClusterSummary(personClusters); - final clusterSummaryCallTime = DateTime.now(); - - // remove personClusters that don't have any summary - for (final clusterID in personClusters.toSet()) { - if (!personClusterToSummary.containsKey(clusterID)) { - _logger.warning('missing summary for $clusterID'); - personClusters.remove(clusterID); - } - } - if (personClusters.isEmpty) { - _logger.warning('No person clusters with summary found'); - return; - } - - // Calculate the avg embedding of the person final w = (kDebugMode ? EnteWatch('sortSuggestions') : null)?..start(); - int personEmbeddingsCount = 0; - for (final clusterID in personClusters) { - personEmbeddingsCount += personClusterToSummary[clusterID]!.$2; - } - Vector personAvg = Vector.filled(192, 0); - for (final personClusterID in personClusters) { - final personClusterBlob = personClusterToSummary[personClusterID]!.$1; - final personClusterAvg = Vector.fromList( - EVector.fromBuffer(personClusterBlob).values, - dtype: DType.float32, - ); - final clusterWeight = - personClusterToSummary[personClusterID]!.$2 / personEmbeddingsCount; - personAvg += personClusterAvg * clusterWeight; + final Map personAverages = {}; + if (person != null) { + final avg = await _getPersonAvg(person.remoteID); + w?.log('getPersonAvg'); + if (avg != null) personAverages[person.remoteID] = avg; } - w?.log('calculated person avg'); // Sort the suggestions based on the distance to the person for (final suggestion in suggestions) { @@ -944,6 +1108,17 @@ class ClusterFeedbackService { continue; } } + // get person average + Vector? personAvg = personAverages[suggestion.person.remoteID]; + if (personAvg == null) { + personAvg = await _getPersonAvg(suggestion.person.remoteID); + if (personAvg != null) { + personAverages[suggestion.person.remoteID] = personAvg; + } else { + continue; + } + } + final clusterID = suggestion.clusterIDToMerge; final faceIDs = suggestion.faceIDsInCluster; final faceIdToEmbeddingMap = await mlDataDB.getFaceEmbeddingMapForFaces( @@ -981,11 +1156,53 @@ class ClusterFeedbackService { } final endTime = DateTime.now(); - _logger.info( - "Sorting suggestions based on distance to person took ${endTime.difference(startTime).inMilliseconds} ms for ${suggestions.length} suggestions, of which ${clusterSummaryCallTime.difference(startTime).inMilliseconds} ms was spent on the cluster summary call", + _logger.fine( + "Sorting suggestions based on distance to person took ${endTime.difference(startTime).inMilliseconds} ms for ${suggestions.length} suggestions", ); } + Future _getPersonAvg(String personID) async { + final w = (kDebugMode ? EnteWatch('_getPersonAvg') : null)?..start(); + // Get the cluster averages for the person's clusters and the suggestions' clusters + final personClusters = await mlDataDB.getPersonClusterIDs(personID); + w?.log('got person clusters'); + final Map personClusterToSummary = + await mlDataDB.getClusterToClusterSummary(personClusters); + w?.log('got cluster summaries'); + + // remove personClusters that don't have any summary + for (final clusterID in personClusters.toSet()) { + if (!personClusterToSummary.containsKey(clusterID)) { + _logger.warning('missing summary for $clusterID'); + personClusters.remove(clusterID); + } + } + if (personClusters.isEmpty) { + _logger.warning('No person clusters with summary found'); + return null; + } + + // Calculate the avg embedding of the person + int personEmbeddingsCount = 0; + for (final clusterID in personClusters) { + personEmbeddingsCount += personClusterToSummary[clusterID]!.$2; + } + + Vector personAvg = Vector.filled(192, 0); + for (final personClusterID in personClusters) { + final personClusterBlob = personClusterToSummary[personClusterID]!.$1; + final personClusterAvg = Vector.fromList( + EVector.fromBuffer(personClusterBlob).values, + dtype: DType.float32, + ); + final clusterWeight = + personClusterToSummary[personClusterID]!.$2 / personEmbeddingsCount; + personAvg += personClusterAvg * clusterWeight; + } + w?.log('calculated person avg'); + return personAvg; + } + Future debugLogClusterBlurValues( String clusterID, { int? clusterSize, @@ -1128,13 +1345,19 @@ class ClusterFeedbackService { } } -/// Returns a map of person's clusterID to map of closest clusterID to with disstance -List<(String, double)> _calcSuggestionsMean(Map args) { +/// Returns a list of suggestions for a cluster in a tuple. The values of the tuple are: +/// 1. The suggested cluster ID +/// 2. The distance between the two clusters +/// 3. The corresponding cluster ID of the person cluster +List<(String, double, String)> _calcSuggestionsMean(Map args) { // Fill in args final Map clusterAvg = args['clusterAvg']; final Set personClusters = args['personClusters']; final Set ignoredClusters = args['ignoredClusters']; final double maxClusterDistance = args['maxClusterDistance']; + final Map>? personClusterToIgnoredClusters = + args['personClusterToIgnoredClusters']; + final bool extraIgnoreCheck = personClusterToIgnoredClusters != null; final Map> suggestions = {}; const suggestionMax = 2000; @@ -1160,6 +1383,12 @@ List<(String, double)> _calcSuggestionsMean(Map args) { dev.log('[WARNING] no avg for personcluster $personCluster'); continue; } + if (extraIgnoreCheck && + personClusterToIgnoredClusters[personCluster] != null && + personClusterToIgnoredClusters[personCluster]! + .contains(otherClusterID)) { + continue; + } final Vector avg = clusterAvg[personCluster]!; final distance = 1 - avg.dot(otherAvg); comparisons++; @@ -1185,9 +1414,14 @@ List<(String, double)> _calcSuggestionsMean(Map args) { ); if (suggestions.isNotEmpty) { - final List<(String, double)> suggestClusterIds = []; - for (final List<(String, double)> suggestion in suggestions.values) { - suggestClusterIds.addAll(suggestion); + final List<(String, double, String)> suggestClusterIds = []; + for (final String personClusterID in suggestions.keys) { + final suggestionss = suggestions[personClusterID]!; + suggestClusterIds.addAll( + suggestionss.map( + (suggestion) => (suggestion.$1, suggestion.$2, personClusterID), + ), + ); } suggestClusterIds.sort( (a, b) => a.$2.compareTo(b.$2), @@ -1199,7 +1433,7 @@ List<(String, double)> _calcSuggestionsMean(Map args) { return suggestClusterIds.sublist(0, min(suggestClusterIds.length, 20)); } else { dev.log("No suggestions found using mean"); - return <(String, double)>[]; + return <(String, double, String)>[]; } } diff --git a/mobile/lib/services/machine_learning/face_ml/person/person_service.dart b/mobile/lib/services/machine_learning/face_ml/person/person_service.dart index d9d2cc7b02..cf8fbc562f 100644 --- a/mobile/lib/services/machine_learning/face_ml/person/person_service.dart +++ b/mobile/lib/services/machine_learning/face_ml/person/person_service.dart @@ -1,21 +1,21 @@ import "dart:convert"; import "dart:developer"; +import "package:computer/computer.dart"; import "package:flutter/foundation.dart"; import "package:logging/logging.dart"; import "package:photos/core/event_bus.dart"; -import "package:photos/db/files_db.dart"; import "package:photos/db/ml/db.dart"; import "package:photos/events/people_changed_event.dart"; import "package:photos/extensions/stop_watch.dart"; import "package:photos/models/api/entity/type.dart"; import "package:photos/models/file/file.dart"; +import "package:photos/models/local_entity_data.dart"; import 'package:photos/models/ml/face/face.dart'; import "package:photos/models/ml/face/person.dart"; import "package:photos/service_locator.dart"; import "package:photos/services/entity_service.dart"; -import "package:photos/services/machine_learning/ml_result.dart"; -import "package:photos/services/search_service.dart"; +import "package:photos/utils/face/face_thumbnail_cache.dart"; import "package:shared_preferences/shared_preferences.dart"; class PersonService { @@ -31,6 +31,9 @@ class PersonService { static const kPersonIDKey = "person_id"; static const kNameKey = "name"; + Future>? _cachedPersonsFuture; + int _lastCacheRefreshTime = 0; + static PersonService get instance { if (_instance == null) { throw Exception("PersonService not initialized"); @@ -48,7 +51,7 @@ class PersonService { SharedPreferences prefs, ) async { _instance = PersonService(entityService, faceMLDataDB, prefs); - await _instance!.resetEmailToPartialPersonDataCache(); + await _instance!.refreshPersonCache(); } Map> get emailToPartialPersonDataMapCache => @@ -56,28 +59,73 @@ class PersonService { void clearCache() { _emailToPartialPersonDataMapCache.clear(); + _cachedPersonsFuture = null; + _lastCacheRefreshTime = 0; } - Future resetEmailToPartialPersonDataCache() async { - _emailToPartialPersonDataMapCache.clear(); - await _instance!.getPersons().then((value) { - for (var person in value) { - if (person.data.email != null && person.data.email!.isNotEmpty) { - _instance!._emailToPartialPersonDataMapCache[person.data.email!] = { - kPersonIDKey: person.remoteID, - kNameKey: person.data.name, - }; - } - } - logger.info("Email to partial person data cache reset"); - }); + Future refreshPersonCache() async { + _lastCacheRefreshTime = 0; + // wait to ensure cache is refreshed + final _ = await getPersons(); + } + + Future> getCertainPersons(List ids) async { + final entities = + await entityService.getCertainEntities(EntityType.cgroup, ids); + return entities + .map( + (e) => PersonEntity( + e.id, + PersonData.fromJson(json.decode(e.data)), + ), + ) + .toList(); + } + + int lastRemoteSyncTime() { + return entityService.lastSyncTime(EntityType.cgroup); } Future> getPersons() async { + if (_lastCacheRefreshTime != lastRemoteSyncTime()) { + _lastCacheRefreshTime = lastRemoteSyncTime(); + _cachedPersonsFuture = null; // Invalidate cache + } + _cachedPersonsFuture ??= _fetchAndCachePersons(); + return _cachedPersonsFuture!; + } + + Future> _fetchAndCachePersons() async { + logger.finest("reading all persons from local db"); final entities = await entityService.getEntities(EntityType.cgroup); + final persons = await Computer.shared().compute( + _decodePersonEntities, + param: {"entity": entities}, + taskName: "decode_person_entities", + ); + _emailToPartialPersonDataMapCache.clear(); + for (PersonEntity person in persons) { + if (person.data.email != null && person.data.email!.isNotEmpty) { + _emailToPartialPersonDataMapCache[person.data.email!] = { + kPersonIDKey: person.remoteID, + kNameKey: person.data.name, + }; + } + } + + return persons; + } + + static List _decodePersonEntities( + Map param, + ) { + final entities = param["entity"] as List; return entities .map( - (e) => PersonEntity(e.id, PersonData.fromJson(json.decode(e.data))), + (e) => PersonEntity( + e.id, + PersonData.fromJson(json.decode(e.data)), + ), ) .toList(); } @@ -87,16 +135,17 @@ class PersonService { if (e == null) { return null; } - return PersonEntity(e.id, PersonData.fromJson(json.decode(e.data))); + return PersonEntity( + e.id, + PersonData.fromJson(json.decode(e.data)), + ); }); } Future> getPersonsMap() async { - final entities = await entityService.getEntities(EntityType.cgroup); + final persons = await getPersons(); final Map map = {}; - for (var e in entities) { - final person = - PersonEntity(e.id, PersonData.fromJson(json.decode(e.data))); + for (var person in persons) { map[person.remoteID] = person; } return map; @@ -131,8 +180,7 @@ class PersonService { ), ) .toList(); - entityService - .addOrUpdate(EntityType.cgroup, personData.toJson(), id: personID) + _addOrUpdateEntity(EntityType.cgroup, personData.toJson(), id: personID) .ignore(); personData.logStats(); } @@ -201,7 +249,7 @@ class PersonService { birthDate: birthdate, email: email, ); - final result = await entityService.addOrUpdate( + final result = await _addOrUpdateEntity( EntityType.cgroup, data.toJson(), ); @@ -210,7 +258,7 @@ class PersonService { clusterID: clusterID, ); if (data.email != null) { - await resetEmailToPartialPersonDataCache(); + await refreshPersonCache(); } memoriesCacheService.queueUpdateCache(); return PersonEntity(result.id, data); @@ -235,7 +283,7 @@ class PersonService { } personData.rejectedFaceIDs.addAll(clusterInfo.faces); personData.assigned.removeWhere((element) => element.id == clusterID); - await entityService.addOrUpdate( + await _addOrUpdateEntity( EntityType.cgroup, personData.toJson(), id: personID, @@ -247,7 +295,7 @@ class PersonService { personData.logStats(); } - Future removeFilesFromPerson({ + Future removeFacesFromPerson({ required PersonEntity person, required Set faceIDs, }) async { @@ -275,7 +323,7 @@ class PersonService { // Add removed faces to rejected faces personData.rejectedFaceIDs.addAll(faceIDs); - await entityService.addOrUpdate( + await _addOrUpdateEntity( EntityType.cgroup, personData.toJson(), id: person.remoteID, @@ -291,7 +339,7 @@ class PersonService { } final PersonEntity justName = PersonEntity(personID, PersonData(name: entity.data.name)); - await entityService.addOrUpdate( + await _addOrUpdateEntity( EntityType.cgroup, justName.data.toJson(), id: personID, @@ -300,7 +348,7 @@ class PersonService { justName.data.logStats(); if (entity.data.email != null) { - await resetEmailToPartialPersonDataCache(); + await refreshPersonCache(); } } else { await entityService.deleteEntry(personID); @@ -308,7 +356,7 @@ class PersonService { if (entity != null) { if (entity.data.email != null) { - await resetEmailToPartialPersonDataCache(); + await refreshPersonCache(); } } } @@ -382,8 +430,15 @@ class PersonService { for (var e in entities) { final personData = PersonData.fromJson(json.decode(e.data)); if (personData.rejectedFaceIDs.isNotEmpty) { + final personClustersToFaceIDs = dbPeopleClusterInfo[e.id]; + if (personClustersToFaceIDs == null) { + logger.warning( + "Person ${e.id} ${personData.name} has rejected faces but no clusters found in local DB", + ); + continue; + } final personFaceIDs = - dbPeopleClusterInfo[e.id]!.values.expand((e) => e).toSet(); + personClustersToFaceIDs.values.expand((e) => e).toSet(); final rejectedFaceIDsSet = personData.rejectedFaceIDs.toSet(); final assignedAndRejectedFaceIDs = rejectedFaceIDsSet.intersection(personFaceIDs); @@ -445,6 +500,7 @@ class PersonService { data: person.data.copyWith(avatarFaceId: face.faceID), ); await updatePerson(updatedPerson); + await putFaceIdCachedForPersonOrCluster(p.remoteID, face.faceID); return updatedPerson; } @@ -469,13 +525,13 @@ class PersonService { ), ); await updatePerson(updatedPerson); - await resetEmailToPartialPersonDataCache(); + await refreshPersonCache(); return updatedPerson; } Future updatePerson(PersonEntity updatePerson) async { try { - await entityService.addOrUpdate( + await _addOrUpdateEntity( EntityType.cgroup, updatePerson.data.toJson(), id: updatePerson.remoteID, @@ -487,48 +543,14 @@ class PersonService { } } - Future getThumbnailFileOfPerson( - PersonEntity person, - ) async { - try { - if (person.data.hasAvatar()) { - final avatarFileID = tryGetFileIdFromFaceId(person.data.avatarFaceID!); - if (avatarFileID != null) { - final file = (await FilesDB.instance - .getFileIDToFileFromIDs([avatarFileID]))[avatarFileID]; - if (file != null) { - return file; - } else { - logger.severe("Avatar File not found for face ${person.data}"); - } - } - } - - final clustersToFiles = - await SearchService.instance.getClusterFilesForPersonID( - person.remoteID, - ); - - EnteFile? resultFile; - // iterate over all clusters and get the first file - for (final clusterFiles in clustersToFiles.values) { - for (final file in clusterFiles) { - resultFile ??= file; - if (resultFile.creationTime! < file.creationTime!) { - resultFile = file; - } - } - } - if (resultFile == null) { - logger.warning( - "Person ${kDebugMode ? person.data.name : person.remoteID} has no files", - ); - return null; - } - return resultFile; - } catch (e, s) { - logger.severe("Error in getThumbnailFileOfPerson", e, s); - return null; - } + /// Wrapper method for entityService.addOrUpdate that handles cache refresh + Future _addOrUpdateEntity( + EntityType type, + Map jsonMap, { + String? id, + }) async { + final result = await entityService.addOrUpdate(type, jsonMap, id: id); + _lastCacheRefreshTime = 0; // Invalidate cache + return result; } } diff --git a/mobile/lib/services/machine_learning/face_thumbnail_generator.dart b/mobile/lib/services/machine_learning/face_thumbnail_generator.dart index d98fe63793..4980f2e904 100644 --- a/mobile/lib/services/machine_learning/face_thumbnail_generator.dart +++ b/mobile/lib/services/machine_learning/face_thumbnail_generator.dart @@ -1,12 +1,15 @@ import 'dart:async'; import 'dart:typed_data' show Uint8List; +import "package:computer/computer.dart"; import "package:logging/logging.dart"; import "package:photos/models/ml/face/box.dart"; import "package:photos/services/isolate_functions.dart"; import "package:photos/services/isolate_service.dart"; import "package:photos/utils/image_ml_util.dart"; +final Computer _computer = Computer.shared(); + class FaceThumbnailGenerator extends SuperIsolate { @override Logger get logger => _logger; @@ -36,12 +39,18 @@ class FaceThumbnailGenerator extends SuperIsolate { ) async { final List> faceBoxesJson = faceBoxes.map((box) => box.toJson()).toList(); - return await runInIsolate( + final List faces = await runInIsolate( IsolateOperation.generateFaceThumbnails, { 'imagePath': imagePath, 'faceBoxesList': faceBoxesJson, }, ).then((value) => value.cast()); + final compressedFaces = + await compressFaceThumbnails({'listPngBytes': faces}); + _logger.fine( + "Compressed face thumbnails from sizes ${faces.map((e) => e.length / 1024).toList()} to ${compressedFaces.map((e) => e.length / 1024).toList()} kilobytes", + ); + return compressedFaces; } } diff --git a/mobile/lib/services/machine_learning/machine_learning_controller.dart b/mobile/lib/services/machine_learning/machine_learning_controller.dart deleted file mode 100644 index 43b24dc9a5..0000000000 --- a/mobile/lib/services/machine_learning/machine_learning_controller.dart +++ /dev/null @@ -1,131 +0,0 @@ -import "dart:async"; -import "dart:io"; - -import "package:battery_info/battery_info_plugin.dart"; -import "package:battery_info/model/android_battery_info.dart"; -import "package:battery_info/model/iso_battery_info.dart"; -import "package:flutter/foundation.dart"; -import "package:logging/logging.dart"; -import "package:photos/core/event_bus.dart"; -import "package:photos/events/machine_learning_control_event.dart"; - -class MachineLearningController { - final _logger = Logger("MachineLearningController"); - - static const kMaximumTemperature = 42; // 42 degree celsius - static const kMinimumBatteryLevel = 20; // 20% - final kDefaultInteractionTimeout = Duration(seconds: Platform.isIOS ? 5 : 15); - static const kUnhealthyStates = ["over_heat", "over_voltage", "dead"]; - - bool _isDeviceHealthy = true; - bool _isUserInteracting = true; - bool _canRunML = false; - bool mlInteractionOverride = false; - late Timer _userInteractionTimer; - - bool get isDeviceHealthy => _isDeviceHealthy; - - MachineLearningController() { - _logger.info('MachineLearningController constructor'); - _startInteractionTimer(kDefaultInteractionTimeout); - if (Platform.isIOS) { - if (kDebugMode) { - _logger.info( - "iOS battery info stream is not available in simulator, disabling in debug mode", - ); - // if you need to test on physical device, uncomment this check - return; - } - BatteryInfoPlugin() - .iosBatteryInfoStream - .listen((IosBatteryInfo? batteryInfo) { - _oniOSBatteryStateUpdate(batteryInfo); - }); - } - if (Platform.isAndroid) { - BatteryInfoPlugin() - .androidBatteryInfoStream - .listen((AndroidBatteryInfo? batteryInfo) { - _onAndroidBatteryStateUpdate(batteryInfo); - }); - } - _logger.info('init done '); - } - - void onUserInteraction() { - if (!_isUserInteracting) { - _logger.info("User is interacting with the app"); - _isUserInteracting = true; - _fireControlEvent(); - } - _resetTimer(); - } - - bool _canRunGivenUserInteraction() { - return !_isUserInteracting || mlInteractionOverride; - } - - void forceOverrideML({required bool turnOn}) { - _logger.info("Forcing to turn on ML: $turnOn"); - mlInteractionOverride = turnOn; - _fireControlEvent(); - } - - void _fireControlEvent() { - final shouldRunML = _isDeviceHealthy && _canRunGivenUserInteraction(); - if (shouldRunML != _canRunML) { - _canRunML = shouldRunML; - _logger.info( - "Firing event: $shouldRunML (device health: $_isDeviceHealthy, user interaction: $_isUserInteracting, mlInteractionOverride: $mlInteractionOverride)", - ); - Bus.instance.fire(MachineLearningControlEvent(shouldRunML)); - } - } - - void _startInteractionTimer(Duration timeout) { - _userInteractionTimer = Timer(timeout, () { - _logger.info("User is not interacting with the app"); - _isUserInteracting = false; - _fireControlEvent(); - }); - } - - void _resetTimer() { - _userInteractionTimer.cancel(); - _startInteractionTimer(kDefaultInteractionTimeout); - } - - void _onAndroidBatteryStateUpdate(AndroidBatteryInfo? batteryInfo) { - _logger.info("Battery info: ${batteryInfo!.toJson()}"); - _isDeviceHealthy = _computeIsAndroidDeviceHealthy(batteryInfo); - _fireControlEvent(); - } - - void _oniOSBatteryStateUpdate(IosBatteryInfo? batteryInfo) { - _logger.info("Battery info: ${batteryInfo!.toJson()}"); - _isDeviceHealthy = _computeIsiOSDeviceHealthy(batteryInfo); - _fireControlEvent(); - } - - bool _computeIsAndroidDeviceHealthy(AndroidBatteryInfo info) { - return _hasSufficientBattery(info.batteryLevel ?? kMinimumBatteryLevel) && - _isAcceptableTemperature(info.temperature ?? kMaximumTemperature) && - _isBatteryHealthy(info.health ?? ""); - } - - bool _computeIsiOSDeviceHealthy(IosBatteryInfo info) { - return _hasSufficientBattery(info.batteryLevel ?? kMinimumBatteryLevel); - } - - bool _hasSufficientBattery(int batteryLevel) { - return batteryLevel >= kMinimumBatteryLevel; - } - - bool _isAcceptableTemperature(int temperature) { - return temperature <= kMaximumTemperature; - } - - bool _isBatteryHealthy(String health) { - return !kUnhealthyStates.contains(health); - } -} diff --git a/mobile/lib/services/machine_learning/ml_indexing_isolate.dart b/mobile/lib/services/machine_learning/ml_indexing_isolate.dart index a9553b3fa7..e66848bb27 100644 --- a/mobile/lib/services/machine_learning/ml_indexing_isolate.dart +++ b/mobile/lib/services/machine_learning/ml_indexing_isolate.dart @@ -106,12 +106,11 @@ class MLIndexingIsolate extends SuperIsolate { Future ensureDownloadedModels([bool forceRefresh = false]) async { if (_downloadModelLock.locked) { - _logger.finest("Download models already in progress"); + _logger.info("Download models already in progress"); return; } return _downloadModelLock.synchronized(() async { if (areModelsDownloaded) { - _logger.finest("Models already downloaded"); return; } final goodInternet = await canUseHighBandwidth(); @@ -128,6 +127,7 @@ class MLIndexingIsolate extends SuperIsolate { ClipImageEncoder.instance.downloadModel(forceRefresh), ]); areModelsDownloaded = true; + _logger.info('Downloaded models'); }); } diff --git a/mobile/lib/services/machine_learning/ml_result.dart b/mobile/lib/services/machine_learning/ml_result.dart index e38b20097a..920cf1b83b 100644 --- a/mobile/lib/services/machine_learning/ml_result.dart +++ b/mobile/lib/services/machine_learning/ml_result.dart @@ -148,11 +148,18 @@ class FaceResult { T getFileIdFromFaceId(String faceId) { final String faceIdSplit = faceId.substring(0, faceId.indexOf('_')); - if (T == int) { - return int.parse(faceIdSplit) as T; - } - if (T == String) { - return faceIdSplit as T; + try { + if (T == int) { + return int.parse(faceIdSplit) as T; + } + if (T == String) { + return faceIdSplit as T; + } + } catch (e) { + Logger("FaceID").severe( + "Error parsing faceId: $faceId with type $T", + e, + ); } throw ArgumentError("Unsupported type: $T"); } diff --git a/mobile/lib/services/machine_learning/ml_service.dart b/mobile/lib/services/machine_learning/ml_service.dart index 0b4fa4ad0b..166421ba08 100644 --- a/mobile/lib/services/machine_learning/ml_service.dart +++ b/mobile/lib/services/machine_learning/ml_service.dart @@ -8,12 +8,11 @@ import "package:logging/logging.dart"; import "package:photos/core/event_bus.dart"; import "package:photos/db/files_db.dart"; import "package:photos/db/ml/db.dart"; -import "package:photos/events/machine_learning_control_event.dart"; +import "package:photos/events/compute_control_event.dart"; import "package:photos/events/people_changed_event.dart"; import "package:photos/models/ml/face/face.dart"; import "package:photos/models/ml/ml_versions.dart"; import "package:photos/service_locator.dart"; -import "package:photos/services/filedata/filedata_service.dart"; import "package:photos/services/filedata/model/file_data.dart"; import 'package:photos/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart'; import "package:photos/services/machine_learning/face_ml/face_clustering/face_db_info_for_clustering.dart"; @@ -21,6 +20,7 @@ import "package:photos/services/machine_learning/face_ml/person/person_service.d import "package:photos/services/machine_learning/ml_indexing_isolate.dart"; import 'package:photos/services/machine_learning/ml_result.dart'; import "package:photos/services/machine_learning/semantic_search/semantic_search_service.dart"; +import "package:photos/services/video_preview_service.dart"; import "package:photos/utils/ml_util.dart"; import "package:photos/utils/network_util.dart"; import "package:photos/utils/ram_check_util.dart"; @@ -40,8 +40,6 @@ class MLService { late String client; - bool get isInitialized => _isInitialized; - bool get showClusteringIsHappening => _clusteringIsHappening; bool debugIndexingDisabled = false; @@ -60,9 +58,6 @@ class MLService { /// Only call this function once at app startup, after that you can directly call [runAllML] Future init() async { if (_isInitialized) return; - if (!flagService.hasGrantedMLConsent) { - return; - } _logger.info("init called"); // Check if the device has enough RAM to run local indexing @@ -73,8 +68,8 @@ class MLService { client = "${packageInfo.packageName}/${packageInfo.version}"; _logger.info("client: $client"); - // Listen on MachineLearningController - Bus.instance.on().listen((event) { + // Listen on ComputeController + Bus.instance.on().listen((event) { if (!flagService.hasGrantedMLConsent) { return; } @@ -119,7 +114,7 @@ class MLService { } Future sync() async { - await FileDataService.instance.syncFDStatus(); + await fileDataService.syncFDStatus(); await faceRecognitionService.syncPersonFeedback(); } @@ -129,6 +124,7 @@ class MLService { _mlControllerStatus = true; } if (!_canRunMLFunction(function: "AllML") && !force) return; + if (!force && !computeController.requestCompute(ml: true)) return; _isRunningML = true; await sync(); @@ -163,6 +159,8 @@ class MLService { rethrow; } finally { _isRunningML = false; + computeController.releaseCompute(ml: true); + VideoPreviewService.instance.queueFiles(); } } @@ -497,11 +495,10 @@ class MLService { ); } // Storing results on remote - await FileDataService.instance.putFileData( + await fileDataService.putFileData( instruction.file, dataEntity, ); - _logger.info("ML results for fileID ${result.fileId} stored on remote"); // Storing results locally if (result.facesRan) await mlDataDB.bulkInsertFaces(faces); if (result.clipRan) { @@ -509,7 +506,7 @@ class MLService { result.clip!, ); } - _logger.info("ML results for fileID ${result.fileId} stored locally"); + _logger.info("ML result for fileID ${result.fileId} stored remote+local"); return actuallyRanML; } catch (e, s) { final String errorString = e.toString(); diff --git a/mobile/lib/services/magic_cache_service.dart b/mobile/lib/services/magic_cache_service.dart index 462cb851fd..fc517cc150 100644 --- a/mobile/lib/services/magic_cache_service.dart +++ b/mobile/lib/services/magic_cache_service.dart @@ -24,6 +24,7 @@ import "package:photos/services/machine_learning/semantic_search/semantic_search import "package:photos/services/remote_assets_service.dart"; import "package:photos/services/search_service.dart"; import "package:photos/ui/viewer/search/result/magic_result_screen.dart"; +import "package:photos/utils/cache_util.dart"; import "package:photos/utils/file_util.dart"; import "package:photos/utils/navigation_util.dart"; import "package:shared_preferences/shared_preferences.dart"; @@ -182,7 +183,7 @@ class MagicCacheService { bool _isUpdateInProgress = false; MagicCacheService(this._prefs) { - _logger.fine("MagicCacheService constructor"); + _logger.info("MagicCacheService constructor"); Bus.instance.on().listen((event) { queueUpdate("File uploaded"); }); @@ -251,13 +252,12 @@ class MagicCacheService { final List magicCaches = await _nonEmptyMagicResults(magicPromptsData); w?.log("resultComputed"); - final file = File(await _getCachePath()); - if (!file.existsSync()) { - file.createSync(recursive: true); - } _magicCacheFuture = Future.value(magicCaches); - await file - .writeAsBytes(MagicCache.encodeListToJson(magicCaches).codeUnits); + await writeToJsonFile>( + await _getCachePath(), + magicCaches, + MagicCache.encodeListToJson, + ); w?.log("cacheWritten"); await _resetLastMagicCacheUpdateTime(); w?.logAndReset('done'); @@ -300,20 +300,11 @@ class MagicCacheService { Future> _readResultFromDisk() async { _logger.info("Reading magic cache result from disk"); - final file = File(await _getCachePath()); - if (!file.existsSync()) { - _logger.info("No magic cache found"); - return []; - } - try { - final bytes = await file.readAsBytes(); - final jsonString = String.fromCharCodes(bytes); - return MagicCache.decodeJsonToList(jsonString); - } catch (e, s) { - _logger.severe("Error reading or decoding cache file", e, s); - await file.delete(); - rethrow; - } + final cache = await decodeJsonFile>( + await _getCachePath(), + MagicCache.decodeJsonToList, + ); + return cache ?? []; } Future clearMagicCache() async { diff --git a/mobile/lib/services/memories_cache_service.dart b/mobile/lib/services/memories_cache_service.dart index 971222a880..51ea8710bb 100644 --- a/mobile/lib/services/memories_cache_service.dart +++ b/mobile/lib/services/memories_cache_service.dart @@ -1,11 +1,13 @@ import "dart:async"; import "dart:io" show File; +import "package:flutter/cupertino.dart"; import "package:flutter/foundation.dart" show kDebugMode; import "package:flutter/material.dart" show BuildContext; import "package:logging/logging.dart"; import "package:path_provider/path_provider.dart"; import "package:photos/core/event_bus.dart"; +import "package:photos/db/files_db.dart"; import "package:photos/db/memories_db.dart"; import "package:photos/events/files_updated_event.dart"; import "package:photos/events/memories_changed_event.dart"; @@ -15,13 +17,19 @@ import "package:photos/extensions/stop_watch.dart"; import "package:photos/models/file/file.dart"; import "package:photos/models/memories/memories_cache.dart"; import "package:photos/models/memories/memory.dart"; +import "package:photos/models/memories/people_memory.dart"; import "package:photos/models/memories/smart_memory.dart"; import "package:photos/models/memories/smart_memory_constants.dart"; import "package:photos/service_locator.dart"; import "package:photos/services/language_service.dart"; +import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; import "package:photos/services/notification_service.dart"; import "package:photos/services/search_service.dart"; +import "package:photos/theme/colors.dart"; +import "package:photos/ui/home/memories/all_memories_page.dart"; import "package:photos/ui/home/memories/full_screen_memory.dart"; +import "package:photos/ui/viewer/people/people_page.dart"; +import "package:photos/utils/cache_util.dart"; import "package:photos/utils/navigation_util.dart"; import "package:shared_preferences/shared_preferences.dart"; import "package:synchronized/synchronized.dart"; @@ -36,7 +44,7 @@ class MemoriesCacheService { static const _kCacheUpdateDelay = Duration(seconds: 5); final SharedPreferences _prefs; - late final Logger _logger = Logger("MemoriesCacheService"); + static final Logger _logger = Logger("MemoriesCacheService"); final _memoriesDB = MemoriesDB.instance; @@ -47,9 +55,10 @@ class MemoriesCacheService { bool get isUpdatingMemories => _isUpdatingMemories; final _memoriesUpdateLock = Lock(); + final _memoriesGetLock = Lock(); MemoriesCacheService(this._prefs) { - _logger.fine("MemoriesCacheService constructor"); + _logger.info("MemoriesCacheService constructor"); Future.delayed(_kCacheUpdateDelay, () { _checkIfTimeToUpdateCache(); @@ -75,13 +84,6 @@ class MemoriesCacheService { }); } - Future _resetLastMemoriesCacheUpdateTime() async { - await _prefs.setInt( - _lastMemoriesCacheUpdateTimeKey, - DateTime.now().microsecondsSinceEpoch, - ); - } - int get lastMemoriesCacheUpdateTime { return _prefs.getInt(_lastMemoriesCacheUpdateTimeKey) ?? 0; } @@ -95,17 +97,6 @@ class MemoriesCacheService { Bus.instance.fire(MemoriesSettingChanged()); } - Future toggleOnThisDayNotifications() async { - final oldValue = localSettings.isOnThisDayNotificationsEnabled; - await localSettings.setOnThisDayNotificationsEnabled(!oldValue); - _logger.info("Turning onThisDayNotifications ${oldValue ? "off" : "on"}"); - if (oldValue) { - await _clearAllScheduledOnThisDayNotifications(); - } else { - queueUpdateCache(); - } - } - bool get enableSmartMemories => flagService.hasGrantedMLConsent && localSettings.isMLLocalIndexingEnabled && @@ -133,11 +124,6 @@ class MemoriesCacheService { .microsecondsSinceEpoch; } - Future _getCachePath() async { - return (await getApplicationSupportDirectory()).path + - "/cache/memories_cache"; - } - Future markMemoryAsSeen(Memory memory, bool lastInList) async { memory.markSeen(); await _memoriesDB.markMemoryAsSeen( @@ -162,11 +148,125 @@ class MemoriesCacheService { unawaited(_prefs.setBool(_shouldUpdateCacheKey, true)); } - Future _cacheUpdated() async { - _shouldUpdate = false; - unawaited(_prefs.setBool(_shouldUpdateCacheKey, false)); - await _resetLastMemoriesCacheUpdateTime(); - Bus.instance.fire(MemoriesChangedEvent()); + Future> getMemories({bool onlyUseCache = false}) async { + _logger.info("getMemories called"); + if (!showAnyMemories) { + _logger.info('Showing memories is disabled in settings, showing none'); + return []; + } + return _memoriesGetLock.synchronized(() async { + if (_cachedMemories != null && _cachedMemories!.isNotEmpty) { + _logger.info("Found memories in memory cache"); + return _cachedMemories!; + } else if (onlyUseCache) { + _logger.info("Only using cache, no memories found"); + return []; + } + try { + if (!enableSmartMemories) { + await _calculateRegularFillers(); + return _cachedMemories!; + } + _cachedMemories = await _getMemoriesFromCache(); + if (_cachedMemories == null || _cachedMemories!.isEmpty) { + _logger.warning( + "No memories found in cache, force updating cache. Possible severe caching issue", + ); + await updateCache(forced: true); + } else { + _logger.info("Found memories in cache"); + } + if (_cachedMemories == null || _cachedMemories!.isEmpty) { + _logger + .severe("No memories found in (computed) cache, getting fillers"); + await _calculateRegularFillers(); + } + return _cachedMemories!; + } catch (e, s) { + _logger.severe("Error in getMemories", e, s); + return []; + } + }); + } + + Future _calculateRegularFillers() async { + if (_cachedMemories == null) { + _cachedMemories = await smartMemoriesService.calcSimpleMemories(); + Bus.instance.fire(MemoriesChangedEvent()); + } + return; + } + + Future?> _getMemoriesFromCache() async { + final cache = await _readCacheFromDisk(); + if (cache == null) { + return null; + } + final result = await fromCacheToMemories(cache); + return result; + } + + Future _readCacheFromDisk() async { + _logger.info("Reading memories cache result from disk"); + final cache = decodeJsonFile( + await _getCachePath(), + MemoriesCache.decodeFromJsonString, + ); + return cache; + } + + static Future> fromCacheToMemories( + MemoriesCache cache, + ) async { + try { + _logger.info('Processing disk cache memories to smart memories'); + final List memories = []; + final seenTimes = await MemoriesDB.instance.getSeenTimes(); + final minimalFileIDs = {}; + for (final ToShowMemory memory in cache.toShowMemories) { + if (memory.shouldShowNow()) { + minimalFileIDs.addAll(memory.fileUploadedIDs); + } + } + final minimalFiles = await FilesDB.instance.getFilesFromIDs( + minimalFileIDs.toList(), + collectionsToIgnore: SearchService.instance.ignoreCollections(), + ); + final minimalFileIdsToFile = {}; + for (final file in minimalFiles) { + if (file.uploadedFileID != null) { + minimalFileIdsToFile[file.uploadedFileID!] = file; + } + } + + for (final ToShowMemory memory in cache.toShowMemories) { + if (memory.shouldShowNow()) { + final smartMemory = SmartMemory( + memory.fileUploadedIDs + .where((fileID) => minimalFileIdsToFile.containsKey(fileID)) + .map( + (fileID) => + Memory.fromFile(minimalFileIdsToFile[fileID]!, seenTimes), + ) + .toList(), + memory.type, + memory.title, + memory.firstTimeToShow, + memory.lastTimeToShow, + id: memory.id, + ); + if (smartMemory.memories.isNotEmpty) { + memories.add(smartMemory); + } + } + } + locationService.baseLocations = cache.baseLocations; + _logger.info('Processing of disk cache memories done'); + return memories; + } catch (e, s) { + _logger.severe("Error converting cache to memories", e, s); + return []; + } } Future updateCache({bool forced = false}) async { @@ -223,19 +323,17 @@ class MemoriesCacheService { } newCache.baseLocations.addAll(nowResult.baseLocations); w?.log("added memories to cache"); - final file = File(await _getCachePath()); - if (!file.existsSync()) { - file.createSync(recursive: true); - } _cachedMemories = nowResult.memories .where((memory) => memory.shouldShowNow()) .toList(); - await _scheduleOnThisDayNotifications( + await _scheduleMemoryNotifications( [...nowResult.memories, ...nextResult.memories], ); locationService.baseLocations = nowResult.baseLocations; - await file.writeAsBytes( - MemoriesCache.encodeToJsonString(newCache).codeUnits, + await writeToJsonFile( + await _getCachePath(), + newCache, + MemoriesCache.encodeToJsonString, ); w?.log("cacheWritten"); await _cacheUpdated(); @@ -248,6 +346,21 @@ class MemoriesCacheService { }); } + Future _getCachePath() async { + return (await getApplicationSupportDirectory()).path + + "/cache/memories_cache"; + } + + Future _cacheUpdated() async { + _shouldUpdate = false; + unawaited(_prefs.setBool(_shouldUpdateCacheKey, false)); + await _prefs.setInt( + _lastMemoriesCacheUpdateTimeKey, + DateTime.now().microsecondsSinceEpoch, + ); + Bus.instance.fire(MemoriesChangedEvent()); + } + /// WARNING: Use for testing only, TODO: lau: remove later Future debugCacheForTesting() async { final oldCache = await _readCacheFromDisk(); @@ -255,65 +368,6 @@ class MemoriesCacheService { return newCache; } - Future _clearAllScheduledOnThisDayNotifications() async { - _logger.info('Clearing all scheduled On This Day notifications'); - await NotificationService.instance - .clearAllScheduledNotifications(containingPayload: "onThisDay"); - } - - Future _scheduleOnThisDayNotifications( - List allMemories, - ) async { - if (!localSettings.isOnThisDayNotificationsEnabled) { - _logger - .info("On this day notifications are disabled, skipping scheduling"); - return; - } - await _clearAllScheduledOnThisDayNotifications(); - final scheduledDates = {}; - for (final memory in allMemories) { - if (memory.type != MemoryType.onThisDay) { - continue; - } - final numberOfMemories = memory.memories.length; - if (numberOfMemories < 5) continue; - final firstDateToShow = - DateTime.fromMicrosecondsSinceEpoch(memory.firstDateToShow); - final scheduleTime = DateTime( - firstDateToShow.year, - firstDateToShow.month, - firstDateToShow.day, - 8, - ); - if (scheduleTime.isBefore(DateTime.now())) { - _logger.info( - "Skipping scheduling notification for memory ${memory.id} because the date is in the past (date: $scheduleTime)", - ); - continue; - } - if (scheduledDates.contains(scheduleTime)) { - _logger.info( - "Skipping scheduling notification for memory ${memory.id} because the date is already scheduled (date: $scheduleTime)", - ); - continue; - } - final s = await LanguageService.s; - await NotificationService.instance.scheduleNotification( - s.onThisDay, - s.lookBackOnYourMemories, - id: memory.id.hashCode, - channelID: "onThisDay", - channelName: s.onThisDay, - payload: memory.id, - dateTime: scheduleTime, - ); - scheduledDates.add(scheduleTime); - _logger.info( - "Scheduled notification for memory ${memory.id} on $scheduleTime", - ); - } - } - MemoriesCache _processOldCache(MemoriesCache? oldCache) { final List peopleShownLogs = []; final List clipShownLogs = []; @@ -365,72 +419,21 @@ class MemoriesCacheService { ); } - Future> _fromCacheToMemories(MemoriesCache cache) async { - try { - _logger.info('Processing disk cache memories to smart memories'); - final List memories = []; - final allFiles = Set.from( - await SearchService.instance.getAllFilesForSearch(), - ); - final allFileIdsToFile = {}; - for (final file in allFiles) { - if (file.uploadedFileID != null) { - allFileIdsToFile[file.uploadedFileID!] = file; - } + Future clearMemoriesCache({bool fromDisk = true}) async { + if (fromDisk) { + final file = File(await _getCachePath()); + if (file.existsSync()) { + await file.delete(); } - final seenTimes = await _memoriesDB.getSeenTimes(); - - for (final ToShowMemory memory in cache.toShowMemories) { - if (memory.shouldShowNow()) { - final smartMemory = SmartMemory( - memory.fileUploadedIDs - .where((fileID) => allFileIdsToFile.containsKey(fileID)) - .map( - (fileID) => - Memory.fromFile(allFileIdsToFile[fileID]!, seenTimes), - ) - .toList(), - memory.type, - memory.title, - memory.firstTimeToShow, - memory.lastTimeToShow, - id: memory.id, - ); - if (smartMemory.memories.isNotEmpty) { - memories.add(smartMemory); - } - } - } - locationService.baseLocations = cache.baseLocations; - _logger.info('Processing of disk cache memories done'); - return memories; - } catch (e, s) { - _logger.severe("Error converting cache to memories", e, s); - return []; } - } - - Future?> _getMemoriesFromCache() async { - final cache = await _readCacheFromDisk(); - if (cache == null) { - return null; - } - final result = await _fromCacheToMemories(cache); - return result; - } - - Future _calculateRegularFillers() async { - if (_cachedMemories == null) { - _cachedMemories = await smartMemoriesService.calcSimpleMemories(); - Bus.instance.fire(MemoriesChangedEvent()); - } - return; + _cachedMemories = null; } Future> getMemoriesForWidget({ required bool onThisDay, required bool pastYears, required bool smart, + required bool hasAnyWidgets, }) async { if (!onThisDay && !pastYears && !smart) { _logger.info( @@ -438,7 +441,7 @@ class MemoriesCacheService { ); return []; } - final allMemories = await getMemories(); + final allMemories = await getMemories(onlyUseCache: !hasAnyWidgets); if (onThisDay && pastYears && smart) { return allMemories; } @@ -457,44 +460,6 @@ class MemoriesCacheService { return filteredMemories; } - Future> getMemories() async { - if (!showAnyMemories) { - _logger.info('Showing memories is disabled in settings, showing none'); - return []; - } - if (_cachedMemories != null && _cachedMemories!.isNotEmpty) { - return _cachedMemories!; - } - try { - if (!enableSmartMemories) { - await _calculateRegularFillers(); - return _cachedMemories!; - } - _cachedMemories = await _getMemoriesFromCache(); - if (_cachedMemories == null || _cachedMemories!.isEmpty) { - _logger.warning( - "No memories found in cache, force updating cache. Possible severe caching issue", - ); - await updateCache(forced: true); - } else { - _logger.info("Found memories in cache"); - } - if (_cachedMemories == null || _cachedMemories!.isEmpty) { - _logger - .severe("No memories found in (computed) cache, getting fillers"); - await _calculateRegularFillers(); - } - return _cachedMemories!; - } catch (e, s) { - _logger.severe("Error in getMemories", e, s); - return []; - } - } - - Future?> getCachedMemories() async { - return _cachedMemories; - } - Future goToMemoryFromGeneratedFileID( BuildContext context, int generatedFileID, @@ -524,10 +489,12 @@ class MemoriesCacheService { } await routeToPage( context, - FullScreenMemoryDataUpdater( - initialIndex: fileIdx, - memories: allMemories[memoryIdx].memories, - child: FullScreenMemory(allMemories[memoryIdx].title, fileIdx), + AllMemoriesPage( + allMemories: _cachedMemories!.map((e) => e.memories).toList(), + allTitles: _cachedMemories!.map((e) => e.title).toList(), + initialPageIndex: memoryIdx, + inititalFileIndex: fileIdx, + isFromWidgetOrNotifications: true, ), forceCustomPageRoute: true, ); @@ -554,52 +521,251 @@ class MemoriesCacheService { } await routeToPage( context, - FullScreenMemoryDataUpdater( - initialIndex: 0, - memories: allMemories[memoryIdx].memories, - child: FullScreenMemory(allMemories[memoryIdx].title, 0), + AllMemoriesPage( + allMemories: allMemories.map((e) => e.memories).toList(), + allTitles: allMemories.map((e) => e.title).toList(), + initialPageIndex: memoryIdx, + inititalFileIndex: 0, + isFromWidgetOrNotifications: true, ), forceCustomPageRoute: true, ); } - Future _readCacheFromDisk() async { - _logger.info("Reading memories cache result from disk"); - final file = File(await _getCachePath()); - if (!file.existsSync()) { - _logger.info("No memories cache found"); - return null; - } - final allFiles = Set.from( - await SearchService.instance.getAllFilesForSearch(), - ); - final allFileIdsToFile = {}; - for (final file in allFiles) { - if (file.uploadedFileID != null) { - allFileIdsToFile[file.uploadedFileID!] = file; + Future goToPersonMemory(BuildContext context, String personID) async { + _logger.info("Going to person memory for personID: $personID"); + final allMemories = await getMemories(); + if (allMemories.isEmpty) return; + final personMemories = []; + for (final memory in allMemories) { + if (memory is PeopleMemory) { + _logger.info("Found person memory"); + _logger.info("Person memory ID: ${memory.id}"); + _logger.info("Person memory personID: ${memory.personID}"); + _logger.info("Person memory isBirthday: ${memory.isBirthday}"); + } + if (memory is PeopleMemory && + (memory.isBirthday ?? false) && + memory.personID == personID) { + personMemories.add(memory); } } - try { - final bytes = await file.readAsBytes(); - final jsonString = String.fromCharCodes(bytes); - final cache = - MemoriesCache.decodeFromJsonString(jsonString, allFileIdsToFile); - _logger.info("Reading memories cache result from disk done"); - return cache; - } catch (e, s) { - _logger.severe("Error reading or decoding cache file", e, s); - await file.delete(); - return null; + if (personMemories.isEmpty) { + _logger.severe("No person memories found"); + } + PeopleMemory? personMemory; + for (final memory in personMemories) { + if (memory.peopleMemoryType == PeopleMemoryType.youAndThem) { + _logger.info("Found youAndThem person memory"); + personMemory = memory; + break; // breaking to prefer youAndThem over spotlight + } + if (memory.peopleMemoryType == PeopleMemoryType.spotlight) { + _logger.info("Found spotlight person memory"); + personMemory = memory; + } + } + + if (personMemory == null) { + _logger.severe( + "Could not find person memory, routing to person page instead", + ); + final person = await PersonService.instance.getPerson(personID); + if (person == null) { + _logger.severe("Person with ID $personID not found"); + return; + } + await routeToPage( + context, + PeoplePage( + person: person, + searchResult: null, + ), + forceCustomPageRoute: true, + ); + } + _logger.info("Routing to the birthday memory"); + await routeToPage( + context, + FullScreenMemoryDataUpdater( + initialIndex: 0, + memories: personMemory!.memories, + child: Container( + color: backgroundBaseDark, + width: double.infinity, + height: double.infinity, + child: FullScreenMemory(personMemory.title, 0), + ), + ), + forceCustomPageRoute: true, + ); + } + + Future toggleOnThisDayNotifications() async { + final oldValue = localSettings.isOnThisDayNotificationsEnabled; + await localSettings.setOnThisDayNotificationsEnabled(!oldValue); + _logger.info("Turning onThisDayNotifications ${oldValue ? "off" : "on"}"); + if (oldValue) { + await _clearAllScheduledOnThisDayNotifications(); + } else { + queueUpdateCache(); } } - Future clearMemoriesCache({bool fromDisk = true}) async { - if (fromDisk) { - final file = File(await _getCachePath()); - if (file.existsSync()) { - await file.delete(); + Future toggleBirthdayNotifications() async { + final oldValue = localSettings.birthdayNotificationsEnabled; + await localSettings.setBirthdayNotificationsEnabled(!oldValue); + _logger.info("Turning birhtdayNotifications ${oldValue ? "off" : "on"}"); + if (oldValue) { + await _clearAllScheduledBirthdayNotifications(); + } else { + queueUpdateCache(); + } + } + + Future _scheduleMemoryNotifications( + List allMemories, + ) async { + await _scheduleOnThisDayNotifications(allMemories); + await _scheduleBirthdayNotifications(allMemories); + } + + Future _scheduleOnThisDayNotifications( + List allMemories, + ) async { + if (!localSettings.isOnThisDayNotificationsEnabled) { + _logger + .info("On this day notifications are disabled, skipping scheduling"); + return; + } + await _clearAllScheduledOnThisDayNotifications(); + final scheduledDates = {}; + for (final memory in allMemories) { + if (memory.type != MemoryType.onThisDay) { + continue; + } + final numberOfMemories = memory.memories.length; + if (numberOfMemories < 5) continue; + final firstDateToShow = + DateTime.fromMicrosecondsSinceEpoch(memory.firstDateToShow); + final scheduleTime = DateTime( + firstDateToShow.year, + firstDateToShow.month, + firstDateToShow.day, + 8, + ); + if (scheduleTime.isBefore(DateTime.now())) { + _logger.info( + "Skipping scheduling notification for memory ${memory.id} because the date is in the past (date: $scheduleTime)", + ); + continue; + } + if (scheduledDates.contains(scheduleTime)) { + _logger.info( + "Skipping scheduling notification for memory ${memory.id} because the date is already scheduled (date: $scheduleTime)", + ); + continue; + } + final s = await LanguageService.s; + await NotificationService.instance.scheduleNotification( + s.onThisDay, + message: s.lookBackOnYourMemories, + id: memory.id.hashCode, + channelID: "onThisDay", + channelName: s.onThisDay, + payload: memory.id, + dateTime: scheduleTime, + timeoutDurationAndroid: const Duration(hours: 16), + ); + scheduledDates.add(scheduleTime); + _logger.info( + "Scheduled notification for memory ${memory.id} on date: $scheduleTime", + ); + } + } + + Future _scheduleBirthdayNotifications( + List allMemories, + ) async { + if (!localSettings.birthdayNotificationsEnabled) { + _logger.info("birthday notifications are disabled, skipping scheduling"); + return; + } + await _clearAllScheduledBirthdayNotifications(); + final scheduledPersons = {}; + final toSchedule = []; + final peopleToBirthdayMemories = >{}; + for (final memory in allMemories) { + if (memory is PeopleMemory && (memory.isBirthday ?? false)) { + peopleToBirthdayMemories + .putIfAbsent(memory.personID, () => []) + .add(memory); } } - _cachedMemories = null; + personLoop: + for (final personID in peopleToBirthdayMemories.keys) { + final birthdayMemories = peopleToBirthdayMemories[personID]!; + for (final memory in birthdayMemories) { + if (memory.peopleMemoryType == PeopleMemoryType.youAndThem) { + toSchedule.add(memory); + continue personLoop; + } + } + for (final memory in birthdayMemories) { + if (memory.peopleMemoryType == PeopleMemoryType.spotlight) { + toSchedule.add(memory); + continue personLoop; + } + } + } + for (final memory in toSchedule) { + final firstDateToShow = + DateTime.fromMicrosecondsSinceEpoch(memory.firstDateToShow); + final scheduleTime = DateTime( + firstDateToShow.year, + firstDateToShow.month, + firstDateToShow.day, + ); + if (scheduleTime.isBefore(DateTime.now())) { + _logger.info( + "Skipping scheduling notification for memory ${memory.id} because the date is in the past", + ); + continue; + } + if (scheduledPersons.contains(memory.personID)) { + _logger.severe( + "Skipping scheduling notification for memory ${memory.id} because the person's birthday is already scheduled", + ); + continue; + } + final s = await LanguageService.s; + await NotificationService.instance.scheduleNotification( + memory.personName != null + ? s.wishThemAHappyBirthday(memory.personName!) + : s.happyBirthday, + id: memory.id.hashCode, + channelID: "birthday", + channelName: s.birthdays, + payload: "birthday_${memory.personID}", + dateTime: scheduleTime, + timeoutDurationAndroid: const Duration(hours: 24), + ); + scheduledPersons.add(memory.personID); + _logger.info( + "Scheduled birthday notification for person ${memory.personID} on date: $scheduleTime", + ); + } + } + + Future _clearAllScheduledOnThisDayNotifications() async { + _logger.info('Clearing all scheduled On This Day notifications'); + await NotificationService.instance + .clearAllScheduledNotifications(containingPayload: "onThisDay"); + } + + Future _clearAllScheduledBirthdayNotifications() async { + _logger.info('Clearing all scheduled birthday notifications'); + await NotificationService.instance + .clearAllScheduledNotifications(containingPayload: "birthday"); } } diff --git a/mobile/lib/services/memory_home_widget_service.dart b/mobile/lib/services/memory_home_widget_service.dart index c015dd0a69..ca69b75eb4 100644 --- a/mobile/lib/services/memory_home_widget_service.dart +++ b/mobile/lib/services/memory_home_widget_service.dart @@ -9,7 +9,6 @@ import 'package:photos/service_locator.dart'; import 'package:photos/services/home_widget_service.dart'; import 'package:photos/services/sync/local_sync_service.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:synchronized/synchronized.dart'; class MemoryHomeWidgetService { // Constants @@ -33,8 +32,6 @@ class MemoryHomeWidgetService { // Properties final Logger _logger = Logger((MemoryHomeWidgetService).toString()); late final SharedPreferences _prefs; - final _memoryForceRefreshLock = Lock(); - bool _hasSyncedMemory = false; // Initialization void init(SharedPreferences prefs) { @@ -42,15 +39,15 @@ class MemoryHomeWidgetService { } // Preference getters and setters - Future getSelectedLastYearMemories() async { + bool? hasLastYearMemoriesSelected() { return _prefs.getBool(SELECTED_LAST_YEAR_MEMORIES_KEY); } - Future setSelectedLastYearMemories(bool selectedMemories) async { + Future setLastYearMemoriesSelected(bool selectedMemories) async { await _prefs.setBool(SELECTED_LAST_YEAR_MEMORIES_KEY, selectedMemories); } - Future getSelectedMLMemories() async { + bool? getMLMemoriesSelected() { return _prefs.getBool(SELECTED_ML_MEMORIES_KEY); } @@ -58,55 +55,53 @@ class MemoryHomeWidgetService { await _prefs.setBool(SELECTED_ML_MEMORIES_KEY, selectedMemories); } - Future getSelectedOnThisDayMemories() async { + bool? getOnThisDayMemoriesSelected() { return _prefs.getBool(SELECTED_ON_THIS_DAY_MEMORIES_KEY); } - Future setSelectedOnThisDayMemories(bool selectedMemories) async { + Future setOnThisDayMemoriesSelected(bool selectedMemories) async { await _prefs.setBool(SELECTED_ON_THIS_DAY_MEMORIES_KEY, selectedMemories); } // Public methods - Future initMemoryHomeWidget(bool? forceFetchNewMemories) async { - if (await _hasAnyBlockers()) { - await clearWidget(); - return; - } - - await _memoryForceRefreshLock.synchronized(() async { + Future initMemoryHomeWidget() async { + await HomeWidgetService.instance.computeLock.synchronized(() async { if (await _hasAnyBlockers()) { + await clearWidget(); return; } - final isWidgetEmpty = await _isWidgetEmpty(); - forceFetchNewMemories ??= await _shouldForceFetchMemories(isWidgetEmpty); + _logger.info("Initializing memories widget"); - _logger.warning( - "Initializing memory widget: forceFetch: $forceFetchNewMemories, isEmpty: $isWidgetEmpty", - ); + final bool forceFetchNewMemories = await _shouldUpdateWidgetCache(); - if (forceFetchNewMemories!) { - await _forceMemoryUpdate(); - } else if (!isWidgetEmpty) { - await _syncExistingMemories(); + if (forceFetchNewMemories) { + if (await _updateMemoriesWidgetCache()) { + await updateMemoryChanged(false); + _logger.info("Force fetch new memories complete"); + } + } else { + await _refreshMemoriesWidget(); + _logger.info("Refresh memories widget complete"); } }); } Future clearWidget() async { - final isWidgetEmpty = await _isWidgetEmpty(); - if (isWidgetEmpty) { + if (getMemoriesStatus() == WidgetStatus.syncedEmpty) { _logger.info("Widget already empty, nothing to clear"); return; } - _logger.info("Clearing MemoryHomeWidget"); await _setTotalMemories(null); - _hasSyncedMemory = false; await updateMemoriesStatus(WidgetStatus.syncedEmpty); await _refreshWidget(message: "MemoryHomeWidget cleared & updated"); } + bool isMemoryChanged() { + return _prefs.getBool(MEMORY_CHANGED_KEY) ?? false; + } + Future updateMemoryChanged(bool value) async { _logger.info("Updating memory changed flag to $value"); await _prefs.setBool(MEMORY_CHANGED_KEY, value); @@ -123,37 +118,31 @@ class MemoryHomeWidgetService { await _prefs.setInt(MEMORY_STATUS_KEY, value.index); } - Future checkPendingMemorySync({bool addDelay = true}) async { - if (addDelay) { - await Future.delayed(const Duration(seconds: 5)); - } - - final isWidgetEmpty = await _isWidgetEmpty(); - final shouldForceFetch = await _shouldForceFetchMemories(isWidgetEmpty); - - if (_hasSyncedMemory && !shouldForceFetch) { - _logger.info("Memories already synced, no action needed"); + Future checkPendingMemorySync() async { + if (await _hasAnyBlockers()) { + await clearWidget(); return; } - await initMemoryHomeWidget(shouldForceFetch); + _logger.info("Checking pending memory sync"); + if (await _shouldUpdateWidgetCache()) { + await initMemoryHomeWidget(); + } } Future memoryChanged() async { await updateMemoryChanged(true); final cachedMemories = await _getMemoriesForWidget(); - final currentTotal = cachedMemories.length; - final existingTotal = await _getTotalMemories() ?? 0; - - if (existingTotal == currentTotal && existingTotal == 0) { - await updateMemoryChanged(false); + if (cachedMemories.isEmpty) { _logger.info("Memories empty, no update needed"); + await updateMemoryChanged(false); + await clearWidget(); return; } _logger.info("Memories changed, updating widget"); - await initMemoryHomeWidget(true); + await initMemoryHomeWidget(); } Future countHomeWidgets() async { @@ -164,13 +153,13 @@ class MemoryHomeWidgetService { } Future onLaunchFromWidget(int generatedId, BuildContext context) async { - _hasSyncedMemory = true; - await _syncExistingMemories(); - - await memoriesCacheService.goToMemoryFromGeneratedFileID( - context, - generatedId, - ); + memoriesCacheService + .goToMemoryFromGeneratedFileID( + context, + generatedId, + ) + .ignore(); + await _refreshMemoriesWidget(); } // Private methods @@ -179,69 +168,61 @@ class MemoryHomeWidgetService { final hasCompletedFirstImport = LocalSyncService.instance.hasCompletedFirstImport(); if (!hasCompletedFirstImport) { - _logger.warning("First import not completed"); return true; } // Check if memories are enabled final areMemoriesShown = memoriesCacheService.showAnyMemories; if (!areMemoriesShown) { - _logger.warning("Memories not enabled"); return true; } return false; } - Future _forceMemoryUpdate() async { - await _loadAndRenderMemories(); - await updateMemoryChanged(false); - } - - Future _syncExistingMemories() async { - final homeWidgetCount = await countHomeWidgets(); - if (homeWidgetCount == 0) { - _logger.warning("No active home widgets found"); - return; - } - + Future _refreshMemoriesWidget() async { + // only refresh if widget was synced without issues + if (await countHomeWidgets() == 0) return; await _refreshWidget(message: "Refreshing from existing memory set"); } - Future _isWidgetEmpty() async { - final total = await _getTotalMemories(); - return total == 0 || total == null; - } - - Future _shouldForceFetchMemories(bool isWidgetEmpty) async { - // Check if memory changed flag is set - final memoryChanged = _prefs.getBool(MEMORY_CHANGED_KEY) ?? true; - if (memoryChanged == true) { - return true; - } + Future _shouldUpdateWidgetCache() async { + // Update widget cache when memories were changed + if (isMemoryChanged() == true) return true; final memoriesStatus = getMemoriesStatus(); - switch (memoriesStatus) { - case WidgetStatus.notSynced: - return true; - case WidgetStatus.syncedPartially: - return await countHomeWidgets() > 0; - case WidgetStatus.syncedEmpty: - case WidgetStatus.syncedAll: - return false; - } + + // update widget cache if + // - memories not synced + // - memories synced partially but now home widget is present + return memoriesStatus == WidgetStatus.notSynced || + memoriesStatus == WidgetStatus.syncedPartially && + await countHomeWidgets() > 0; } Future> _getMemoriesForWidget() async { - final lastYearValue = await getSelectedLastYearMemories(); - final mlValue = await getSelectedMLMemories(); - final onThisDayValue = await getSelectedOnThisDayMemories(); final isMLEnabled = flagService.hasGrantedMLConsent; + bool? smartMemoryValue = getMLMemoriesSelected(); + bool? lastYearValue = hasLastYearMemoriesSelected(); + bool? onThisDayValue = getOnThisDayMemoriesSelected(); + // If ML is enabled then we use Smart memories by default, otherwise date based memories + if (isMLEnabled) { + lastYearValue ??= false; + onThisDayValue ??= false; + smartMemoryValue ??= true; + } else { + lastYearValue ??= true; + onThisDayValue ??= true; + smartMemoryValue ??= false; + } + + // TODO: Only read from cache memory final memories = await memoriesCacheService.getMemoriesForWidget( - onThisDay: onThisDayValue ?? !isMLEnabled, - pastYears: lastYearValue ?? !isMLEnabled, - smart: mlValue ?? isMLEnabled, + onThisDay: onThisDayValue, + pastYears: lastYearValue, + smart: smartMemoryValue, + hasAnyWidgets: await countHomeWidgets() > 0, ); return memories; @@ -256,20 +237,14 @@ class MemoryHomeWidgetService { return Map.fromEntries( memories.map( - (memory) => - MapEntry(memory.title, memory.memories.map((m) => m.file).toList()), + (memory) => MapEntry( + memory.title, + memory.memories.map((m) => m.file).toList(), + ), ), ); } - Future _getTotalMemories() async { - return HomeWidgetService.instance.getData(TOTAL_MEMORIES_KEY); - } - - Future _setTotalMemories(int? total) async { - await HomeWidgetService.instance.setData(TOTAL_MEMORIES_KEY, total); - } - Future _refreshWidget({String? message}) async { await HomeWidgetService.instance.updateWidget( androidClass: ANDROID_CLASS_NAME, @@ -291,20 +266,20 @@ class MemoryHomeWidgetService { _logger.info("Home Widget updated: ${message ?? "standard update"}"); } - Future _loadAndRenderMemories() async { - final memoriesWithFiles = await _getMemoriesWithFiles(); + Future _setTotalMemories(int? total) async { + await HomeWidgetService.instance.setData(TOTAL_MEMORIES_KEY, total); + } + // _updateMemoriesWidgetCache will return false if no memories were cached + Future _updateMemoriesWidgetCache() async { + // TODO: Can update the method to fetch directly max limit random memories + final memoriesWithFiles = await _getMemoriesWithFiles(); if (memoriesWithFiles.isEmpty) { - _logger.warning("No memories found, clearing widget"); await clearWidget(); - return; + return false; } - final currentTotal = await _getTotalMemories(); - _logger.info("Current total memories in widget: $currentTotal"); - final bool isWidgetPresent = await countHomeWidgets() > 0; - final limit = isWidgetPresent ? MAX_MEMORIES_LIMIT : 5; final maxAttempts = limit * 10; @@ -343,7 +318,8 @@ class MemoryHomeWidgetService { if (renderResult != null) { // Check for blockers again before continuing if (await _hasAnyBlockers()) { - return; + await clearWidget(); + return true; } await _setTotalMemories(renderedCount); @@ -369,7 +345,7 @@ class MemoryHomeWidgetService { } if (renderedCount == 0) { - return; + return false; } if (isWidgetPresent) { @@ -379,5 +355,6 @@ class MemoryHomeWidgetService { await _refreshWidget( message: "Switched to next memory set, total: $renderedCount", ); + return true; } } diff --git a/mobile/lib/services/notification_service.dart b/mobile/lib/services/notification_service.dart index 8d9fe3e3f7..c315d3e410 100644 --- a/mobile/lib/services/notification_service.dart +++ b/mobile/lib/services/notification_service.dart @@ -143,13 +143,14 @@ class NotificationService { } Future scheduleNotification( - String title, - String message, { + String title, { + String? message, required int id, String channelID = "io.ente.photos", String channelName = "ente", String payload = "ente://home", required DateTime dateTime, + Duration? timeoutDurationAndroid, }) async { try { _logger.info( @@ -207,6 +208,39 @@ class NotificationService { s, ); } + final androidSpecs = AndroidNotificationDetails( + channelID, + channelName, + channelDescription: 'ente alerts', + importance: Importance.max, + priority: Priority.high, + category: AndroidNotificationCategory.reminder, + showWhen: false, + timeoutAfter: timeoutDurationAndroid?.inMilliseconds, + ); + final iosSpecs = DarwinNotificationDetails(threadIdentifier: channelID); + final platformChannelSpecs = + NotificationDetails(android: androidSpecs, iOS: iosSpecs); + final scheduledDate = tz.TZDateTime.local( + dateTime.year, + dateTime.month, + dateTime.day, + dateTime.hour, + dateTime.minute, + dateTime.second, + ); + await _notificationsPlugin.zonedSchedule( + id, + title, + message, + scheduledDate, + platformChannelSpecs, + androidScheduleMode: AndroidScheduleMode.inexactAllowWhileIdle, + payload: payload, + ); + _logger.info( + "Scheduled notification with: $title, $message, $channelID, $channelName, $payload", + ); } Future clearAllScheduledNotifications({ diff --git a/mobile/lib/services/people_home_widget_service.dart b/mobile/lib/services/people_home_widget_service.dart index ee758caac0..c204e140b1 100644 --- a/mobile/lib/services/people_home_widget_service.dart +++ b/mobile/lib/services/people_home_widget_service.dart @@ -6,9 +6,6 @@ import 'package:fluttertoast/fluttertoast.dart'; import 'package:logging/logging.dart'; import 'package:photos/db/files_db.dart'; import 'package:photos/models/file/file.dart'; -import "package:photos/models/search/generic_search_result.dart"; -import "package:photos/models/search/hierarchical/face_filter.dart"; -import "package:photos/models/search/search_types.dart"; import 'package:photos/service_locator.dart'; import 'package:photos/services/home_widget_service.dart'; import 'package:photos/services/machine_learning/face_ml/person/person_service.dart'; @@ -23,6 +20,7 @@ import 'package:synchronized/synchronized.dart'; class PeopleHomeWidgetService { // Constants static const String SELECTED_PEOPLE_KEY = "selectedPeopleHW"; + static const String PEOPLE_LAST_HASH_KEY = "peopleLastHash"; static const String ANDROID_CLASS_NAME = "EntePeopleWidgetProvider"; static const String IOS_CLASS_NAME = "EntePeopleWidget"; static const String PEOPLE_STATUS_KEY = "peopleStatusKey.widget"; @@ -38,8 +36,7 @@ class PeopleHomeWidgetService { // Properties final Logger _logger = Logger((PeopleHomeWidgetService).toString()); late final SharedPreferences _prefs; - final _peopleForceRefreshLock = Lock(); - bool _hasSyncedPeople = false; + final peopleChangedLock = Lock(); // Initialization void init(SharedPreferences prefs) { @@ -52,69 +49,63 @@ class PeopleHomeWidgetService { } Future setSelectedPeople(List selectedPeople) async { - final previousSelection = getSelectedPeople(); await _prefs.setStringList(SELECTED_PEOPLE_KEY, selectedPeople); - if (previousSelection != null) { - final oldSet = previousSelection.toSet(); - final newSet = selectedPeople.toSet(); - - if (oldSet.containsAll(newSet) && newSet.containsAll(oldSet)) { - _logger.info("People selection unchanged, no update needed"); - return; - } - } - _logger.info("People selection changed, updating widget"); - await updatePeopleChanged(true); + await checkPeopleChanged(); } - Future countHomeWidgets() async { - return await HomeWidgetService.instance.countHomeWidgets( - ANDROID_CLASS_NAME, - IOS_CLASS_NAME, - ); + String? getPeopleLastHash() { + return _prefs.getString(PEOPLE_LAST_HASH_KEY); } - Future initHomeWidget(bool? forceFetchNewPeople) async { - if (await _hasAnyBlockers()) { - await clearWidget(); - return; - } + Future setPeopleLastHash(String hash) async { + await _prefs.setString(PEOPLE_LAST_HASH_KEY, hash); + } - await _peopleForceRefreshLock.synchronized(() async { + Future initPeopleHomeWidget() async { + await HomeWidgetService.instance.computeLock.synchronized(() async { if (await _hasAnyBlockers()) { + await clearWidget(); return; } - final isPeopleEmpty = await _isWidgetEmpty(); - forceFetchNewPeople ??= await _shouldForceFetchPeople(isPeopleEmpty); + _logger.info("Initializing people widget"); - _logger.warning( - "Initializing people widget: forceFetch: $forceFetchNewPeople, isPeopleEmpty: $isPeopleEmpty", - ); + final bool forceFetchNewPeople = await _shouldUpdateWidgetCache(); - if (forceFetchNewPeople!) { - await _forcePeopleUpdate(); - } else if (!isPeopleEmpty) { - await _syncExistingPeople(); + if (forceFetchNewPeople) { + await _updatePeopleWidgetCache(); + await updatePeopleChanged(false); + _logger.info("Force fetch new people complete"); + } else { + await _refreshPeopleWidget(); + _logger.info("Refresh people widget complete"); } }); } Future clearWidget() async { - if (await _isWidgetEmpty()) { + if (getPeopleStatus() == WidgetStatus.syncedEmpty) { _logger.info("Widget already empty, nothing to clear"); return; } - _logger.info("Clearing PeopleHomeWidget"); + await setPeopleLastHash(""); await _setTotalPeople(null); - _hasSyncedPeople = false; await updatePeopleStatus(WidgetStatus.syncedEmpty); await _refreshWidget(message: "PeopleHomeWidget cleared & updated"); } + bool getPeopleChanged() { + return _prefs.getBool(PEOPLE_CHANGED_KEY) ?? false; + } + + Future updatePeopleChanged(bool value) async { + _logger.info("Updating people changed flag to $value"); + await _prefs.setBool(PEOPLE_CHANGED_KEY, value); + } + WidgetStatus getPeopleStatus() { return WidgetStatus.values.firstWhereOrNull( (v) => v.index == (_prefs.getInt(PEOPLE_STATUS_KEY) ?? 0), @@ -126,42 +117,44 @@ class PeopleHomeWidgetService { await _prefs.setInt(PEOPLE_STATUS_KEY, value.index); } - Future updatePeopleChanged(bool value) async { - _logger.info("Updating people changed flag to $value"); - await _prefs.setBool(PEOPLE_CHANGED_KEY, value); - } - - Future checkPendingPeopleSync({bool addDelay = true}) async { - if (addDelay) { - await Future.delayed(const Duration(seconds: 5)); - } - - final isPeopleEmpty = await _isWidgetEmpty(); - final needsForceFetch = await _shouldForceFetchPeople(isPeopleEmpty); - - if (_hasSyncedPeople && !needsForceFetch) { - _logger.info("People already synced, no action needed"); + Future checkPendingPeopleSync() async { + if (await _hasAnyBlockers()) { + await clearWidget(); return; } - await HomeWidgetService.instance.initHomeWidget(); + _logger.info("Checking pending people sync"); + if (await _shouldUpdateWidgetCache()) { + await initPeopleHomeWidget(); + } } - Future peopleChanged() async { - await updatePeopleChanged(true); + Future checkPeopleChanged() async { + final havePeopleChanged = await peopleChangedLock.synchronized(() async { + final peopleIds = await _getEffectiveSelections(); + final currentHash = await _calculateHash(peopleIds); + final lastHash = getPeopleLastHash(); - final cachedMemories = await _getPeople(); - final currentTotal = cachedMemories.length; - final existingTotal = await _getTotalPeople() ?? 0; + if (lastHash != null && currentHash == lastHash) { + return false; + } - if (existingTotal == currentTotal && existingTotal == 0) { - await updatePeopleChanged(false); - _logger.info("People empty, no update needed"); + return true; + }); + + await updatePeopleChanged(havePeopleChanged); + if (!havePeopleChanged) { + _logger.info("No changes detected in people, skipping update"); return; } + await initPeopleHomeWidget(); + } - _logger.info("People changed, updating widget"); - await initHomeWidget(true); + Future countHomeWidgets() async { + return await HomeWidgetService.instance.countHomeWidgets( + ANDROID_CLASS_NAME, + IOS_CLASS_NAME, + ); } Future onLaunchFromWidget( @@ -169,9 +162,6 @@ class PeopleHomeWidgetService { String personId, BuildContext context, ) async { - _hasSyncedPeople = true; - await _syncExistingPeople(); - final file = await FilesDB.instance.getFile(fileId); if (file == null) { _logger.warning("Cannot launch widget: file with ID $fileId not found"); @@ -200,7 +190,7 @@ class PeopleHomeWidgetService { ); final files = clusterFiles.entries.expand((e) => e.value).toList(); - await routeToPage( + routeToPage( context, DetailPage( DetailPageConfiguration( @@ -210,126 +200,95 @@ class PeopleHomeWidgetService { ), ), forceCustomPageRoute: true, - ); + ).ignore(); + await _refreshPeopleWidget(); } - // Private methods - Future _forcePeopleUpdate() async { - await _loadAndRenderPeople(); - await updatePeopleChanged(false); + Future> _getEffectiveSelections() async { + var selection = getSelectedPeople(); + + if ((selection?.isEmpty ?? true) && + getPeopleStatus() == WidgetStatus.syncedAll) { + selection = await SearchService.instance.getTopTwoFaces(); + if (selection.isEmpty) { + await clearWidget(); + return []; + } + await setSelectedPeople(selection); + } + + return selection ?? []; + } + + Future _calculateHash(List peopleIds) async { + return await entityService.getHashForIds(peopleIds); } Future _hasAnyBlockers() async { + if (await countHomeWidgets() == 0) { + return true; + } + // Check if first import is completed final hasCompletedFirstImport = LocalSyncService.instance.hasCompletedFirstImport(); if (!hasCompletedFirstImport) { - _logger.warning("First import not completed"); return true; } // Check ML consent if (!flagService.hasGrantedMLConsent) { - _logger.warning("ML consent not granted"); return true; } - // Check if selected people exist - final peopleIds = await _getEffectiveSelectedPeopleIds(); - try { - for (final id in peopleIds) { - final person = await PersonService.instance.getPerson(id); - if (person == null) { - _logger.warning("Person not found for id: $id"); - return true; - } - } - } catch (e) { - _logger.warning("Error looking up people: $e"); + // Check if selected people or hash exist + final peopleIds = await _getEffectiveSelections(); + final hash = await _calculateHash(peopleIds); + + final noSelectionOrHashEmpty = peopleIds.isEmpty || hash.isEmpty; + if (noSelectionOrHashEmpty) { + _logger.info("No selected people or hash empty, cannot update widget"); return true; } return false; } - Future _syncExistingPeople() async { - final homeWidgetCount = await countHomeWidgets(); - if (homeWidgetCount == 0) { - _logger.warning("No active home widgets found"); - return; - } - + Future _refreshPeopleWidget() async { + // only refresh if widget was synced without issues + if (await countHomeWidgets() == 0) return; await _refreshWidget(message: "Refreshing from existing people set"); } - Future _isWidgetEmpty() async { - final totalPeople = await _getTotalPeople(); - return totalPeople == 0 || totalPeople == null; - } - - Future _shouldForceFetchPeople(bool isPeopleEmpty) async { - final peopleChanged = _prefs.getBool(PEOPLE_CHANGED_KEY); - if (peopleChanged ?? true) { + Future _shouldUpdateWidgetCache() async { + // Update widget cache when people were changed + if (getPeopleChanged() == true) { return true; } + // update widget cache if + // - people not synced + // - people synced partially but now home widget is present final peopleStatus = getPeopleStatus(); - switch (peopleStatus) { - case WidgetStatus.notSynced: - return true; - case WidgetStatus.syncedPartially: - return await countHomeWidgets() > 0; - case WidgetStatus.syncedEmpty: - case WidgetStatus.syncedAll: - return false; - } + return peopleStatus == WidgetStatus.notSynced || + peopleStatus == WidgetStatus.syncedPartially && + await countHomeWidgets() > 0; } - Future> _getEffectiveSelectedPeopleIds() async { - var peopleIds = getSelectedPeople(); - - if (peopleIds == null || peopleIds.isEmpty) { - // Search Filter with face and pick top two faces - final searchFilter = await SectionType.face.getData(null).then( - (value) => List.from(value).where( - (element) => - (element.hierarchicalSearchFilter as FaceFilter).personId != - null, - ), - ); - - if (searchFilter.isNotEmpty) { - peopleIds = searchFilter - .take(2) - .map((e) => (e.hierarchicalSearchFilter as FaceFilter).personId!) - .toList(); - } else { - _logger.warning("No selected people found"); - } - } - - return peopleIds ?? []; - } - - Future)>> _getPeople() async { - final peopleIds = await _getEffectiveSelectedPeopleIds(); + Future)>> _getPeople( + List personIds, + ) async { final Map)> peopleFiles = {}; - - for (final id in peopleIds) { - final person = await PersonService.instance.getPerson(id); - if (person == null) { - _logger.warning("Person not found for id: $id"); - continue; - } - - final clusterFiles = - await SearchService.instance.getClusterFilesForPersonID(id); + final persons = await PersonService.instance.getCertainPersons(personIds); + for (final person in persons) { + final clusterFiles = await SearchService.instance + .getClusterFilesForPersonID(person.remoteID); final files = clusterFiles.entries.expand((e) => e.value).toList(); if (files.isEmpty) { _logger.warning("No files found for person: ${person.data.name}"); continue; } - peopleFiles[id] = (person.data.name, files); + peopleFiles[person.remoteID] = (person.data.name, files); } return peopleFiles; @@ -356,16 +315,13 @@ class PeopleHomeWidgetService { _logger.info("Home Widget updated: ${message ?? "standard update"}"); } - Future _getTotalPeople() async { - return HomeWidgetService.instance.getData(TOTAL_PEOPLE_KEY); - } - Future _setTotalPeople(int? total) async { await HomeWidgetService.instance.setData(TOTAL_PEOPLE_KEY, total); } - Future _loadAndRenderPeople() async { - final peopleWithFiles = await _getPeople(); + Future _updatePeopleWidgetCache() async { + final peopleIds = await _getEffectiveSelections(); + final peopleWithFiles = await _getPeople(peopleIds); if (peopleWithFiles.isEmpty) { _logger.warning("No files found for any people, clearing widget"); @@ -373,13 +329,8 @@ class PeopleHomeWidgetService { return; } - final currentTotal = await _getTotalPeople(); - _logger.info("Current total people in widget: $currentTotal"); - - final bool isWidgetPresent = await countHomeWidgets() > 0; - - final limit = isWidgetPresent ? MAX_PEOPLE_LIMIT : 5; - final maxAttempts = limit * 10; + const limit = MAX_PEOPLE_LIMIT; + const maxAttempts = limit * 10; int renderedCount = 0; int attemptsCount = 0; @@ -446,9 +397,10 @@ class PeopleHomeWidgetService { return; } - if (isWidgetPresent) { - await updatePeopleStatus(WidgetStatus.syncedAll); - } + await updatePeopleStatus(WidgetStatus.syncedAll); + + final hash = await _calculateHash(peopleIds); + await setPeopleLastHash(hash); await _refreshWidget( message: "Switched to next people set, total: $renderedCount", diff --git a/mobile/lib/services/search_service.dart b/mobile/lib/services/search_service.dart index a2191526f0..3530e407c1 100644 --- a/mobile/lib/services/search_service.dart +++ b/mobile/lib/services/search_service.dart @@ -5,6 +5,7 @@ import "package:flutter/cupertino.dart"; import "package:flutter/material.dart"; import "package:intl/intl.dart"; import 'package:logging/logging.dart'; +import "package:path_provider/path_provider.dart"; import "package:photos/core/configuration.dart"; import "package:photos/core/constants.dart"; import 'package:photos/core/event_bus.dart'; @@ -24,6 +25,7 @@ import 'package:photos/models/file/file_type.dart'; import "package:photos/models/local_entity_data.dart"; import "package:photos/models/location/location.dart"; import "package:photos/models/location_tag/location_tag.dart"; +import "package:photos/models/memories/memories_cache.dart"; import "package:photos/models/memories/memory.dart"; import "package:photos/models/memories/smart_memory.dart"; import "package:photos/models/ml/face/person.dart"; @@ -47,12 +49,14 @@ import "package:photos/services/location_service.dart"; import "package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart"; import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; import 'package:photos/services/machine_learning/semantic_search/semantic_search_service.dart'; +import "package:photos/services/memories_cache_service.dart"; import "package:photos/states/location_screen_state.dart"; import "package:photos/ui/viewer/location/add_location_sheet.dart"; import "package:photos/ui/viewer/location/location_screen.dart"; import "package:photos/ui/viewer/people/cluster_page.dart"; import "package:photos/ui/viewer/people/people_page.dart"; import "package:photos/ui/viewer/search/result/magic_result_screen.dart"; +import "package:photos/utils/cache_util.dart"; import "package:photos/utils/file_util.dart"; import "package:photos/utils/navigation_util.dart"; import 'package:photos/utils/standalone/date_time.dart'; @@ -92,7 +96,7 @@ class SearchService { } if (_cachedFilesFuture == null) { - _logger.fine("Reading all files from db"); + _logger.info("Reading all files from db"); _cachedFilesFuture = FilesDB.instance.getAllFilesFromDB( ignoreCollections(), dedupeByUploadId: false, @@ -118,7 +122,7 @@ class SearchService { } if (_cachedFilesFuture == null) { - _logger.fine("Reading all files from db"); + _logger.info("Reading all files from db"); _cachedFilesFuture = FilesDB.instance.getAllFilesFromDB( ignoreCollections(), dedupeByUploadId: false, @@ -142,7 +146,7 @@ class SearchService { if (_cachedHiddenFilesFuture != null) { return _cachedHiddenFilesFuture!; } - _logger.fine("Reading hidden files from db"); + _logger.info("Reading hidden files from db"); final hiddenCollections = CollectionsService.instance.getHiddenCollectionIds(); _cachedHiddenFilesFuture = @@ -659,6 +663,19 @@ class SearchService { return searchResults; } + Future> getTopTwoFaces() async { + final searchFilter = await SectionType.face.getData(null).then( + (value) => (value as List).where( + (element) => (element.params[kPersonParamID] as String?) != null, + ), + ); + + return searchFilter + .take(2) + .map((e) => e.params[kPersonParamID] as String) + .toList(); + } + Future> getLocationResults(String query) async { final locationTagEntities = (await locationService.getLocationTags()); final Map, List> result = {}; @@ -687,7 +704,7 @@ class SearchService { } } if (showNoLocationTag) { - _logger.fine("finding photos with no location"); + _logger.info("finding photos with no location"); // find files that have location but the file's location is not inside // any location tag final noLocationTagFiles = allFiles.where((file) { @@ -925,10 +942,10 @@ class SearchService { ); for (final clusterId in sortedClusterIds) { + if (limit != null && facesResult.length >= limit) { + break; + } final files = clusterIdToFiles[clusterId]!; - // final String clusterName = "ID:$clusterId, ${files.length}"; - // final String clusterName = "${files.length}"; - // const String clusterName = ""; final String clusterName = clusterId; if (clusterIDToPersonID[clusterId] != null) { @@ -987,15 +1004,8 @@ class SearchService { ); } if (facesResult.isEmpty) { - int newMinimum = minClusterSize; - for (final int minimum in kLowerMinimumClusterSizes) { - if (minimum < minClusterSize) { - newMinimum = minimum; - break; - } - } - if (newMinimum < minClusterSize) { - return getAllFace(limit, minClusterSize: newMinimum); + if (kMinimumClusterSizeAllFaces < minClusterSize) { + return getAllFace(limit, minClusterSize: kMinimumClusterSizeAllFaces); } else { return []; } @@ -1275,7 +1285,33 @@ class SearchService { final memoriesResult = await smartMemoriesService .calcSmartMemories(calcTime, cache, debugSurfaceAll: true); locationService.baseLocations = memoriesResult.baseLocations; - memories = memoriesResult.memories; + for (final nowMemory in memoriesResult.memories) { + cache.toShowMemories + .add(ToShowMemory.fromSmartMemory(nowMemory, calcTime)); + } + cache.baseLocations.addAll(memoriesResult.baseLocations); + // memories = memoriesResult.memories; + final tempCachePath = (await getTemporaryDirectory()).path + + "/cache/test/memories_cache_test"; + await writeToJsonFile( + tempCachePath, + cache, + MemoriesCache.encodeToJsonString, + ); + _logger.info( + "Smart memories cache written to $tempCachePath", + ); + final decodedCache = await decodeJsonFile( + tempCachePath, + MemoriesCache.decodeFromJsonString, + ); + _logger.info( + "Smart memories cache decoded from $tempCachePath", + ); + memories = await MemoriesCacheService.fromCacheToMemories(decodedCache!); + _logger.info( + "Smart memories cache converted to memories", + ); } final searchResults = []; for (final memory in memories) { diff --git a/mobile/lib/services/smart_memories_service.dart b/mobile/lib/services/smart_memories_service.dart index fecdebeae0..1da43ff1fd 100644 --- a/mobile/lib/services/smart_memories_service.dart +++ b/mobile/lib/services/smart_memories_service.dart @@ -70,36 +70,36 @@ class SmartMemoriesService { }) async { try { final TimeLogger t = TimeLogger(context: "calcMemories"); - _logger.finest( + _logger.info( 'calcMemories called with time: $now at ${DateTime.now()} $t', ); final (allFiles, allFileIdsToFile) = await _getFilesAndMapForMemories(); - _logger.finest("All files length: ${allFiles.length} $t"); + _logger.info("All files length: ${allFiles.length} $t"); final collectionIDsToExclude = await getCollectionIDsToExclude(); - _logger.finest( + _logger.info( 'collectionIDsToExclude length: ${collectionIDsToExclude.length} $t', ); final seenTimes = await _memoriesDB.getSeenTimes(); - _logger.finest('seenTimes has ${seenTimes.length} entries $t'); + _logger.info('seenTimes has ${seenTimes.length} entries $t'); final persons = await PersonService.instance.getPersons(); - _logger.finest('gotten all ${persons.length} persons $t'); + _logger.info('gotten all ${persons.length} persons $t'); final currentUserEmail = Configuration.instance.getEmail(); - _logger.finest('currentUserEmail: $currentUserEmail $t'); + _logger.info('currentUserEmail: $currentUserEmail $t'); final cities = await locationService.getCities(); - _logger.finest('cities has ${cities.length} entries $t'); + _logger.info('cities has ${cities.length} entries $t'); final Map> fileIdToFaces = await MLDataDB.instance.getFileIDsToFacesWithoutEmbedding(); - _logger.finest('fileIdToFaces has ${fileIdToFaces.length} entries $t'); + _logger.info('fileIdToFaces has ${fileIdToFaces.length} entries $t'); final allImageEmbeddings = await MLDataDB.instance.getAllClipVectors(); - _logger.finest( + _logger.info( 'allImageEmbeddings has ${allImageEmbeddings.length} entries $t', ); @@ -120,15 +120,15 @@ class SmartMemoriesService { await MLComputer.instance.runClipText(clipQuery(clipMemoryType)), ); } - _logger.finest('clipPositiveTextVector and clipPeopleActivityVectors $t'); + _logger.info('clipPositiveTextVector and clipPeopleActivityVectors $t'); final local = await getLocale(); final languageCode = local?.languageCode ?? "en"; final s = await LanguageService.s; - _logger.finest('get locale and S $t'); + _logger.info('get locale and S $t'); - _logger.finest('all data fetched $t at ${DateTime.now()}, to computer'); + _logger.info('all data fetched $t at ${DateTime.now()}, to computer'); final memoriesResult = await Computer.shared().compute( _allMemoriesCalculations, param: { @@ -149,14 +149,14 @@ class SmartMemoriesService { "clipMemoryTypeVectors": clipMemoryTypeVectors, }, ) as MemoriesResult; - _logger.finest( + _logger.info( '${memoriesResult.memories.length} memories computed in computer $t', ); for (final memory in memoriesResult.memories) { memory.title = memory.createTitle(s, languageCode); } - _logger.finest('titles created for all memories $t'); + _logger.info('titles created for all memories $t'); return memoriesResult; } catch (e, s) { _logger.severe("Error calculating smart memories", e, s); @@ -272,6 +272,7 @@ class SmartMemoriesService { // Trip memories final (tripMemories, bases) = await _getTripsResults( allFiles, + allFileIdsToFile, now, oldCache.tripsShownLogs, surfaceAll: debugSurfaceAll, @@ -358,7 +359,7 @@ class SmartMemoriesService { final languageCode = local?.languageCode ?? "en"; final s = await LanguageService.s; - _logger.finest('get locale and S'); + _logger.info('get locale and S'); for (final memory in memories) { memory.title = memory.createTitle(s, languageCode); } @@ -631,7 +632,7 @@ class SmartMemoriesService { // Loop through the people and check if we should surface anything based on relevancy (bday, last met) for (final personID in orderedImportantPersonsID) { final personMemories = personToMemories[personID]; - if (personID == meID || personMemories == null) continue; + if (personMemories == null) continue; final person = personIdToPerson[personID]!; // Check if we should surface memory based on last met @@ -645,8 +646,6 @@ class SmartMemoriesService { if (daysSinceLastMet < 7 && daysSinceLastMet >= 0) { memoryResults.add(lastMetMemory); } - // Don't surface birthday when person hasn't been seen in a while (could be passed away) - continue; } // Check if we should surface memory based on birthday @@ -686,15 +685,24 @@ class SmartMemoriesService { if (youAndThemMem != null) { memoryResults.add( youAndThemMem.copyWith( + isBirthday: false, + newAge: newAge, firstDateToShow: thisBirthday .subtract(const Duration(days: 5)) .microsecondsSinceEpoch, + lastDateToShow: thisBirthday.microsecondsSinceEpoch, + ), + ); + memoryResults.add( + youAndThemMem.copyWith( + isBirthday: true, + newAge: newAge, + firstDateToShow: thisBirthday.microsecondsSinceEpoch, lastDateToShow: thisBirthday.add(kDayItself).microsecondsSinceEpoch, ), ); } - continue; } } } @@ -728,7 +736,7 @@ class SmartMemoriesService { 'Something is going wrong, ${potentialMemory.peopleMemoryType} has multiple memories for same person', ); } else { - final randIdx = Random().nextInt(potentialMemory.memories.length); + final randIdx = Random().nextInt(memoriesForCategory.length); potentialMemory = memoriesForCategory[randIdx]; } } @@ -841,6 +849,7 @@ class SmartMemoriesService { static Future<(List, List)> _getTripsResults( Iterable allFiles, + Map allFileIdsToFile, DateTime currentTime, List shownTrips, { bool surfaceAll = false, @@ -946,7 +955,13 @@ class SmartMemoriesService { const Duration(days: 90), ), ); - baseLocations.add(BaseLocation(files, location, isCurrent)); + baseLocations.add( + BaseLocation( + files.map((file) => file.uploadedFileID!).toList(), + location, + isCurrent, + ), + ); } // Identify trip locations @@ -1098,8 +1113,11 @@ class SmartMemoriesService { for (final baseLocation in baseLocations) { String name = "Base (${baseLocation.isCurrentBase ? 'current' : 'old'})"; + final files = baseLocation.fileIDs + .map((fileID) => allFileIdsToFile[fileID]!) + .toList(); final String? locationName = _tryFindLocationName( - Memory.fromFiles(baseLocation.files, seenTimes), + Memory.fromFiles(files, seenTimes), cities, base: true, ); @@ -1109,7 +1127,7 @@ class SmartMemoriesService { } memoryResults.add( TripMemory( - Memory.fromFiles(baseLocation.files, seenTimes), + Memory.fromFiles(files, seenTimes), nowInMicroseconds, windowEnd, baseLocation.location, @@ -1678,14 +1696,7 @@ class SmartMemoriesService { if (memories == null) continue; if (memories.length < 5) continue; final years = daysToYears[day]!; - if (years.toSet().length < 3) continue; - final yearCounts = {}; - for (final year in years) { - yearCounts[year] = (yearCounts[year] ?? 0) + 1; - } - final bool hasThreeInAtLeastThreeYears = - yearCounts.values.where((count) => count >= 3).length >= 3; - if (!hasThreeInAtLeastThreeYears) continue; + if (years.toSet().length < 2) continue; final filteredMemories = []; if (memories.length > 20) { diff --git a/mobile/lib/services/sync/diff_fetcher.dart b/mobile/lib/services/sync/diff_fetcher.dart index 405978f2f8..45794bf3d3 100644 --- a/mobile/lib/services/sync/diff_fetcher.dart +++ b/mobile/lib/services/sync/diff_fetcher.dart @@ -24,18 +24,10 @@ class DiffFetcher { bool sortAsc, ) async { try { - final authToken = await CollectionsService.instance - .getSharedPublicAlbumToken(collectionID); - final authJWTToken = await CollectionsService.instance - .getSharedPublicAlbumTokenJWT(collectionID); bool hasMore = false; final sharedFiles = []; - - final headers = { - "X-Auth-Access-Token": authToken, - if (authJWTToken != null) "X-Auth-Access-Token-JWT": authJWTToken, - }; - + final headers = + CollectionsService.instance.publicCollectionHeaders(collectionID); int sinceTime = 0; do { diff --git a/mobile/lib/services/sync/local_sync_service.dart b/mobile/lib/services/sync/local_sync_service.dart index aa630c2d73..8e46ba9893 100644 --- a/mobile/lib/services/sync/local_sync_service.dart +++ b/mobile/lib/services/sync/local_sync_service.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:logging/logging.dart'; import 'package:photo_manager/photo_manager.dart'; +import "package:photos/core/cache/lru_map.dart"; import 'package:photos/core/configuration.dart'; import "package:photos/core/errors.dart"; import 'package:photos/core/event_bus.dart'; @@ -29,6 +30,11 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:synchronized/synchronized.dart'; import 'package:tuple/tuple.dart'; +// This map is used to track if a iOS origin file is being fetched for uploading +// or ML processing. In such cases, we want to ignore these files if they come in response +// from the local sync service. When a file is download +final LRUMap trackOriginFetchForUploadOrML = LRUMap(200); + class LocalSyncService { final _logger = Logger("LocalSyncService"); final _db = FilesDB.instance; @@ -124,7 +130,7 @@ class LocalSyncService { if (!hasCompletedFirstImport()) { await _prefs.setBool(kHasCompletedFirstImportKey, true); await _refreshDeviceFolderCountAndCover(isFirstSync: true); - _logger.fine("first gallery import finished"); + _logger.info("first gallery import finished"); Bus.instance .fire(SyncStatusUpdate(SyncStatus.completedFirstGalleryImport)); } @@ -297,15 +303,31 @@ class LocalSyncService { conflictAlgorithm: SqliteAsyncConflictAlgorithm.ignore, ); _logger.info('Inserted ${files.length} out of ${allFiles.length} files'); - if (allFiles.isNotEmpty) { - Bus.instance.fire( - LocalPhotosUpdatedEvent(allFiles, source: "loadedPhoto"), - ); - } + _checkAndFireLocalAssetUpdateEvent(allFiles, files.isNotEmpty); } await _prefs.setInt(kDbUpdationTimeKey, toTime); } + void _checkAndFireLocalAssetUpdateEvent( + List allFiles, + bool discoveredNewFiles, + ) { + if (allFiles.isEmpty) return; + if (!discoveredNewFiles) { + allFiles.removeWhere( + (file) => + trackOriginFetchForUploadOrML.get(file.localID ?? '') ?? false, + ); + if (allFiles.isEmpty) { + _logger.info("skipping firing LocalPhotosUpdatedEvent as no new files"); + return; + } + } + Bus.instance.fire( + LocalPhotosUpdatedEvent(allFiles, source: "loadedPhoto"), + ); + } + Future _trackUpdatedFiles( List files, Set existingLocalFileIDs, @@ -318,11 +340,20 @@ class LocalSyncService { ) .map((e) => e.localID!) .toList(); + if (updatedLocalIDs.isNotEmpty) { - await FileUpdationDB.instance.insertMultiple( - updatedLocalIDs, - FileUpdationDB.modificationTimeUpdated, + final int updateCount = updatedLocalIDs.length; + updatedLocalIDs + .removeWhere((x) => trackOriginFetchForUploadOrML.get(x) ?? false); + _logger.info( + "track ${updatedLocalIDs.length}/ $updateCount files due to modification change", ); + if (updatedLocalIDs.isEmpty) { + await FileUpdationDB.instance.insertMultiple( + updatedLocalIDs, + FileUpdationDB.modificationTimeUpdated, + ); + } } } diff --git a/mobile/lib/services/sync/remote_sync_service.dart b/mobile/lib/services/sync/remote_sync_service.dart index 1706e35bee..4cee087a45 100644 --- a/mobile/lib/services/sync/remote_sync_service.dart +++ b/mobile/lib/services/sync/remote_sync_service.dart @@ -25,14 +25,13 @@ import 'package:photos/models/upload_strategy.dart'; import "package:photos/service_locator.dart"; import 'package:photos/services/app_lifecycle_service.dart'; import 'package:photos/services/collections_service.dart'; -import "package:photos/services/filedata/filedata_service.dart"; import 'package:photos/services/ignored_files_service.dart'; import "package:photos/services/language_service.dart"; import 'package:photos/services/local_file_update_service.dart'; import "package:photos/services/notification_service.dart"; -import "package:photos/services/preview_video_store.dart"; import 'package:photos/services/sync/diff_fetcher.dart'; import 'package:photos/services/sync/sync_service.dart'; +import "package:photos/services/video_preview_service.dart"; import 'package:photos/utils/file_uploader.dart'; import 'package:photos/utils/file_util.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -128,9 +127,16 @@ class RemoteSyncService { await syncDeviceCollectionFilesForUpload(); } - FileDataService.instance.syncFDStatus().then((_) { - PreviewVideoStore.instance.queueFiles(); - }).ignore(); + if ( + // Only Uploading Previews in fg to prevent heating issues + AppLifecycleService.instance.isForeground && + // if ML is enabled the MLService will queue when ML is done + !flagService.hasGrantedMLConsent) { + fileDataService.syncFDStatus().then((_) { + VideoPreviewService.instance.queueFiles(); + }).ignore(); + } + final filesToBeUploaded = await _getFilesToBeUploaded(); final hasUploadedFiles = await _uploadFiles(filesToBeUploaded); if (filesToBeUploaded.isNotEmpty) { @@ -150,8 +156,7 @@ class RemoteSyncService { if (hasMoreFilesToBackup && !_shouldThrottleSync()) { // Skipping a resync to ensure that files that were ignored in this // session are not processed now - // ignore: unawaited_futures - sync(); + await sync(); } else { _logger.info("Fire backup completed event"); Bus.instance.fire(SyncStatusUpdate(SyncStatus.completedBackup)); @@ -173,20 +178,19 @@ class RemoteSyncService { } catch (e, s) { _existingSync?.complete(); _existingSync = null; - // rethrow whitelisted error so that UI status can be updated correctly. - if (e is UnauthorizedError || - e is NoActiveSubscriptionError || - e is WiFiUnavailableError || - e is StorageLimitExceededError || - e is SyncStopRequestedError || - e is NoMediaLocationAccessError) { - _logger.warning("Error executing remote sync", e, s); + _logger.warning("Error executing remote sync", e, s); + + if (flagService.internalUser || + // rethrow whitelisted error so that UI status can be updated correctly. + { + UnauthorizedError, + NoActiveSubscriptionError, + WiFiUnavailableError, + StorageLimitExceededError, + SyncStopRequestedError, + NoMediaLocationAccessError, + }.contains(e.runtimeType)) { rethrow; - } else { - _logger.severe("Error executing remote sync ", e, s); - if (flagService.internalUser) { - rethrow; - } } } finally { _isExistingSyncSilent = false; @@ -573,7 +577,7 @@ class RemoteSyncService { _logger.info("Skipped $skippedVideos videos and $ignoredForUpload " "ignored files for upload"); } - _sortByTimeAndType(filesToBeUploaded); + _sortByTime(filesToBeUploaded); _logger.info("${filesToBeUploaded.length} new files to be uploaded."); return filesToBeUploaded; } @@ -600,6 +604,22 @@ class RemoteSyncService { await _uploader.fetchUploadURLs(toBeUploaded); } final List futures = []; + + for (final file in filesToBeUploaded) { + if (_shouldThrottleSync() && + futures.length >= kMaximumPermissibleUploadsInThrottledMode) { + _logger.info("Skipping some new files as we are throttling uploads"); + break; + } + // prefer existing collection ID for manually uploaded files. + // See https://github.com/ente-io/photos-app/pull/187 + final collectionID = file.collectionID ?? + (await _collectionsService + .getOrCreateForPath(file.deviceFolder ?? 'Unknown Folder')) + .id; + _uploadFile(file, collectionID, futures); + } + for (final uploadedFileID in updatedFileIDs) { if (_shouldThrottleSync() && futures.length >= kMaximumPermissibleUploadsInThrottledMode) { @@ -631,21 +651,6 @@ class RemoteSyncService { } } - for (final file in filesToBeUploaded) { - if (_shouldThrottleSync() && - futures.length >= kMaximumPermissibleUploadsInThrottledMode) { - _logger.info("Skipping some new files as we are throttling uploads"); - break; - } - // prefer existing collection ID for manually uploaded files. - // See https://github.com/ente-io/photos-app/pull/187 - final collectionID = file.collectionID ?? - (await _collectionsService - .getOrCreateForPath(file.deviceFolder ?? 'Unknown Folder')) - .id; - _uploadFile(file, collectionID, futures); - } - try { await Future.wait(futures); } on InvalidFileError { @@ -931,31 +936,23 @@ class RemoteSyncService { } bool _shouldThrottleSync() { - return Platform.isIOS && !AppLifecycleService.instance.isForeground; + return !flagService.enableMobMultiPart || + !localSettings.userEnabledMultiplePart; } - // _sortByTimeAndType moves videos to end and sort by creation time (desc). + // _sortByTime sort by creation time (desc). // This is done to upload most recent photo first. - void _sortByTimeAndType(List file) { + void _sortByTime(List file) { file.sort((first, second) { - if (first.fileType == second.fileType) { - return second.creationTime!.compareTo(first.creationTime!); - } else if (first.fileType == FileType.video) { - return 1; - } else { - return -1; - } - }); - // move updated files towards the end - file.sort((first, second) { - if (first.updationTime == second.updationTime) { - return 0; - } - if (first.updationTime == -1) { - return 1; - } else { - return -1; + // 1. fileType: move videos to end when in bg + if (!AppLifecycleService.instance.isForeground && + first.fileType != second.fileType) { + if (first.fileType == FileType.video) return 1; + if (second.fileType == FileType.video) return -1; } + + // 2. creationTime descending + return second.creationTime!.compareTo(first.creationTime!); }); } @@ -995,7 +992,7 @@ class RemoteSyncService { final totalCount = sharedFilesIDs.length + collectedFilesIDs.length; if (totalCount > 0) { final collection = _collectionsService.getCollectionByID(collectionID); - _logger.finest( + _logger.info( 'creating notification for ${collection?.displayName} ' 'shared: $sharedFilesIDs, collected: $collectedFilesIDs files', ); diff --git a/mobile/lib/services/sync/trash_sync_service.dart b/mobile/lib/services/sync/trash_sync_service.dart index b3cf1db6a9..b2955f22d5 100644 --- a/mobile/lib/services/sync/trash_sync_service.dart +++ b/mobile/lib/services/sync/trash_sync_service.dart @@ -32,7 +32,7 @@ class TrashSyncService { final Dio _enteDio; TrashSyncService(this._prefs, this._enteDio) { - _logger.fine("TrashSyncService constructor"); + _logger.info("TrashSyncService constructor"); } void init(SharedPreferences preferences) { @@ -42,20 +42,20 @@ class TrashSyncService { Future syncTrash() async { final lastSyncTime = _getSyncTime(); bool isLocalTrashUpdated = false; - _logger.fine('sync trash sinceTime : $lastSyncTime'); + _logger.info('sync trash sinceTime : $lastSyncTime'); final diff = await getTrashFilesDiff(lastSyncTime); if (diff.trashedFiles.isNotEmpty) { isLocalTrashUpdated = true; - _logger.fine("inserting ${diff.trashedFiles.length} items in trash"); + _logger.info("inserting ${diff.trashedFiles.length} items in trash"); await _trashDB.insertMultiple(diff.trashedFiles); } if (diff.deletedUploadIDs.isNotEmpty) { - _logger.fine("discard ${diff.deletedUploadIDs.length} deleted items"); + _logger.info("discard ${diff.deletedUploadIDs.length} deleted items"); final itemsDeleted = await _trashDB.delete(diff.deletedUploadIDs); isLocalTrashUpdated = isLocalTrashUpdated || itemsDeleted > 0; } if (diff.restoredFiles.isNotEmpty) { - _logger.fine("discard ${diff.restoredFiles.length} restored items"); + _logger.info("discard ${diff.restoredFiles.length} restored items"); final itemsDeleted = await _trashDB .delete(diff.restoredFiles.map((e) => e.uploadedFileID!).toList()); isLocalTrashUpdated = isLocalTrashUpdated || itemsDeleted > 0; @@ -94,7 +94,7 @@ class TrashSyncService { } } if (ignoredFiles.isNotEmpty) { - _logger.fine('updating ${ignoredFiles.length} ignored files '); + _logger.info('updating ${ignoredFiles.length} ignored files '); await IgnoredFilesService.instance.cacheAndInsert(ignoredFiles); } } diff --git a/mobile/lib/services/update_service.dart b/mobile/lib/services/update_service.dart index 10b5589ebd..4c7b1dc881 100644 --- a/mobile/lib/services/update_service.dart +++ b/mobile/lib/services/update_service.dart @@ -14,7 +14,7 @@ import 'package:url_launcher/url_launcher_string.dart'; class UpdateService { static const kUpdateAvailableShownTimeKey = "update_available_shown_time_key"; static const changeLogVersionKey = "update_change_log_key"; - static const currentChangeLogVersion = 28; + static const currentChangeLogVersion = 30; LatestVersionInfo? _latestVersion; final _logger = Logger("UpdateService"); diff --git a/mobile/lib/services/preview_video_store.dart b/mobile/lib/services/video_preview_service.dart similarity index 73% rename from mobile/lib/services/preview_video_store.dart rename to mobile/lib/services/video_preview_service.dart index c8e4d7aa89..785b9ca92a 100644 --- a/mobile/lib/services/preview_video_store.dart +++ b/mobile/lib/services/video_preview_service.dart @@ -10,7 +10,6 @@ import "package:ffmpeg_kit_flutter/ffmpeg_kit.dart"; import "package:ffmpeg_kit_flutter/ffmpeg_session.dart"; import "package:ffmpeg_kit_flutter/return_code.dart"; import "package:flutter/foundation.dart"; -// import "package:flutter/wid.dart"; import "package:flutter/widgets.dart"; import "package:flutter_cache_manager/flutter_cache_manager.dart"; import "package:logging/logging.dart"; @@ -21,7 +20,6 @@ import "package:photos/core/event_bus.dart"; import "package:photos/core/network/network.dart"; import 'package:photos/db/files_db.dart'; import "package:photos/db/upload_locks_db.dart"; -import "package:photos/events/preview_updated_event.dart"; import "package:photos/events/video_streaming_changed.dart"; import "package:photos/models/base/id.dart"; import "package:photos/models/ffmpeg/ffprobe_props.dart"; @@ -30,7 +28,8 @@ import "package:photos/models/file/file_type.dart"; import "package:photos/models/preview/playlist_data.dart"; import "package:photos/models/preview/preview_item.dart"; import "package:photos/models/preview/preview_item_status.dart"; -import "package:photos/services/filedata/filedata_service.dart"; +import "package:photos/service_locator.dart"; +import "package:photos/services/collections_service.dart"; import "package:photos/services/filedata/model/file_data.dart"; import "package:photos/ui/notification/toast.dart"; import "package:photos/utils/exif_util.dart"; @@ -42,26 +41,28 @@ import "package:shared_preferences/shared_preferences.dart"; const _maxRetryCount = 3; -class PreviewVideoStore { +class VideoPreviewService { + final _logger = Logger("VideoPreviewService"); final LinkedHashMap _items = LinkedHashMap(); - LinkedHashMap get previews => _items; + LinkedHashMap fileQueue = LinkedHashMap(); + final int _maxPreviewSizeLimitForCache = 50 * 1024 * 1024; // 50 MB Set? _failureFiles; - bool _initSuccess = false; + bool _hasQueuedFile = false; - PreviewVideoStore._privateConstructor(); + VideoPreviewService._privateConstructor(); - static final PreviewVideoStore instance = - PreviewVideoStore._privateConstructor(); + static final VideoPreviewService instance = + VideoPreviewService._privateConstructor(); - final _logger = Logger("PreviewVideoStore"); final cacheManager = DefaultCacheManager(); final videoCacheManager = VideoCacheManager.instance; - LinkedHashSet fileQueue = LinkedHashSet(); int uploadingFileId = -1; - final _dio = NetworkClient.instance.enteDio; + final _enteDio = NetworkClient.instance.enteDio; + final _nonEnteDio = NetworkClient.instance.getDio(); + final CollectionsService collectionsService = CollectionsService.instance; void init(SharedPreferences prefs) { _prefs = prefs; @@ -69,26 +70,18 @@ class PreviewVideoStore { late final SharedPreferences _prefs; static const String _videoStreamingEnabled = "videoStreamingEnabled"; - static const String _videoStreamingCutoff = "videoStreamingCutoff"; bool get isVideoStreamingEnabled { return _prefs.getBool(_videoStreamingEnabled) ?? false; } Future setIsVideoStreamingEnabled(bool value) async { - final oneMonthBack = DateTime.now().subtract(const Duration(days: 30)); _prefs.setBool(_videoStreamingEnabled, value).ignore(); - _prefs - .setInt( - _videoStreamingCutoff, - oneMonthBack.millisecondsSinceEpoch, - ) - .ignore(); Bus.instance.fire(VideoStreamingChanged()); if (isVideoStreamingEnabled) { - await FileDataService.instance.syncFDStatus(); - _putFilesForPreviewCreation().ignore(); + await fileDataService.syncFDStatus(); + queueFiles(duration: Duration.zero); } else { clearQueue(); } @@ -97,20 +90,12 @@ class PreviewVideoStore { void clearQueue() { fileQueue.clear(); _items.clear(); - Bus.instance.fire(PreviewUpdatedEvent(_items)); - } - - DateTime? get videoStreamingCutoff { - final milliseconds = _prefs.getInt(_videoStreamingCutoff); - if (milliseconds == null) return null; - return DateTime.fromMillisecondsSinceEpoch(milliseconds); + _hasQueuedFile = false; } Future isSharedFileStreamble(EnteFile file) async { try { - if (FileDataService.instance.previewIds - ?.containsKey(file.uploadedFileID) ?? - false) { + if (fileDataService.previewIds.containsKey(file.uploadedFileID)) { return true; } await _getPreviewUrl(file); @@ -125,7 +110,11 @@ class PreviewVideoStore { EnteFile enteFile, [ bool forceUpload = false, ]) async { - if (!isVideoStreamingEnabled) { + if (!_allowStream()) { + _logger.info( + "Pause preview due to disabledSteaming($isVideoStreamingEnabled) or computeController permission)", + ); + if (isVideoStreamingEnabled) _logger.info("No permission to run compute"); clearQueue(); return; } @@ -137,17 +126,15 @@ class PreviewVideoStore { removeFile = true; return; } - try { // check if playlist already exist - await getPlaylist(enteFile); - final _ = await _getPreviewUrl(enteFile); - - if (ctx != null && ctx.mounted) { - showShortToast(ctx, 'Video preview already exists'); + if (await getPlaylist(enteFile) != null) { + if (ctx != null && ctx.mounted) { + showShortToast(ctx, 'Video preview already exists'); + } + removeFile = true; + return; } - removeFile = true; - return; } catch (e, s) { if (e is DioException && e.response?.statusCode == 404) { _logger.info("No preview found for $enteFile"); @@ -157,7 +144,6 @@ class PreviewVideoStore { return; } } - // elimination case for <=10 MB with H.264 var (props, result, file) = await _checkFileForPreviewCreation(enteFile); if (result) { @@ -177,8 +163,7 @@ class PreviewVideoStore { : _items[enteFile.uploadedFileID!]?.retryCount ?? 0, collectionID: enteFile.collectionID ?? 0, ); - Bus.instance.fire(PreviewUpdatedEvent(_items)); - fileQueue.add(enteFile); + fileQueue[enteFile.uploadedFileID!] = enteFile; return; } @@ -191,7 +176,6 @@ class PreviewVideoStore { forceUpload ? 0 : _items[enteFile.uploadedFileID!]?.retryCount ?? 0, collectionID: enteFile.collectionID ?? 0, ); - Bus.instance.fire(PreviewUpdatedEvent(_items)); // get file file ??= await getFile(enteFile, isOrigin: true); @@ -208,14 +192,16 @@ class PreviewVideoStore { .firstWhereOrNull((e) => e["type"] == "video"); final codec = videoData["codec_name"]?.toString().toLowerCase(); - final codecIsH264 = codec?.contains("h264") ?? false; + final isH264 = codec?.contains("h264") ?? false; final bitrate = props?.duration?.inSeconds != null ? (fileSize * 8) / props!.duration!.inSeconds : null; - final colorSpace = videoData["color_space"]?.toString().toLowerCase(); - final isColorGood = colorSpace == "bt709"; + final colorTransfer = + videoData["color_transfer"]?.toString().toLowerCase(); + final isHDR = colorTransfer != null && + (colorTransfer == "smpte2084" || colorTransfer == "arib-std-b67"); // create temp file & directory for preview generation final String tempDir = Configuration.instance.getTempDirectory(); @@ -238,54 +224,61 @@ class PreviewVideoStore { FFmpegSession? session; - // case 1, if it's already a good stream - if (bitrate != null && bitrate <= 4000 * 1000 && codecIsH264) { - session = await FFmpegKit.execute( - '-i "${file.path}" ' - '-c:v copy -c:a copy ' - '-f hls -hls_time 2 -hls_flags single_file ' - '-hls_list_size 0 -hls_key_info_file ${keyinfo.path} ' - '$prefix/output.m3u8', - ); - } // case 2, if it's bitrate is good, but codec is not - else if (bitrate != null && - codec != null && - bitrate <= 2000 * 1000 && - !codecIsH264) { - session = await FFmpegKit.execute( - '-i "${file.path}" ' - '-vf "format=yuv420p10le,zscale=transfer=linear,tonemap=tonemap=hable:desat=0:peak=10,zscale=transfer=bt709:matrix=bt709:primaries=bt709,format=yuv420p" ' - '-color_primaries bt709 -color_trc bt709 -colorspace bt709 ' - '-c:v libx264 -crf 23 -preset medium ' - '-c:a aac -b:a 128k ' - '-f hls -hls_time 2 -hls_flags single_file ' - '-hls_list_size 0 -hls_key_info_file ${keyinfo.path} ' - '$prefix/output.m3u8', - ); - } // case 3, if it's color space is good - else if (colorSpace != null && isColorGood) { - session = await FFmpegKit.execute( - '-i "${file.path}" ' - '-vf "scale=-2:720,fps=30" ' - '-c:v libx264 -b:v 2000k -crf 23 -preset medium ' - '-c:a aac -b:a 128k -f hls -hls_time 2 -hls_flags single_file ' - '-hls_list_size 0 -hls_key_info_file ${keyinfo.path} ' - '$prefix/output.m3u8', - ); - } // case 4, make it compatible - else { - session = await FFmpegKit.execute( - '-i "${file.path}" ' - '-vf "scale=-2:720,fps=30,format=yuv420p10le,zscale=transfer=linear,tonemap=tonemap=hable:desat=0:peak=10,zscale=transfer=bt709:matrix=bt709:primaries=bt709,format=yuv420p" ' - '-color_primaries bt709 -color_trc bt709 -colorspace bt709 ' - '-x264-params "colorprim=bt709:transfer=bt709:colormatrix=bt709" ' - '-c:v libx264 -b:v 2000k -crf 23 -preset medium ' - '-c:a aac -b:a 128k -f hls -hls_time 2 -hls_flags single_file ' - '-hls_list_size 0 -hls_key_info_file ${keyinfo.path} ' - '$prefix/output.m3u8', - ); + final reencodeVideo = + !(isH264 && bitrate != null && bitrate <= 4000 * 1000); + final rescaleVideo = !(bitrate != null && bitrate <= 2000 * 1000); + final needsTonemap = isHDR; + final applyFPS = (double.tryParse(props?.fps ?? "") ?? 100) > 30; + + String filters = ""; + + if (reencodeVideo) { + final videoFilters = []; + + if (rescaleVideo || needsTonemap) { + // scale video to 720p or keep original height if less than 720p + videoFilters.add("scale=-2:'min(720,ih)'"); + + // reduce fps to 30 if it is more than 30 + if (applyFPS) videoFilters.add("fps=30"); + } + + if (needsTonemap) { + // apply tonemapping for HDR videos + videoFilters.addAll([ + 'zscale=transfer=linear', + 'tonemap=tonemap=hable:desat=0', + 'zscale=primaries=709:transfer=709:matrix=709', + ]); + } + + videoFilters.add("format=yuv420p"); + + filters = '-vf "${videoFilters.join(",")}" '; } + final command = + // scaling, fps, tonemapping + '$filters' + // video encoding + '${reencodeVideo ? '-c:v libx264 -crf 23 -preset medium ' : '-c:v copy '}' + // audio encoding + '-c:a aac -b:a 128k ' + // hls options + '-f hls -hls_flags single_file ' + '-hls_list_size 0 -hls_key_info_file ${keyinfo.path} '; + + _logger.info(command); + + session = await FFmpegKit.execute( + // input file path + '-i "${file.path}" ' + + // main params for streaming + command + + // output file path + '$prefix/output.m3u8', + ); + final returnCode = await session.getReturnCode(); String? objectId; @@ -299,7 +292,6 @@ class PreviewVideoStore { collectionID: enteFile.collectionID ?? 0, retryCount: _items[enteFile.uploadedFileID!]?.retryCount ?? 0, ); - Bus.instance.fire(PreviewUpdatedEvent(_items)); _logger.info('Playlist Generated ${enteFile.displayName}'); @@ -357,7 +349,7 @@ class PreviewVideoStore { if (error == null) { // update previewIds - FileDataService.instance.appendPreview( + fileDataService.appendPreview( enteFile.uploadedFileID!, objectId!, objectSize!, @@ -371,17 +363,14 @@ class PreviewVideoStore { ); _removeFromLocks(enteFile).ignore(); Directory(prefix).delete(recursive: true).ignore(); - - Bus.instance.fire(PreviewUpdatedEvent(_items)); } } finally { + computeController.releaseCompute(stream: true); if (error != null) { _retryFile(enteFile, error); - Bus.instance.fire(PreviewUpdatedEvent(_items)); } else if (removeFile) { _removeFile(enteFile); _removeFromLocks(enteFile).ignore(); - Bus.instance.fire(PreviewUpdatedEvent(_items)); } // reset uploading status if this was getting processed if (uploadingFileId == enteFile.uploadedFileID!) { @@ -390,8 +379,9 @@ class PreviewVideoStore { _logger.info("[chunk] Processing ${_items.length} items for streaming"); // process next file if (fileQueue.isNotEmpty) { - final file = fileQueue.first; - fileQueue.remove(file); + final entry = fileQueue.entries.first; + final file = entry.value; + fileQueue.remove(entry.key); await chunkAndUploadVideo(ctx, file); } } @@ -420,7 +410,7 @@ class PreviewVideoStore { retryCount: _items[enteFile.uploadedFileID!]!.retryCount + 1, collectionID: enteFile.collectionID ?? 0, ); - fileQueue.add(enteFile); + fileQueue[enteFile.uploadedFileID!] = enteFile; } else { _items[enteFile.uploadedFileID!] = PreviewItem( status: PreviewItemStatus.failed, @@ -470,7 +460,7 @@ class PreviewVideoStore { }, encryptionKey, ); - final _ = await _dio.put( + final _ = await _enteDio.put( "/files/video-data", data: { "fileID": file.uploadedFileID!, @@ -489,7 +479,7 @@ class PreviewVideoStore { Future<(String, int)> _uploadPreviewVideo(EnteFile file, File preview) async { _logger.info("Pushing preview for $file"); try { - final response = await _dio.get( + final response = await _enteDio.get( "/files/data/preview-upload-url", queryParameters: { "fileID": file.uploadedFileID!, @@ -499,7 +489,7 @@ class PreviewVideoStore { final uploadURL = response.data["url"]; final String objectID = response.data["objectID"]; final objectSize = preview.lengthSync(); - final _ = await _dio.put( + final _ = await _enteDio.put( uploadURL, data: preview.openRead(), options: Options( @@ -537,7 +527,7 @@ class PreviewVideoStore { try { late final String objectID; final PreviewInfo? previewInfo = - FileDataService.instance.previewIds?[file.uploadedFileID!]; + fileDataService.previewIds[file.uploadedFileID!]; bool shouldAppendPreview = false; (String, String)? previewURLResult; if (previewInfo == null) { @@ -564,21 +554,7 @@ class PreviewVideoStore { size = details["size"]; } } else { - final response = await _dio.get( - "/files/data/fetch/", - queryParameters: { - "fileID": file.uploadedFileID, - "type": "vid_preview", - }, - ); - final encryptedData = response.data["data"]["encryptedData"]; - final header = response.data["data"]["decryptionHeader"]; - final encryptionKey = getFileKey(file); - final playlistData = await decryptAndUnzipJson( - encryptionKey, - encryptedData: encryptedData, - header: header, - ); + final Map playlistData = await _getPlaylistData(file); finalPlaylist = playlistData["playlist"]; width = playlistData["width"]; height = playlistData["height"]; @@ -609,12 +585,14 @@ class PreviewVideoStore { ?.file; if (videoFile == null) { previewURLResult = previewURLResult ?? await _getPreviewUrl(file); - unawaited( - videoCacheManager.downloadFile( - previewURLResult.$1, - key: _getVideoPreviewKey(objectID), - ), - ); + if (size != null && size < _maxPreviewSizeLimitForCache) { + unawaited( + videoCacheManager.downloadFile( + previewURLResult.$1, + key: _getVideoPreviewKey(objectID), + ), + ); + } finalPlaylist = finalPlaylist.replaceAll('\noutput.ts', '\n${previewURLResult.$1}'); } else { @@ -639,7 +617,7 @@ class PreviewVideoStore { durationInSeconds: parseDurationFromHLS(finalPlaylist), ); if (shouldAppendPreview) { - FileDataService.instance.appendPreview( + fileDataService.appendPreview( file.uploadedFileID!, objectID, size!, @@ -651,6 +629,40 @@ class PreviewVideoStore { } } + Future> _getPlaylistData(EnteFile file) async { + late Response response; + if (collectionsService.isSharedPublicLink(file.collectionID!)) { + response = await _nonEnteDio.get( + "${Configuration.instance.getHttpEndpoint()}/public-collection/files/data/fetch/", + queryParameters: { + "fileID": file.uploadedFileID, + "type": "vid_preview", + }, + options: Options( + headers: + collectionsService.publicCollectionHeaders(file.collectionID!), + ), + ); + } else { + response = await _enteDio.get( + "/files/data/fetch/", + queryParameters: { + "fileID": file.uploadedFileID, + "type": "vid_preview", + }, + ); + } + final encryptedData = response.data["data"]["encryptedData"]; + final header = response.data["data"]["decryptionHeader"]; + final encryptionKey = getFileKey(file); + final playlistData = await decryptAndUnzipJson( + encryptionKey, + encryptedData: encryptedData, + header: header, + ); + return playlistData; + } + int? parseDurationFromHLS(String playlist) { final lines = playlist.split("\n"); double totalDuration = 0.0; @@ -672,16 +684,32 @@ class PreviewVideoStore { Future<(String, String)> _getPreviewUrl(EnteFile file) async { try { - final response = await _dio.get( - "/files/data/preview", - queryParameters: { - "fileID": file.uploadedFileID, - "type": - file.fileType == FileType.video ? "vid_preview" : "img_preview", - }, - ); - - final url = (response.data["url"] as String); + late String url; + if (collectionsService.isSharedPublicLink(file.collectionID!)) { + final response = await _nonEnteDio.get( + "${Configuration.instance.getHttpEndpoint()}/public-collection/files/data/preview", + queryParameters: { + "fileID": file.uploadedFileID, + "type": + file.fileType == FileType.video ? "vid_preview" : "img_preview", + }, + options: Options( + headers: + collectionsService.publicCollectionHeaders(file.collectionID!), + ), + ); + url = (response.data["url"] as String); + } else { + final response = await _enteDio.get( + "/files/data/preview", + queryParameters: { + "fileID": file.uploadedFileID, + "type": + file.fileType == FileType.video ? "vid_preview" : "img_preview", + }, + ); + url = (response.data["url"] as String); + } final uri = Uri.parse(url); final segments = uri.pathSegments; if (segments.isEmpty) throw Exception("Invalid URL"); @@ -696,20 +724,37 @@ class PreviewVideoStore { Future<(FFProbeProps?, bool, File?)> _checkFileForPreviewCreation( EnteFile enteFile, ) async { - final fileSize = enteFile.fileSize; + if ((enteFile.pubMagicMetadata?.sv ?? 0) == 1) { + _logger.info( + "Skip Preview due to sv=1 for ${enteFile.displayName}", + ); + return (null, true, null); + } + if (enteFile.fileSize == null || enteFile.duration == null) { + _logger.warning( + "Skip Preview due to misisng size/duration for ${enteFile.displayName}", + ); + return (null, true, null); + } + final int size = enteFile.fileSize!; + final int duration = enteFile.duration!; + if (size >= 500 * 1024 * 1024 || duration > 60) { + _logger.info( + "Skip Preview due to size: $size or duration: $duration", + ); + return (null, true, null); + } FFProbeProps? props; File? file; bool skipFile = false; - try { - final isFileUnder10MB = fileSize != null && fileSize <= 10 * 1024 * 1024; + final isFileUnder10MB = size <= 10 * 1024 * 1024; if (isFileUnder10MB) { file = await getFile(enteFile, isOrigin: true); if (file != null) { props = await getVideoPropsAsync(file); final videoData = List.from(props?.propData?["streams"] ?? []) .firstWhereOrNull((e) => e["type"] == "video"); - final codec = videoData["codec_name"]?.toString().toLowerCase(); skipFile = codec?.contains("h264") ?? false; @@ -721,28 +766,6 @@ class PreviewVideoStore { } } } - - int? size = enteFile.fileSize; - int? duration = enteFile.duration; - - if (size == null) { - file = await getFile(enteFile, isOrigin: true); - size = file?.lengthSync(); - } - - if (duration == null) { - file ??= await getFile(enteFile, isOrigin: true); - props = await getVideoPropsAsync(file!); - duration = props?.duration?.inSeconds; - } - - if ((size == null || duration == null) || - (size >= 500 * 1024 * 1024 || duration > 60)) { - skipFile = true; - _logger.info( - "[init] Ignoring file ${enteFile.displayName} for preview due to size: $size and duration: $duration", - ); - } } catch (e, sT) { _logger.warning("Failed to check props", e, sT); } @@ -753,9 +776,7 @@ class PreviewVideoStore { Future _putFilesForPreviewCreation([bool updateInit = false]) async { if (!isVideoStreamingEnabled || !await canUseHighBandwidth()) return; - final cutoff = videoStreamingCutoff; - if (cutoff == null) return; - if (updateInit) _initSuccess = true; + if (updateInit) _hasQueuedFile = true; Map failureFiles = {}; try { @@ -764,7 +785,7 @@ class PreviewVideoStore { // handle case when failures are already previewed for (final failure in _failureFiles!) { - if (previews.containsKey(failure)) { + if (_items.containsKey(failure)) { UploadLocksDB.instance.deleteStreamUploadErrorEntry(failure).ignore(); } } @@ -772,32 +793,22 @@ class PreviewVideoStore { final files = await FilesDB.instance.getAllFilesAfterDate( fileType: FileType.video, - beginDate: cutoff, + beginDate: DateTime.now().subtract( + const Duration(days: 30), + ), userID: Configuration.instance.getUserID()!, ); - final previewIds = FileDataService.instance.previewIds; - final allFiles = files - .where((file) => previewIds?[file.uploadedFileID] == null) - .sorted((a, b) { - // put higher duration videos last along with remote files - final first = (a.localID == null ? 2 : 0) + - (a.duration == null || a.duration! >= 10 * 60 ? 1 : 0); - final second = (b.localID == null ? 2 : 0) + - (b.duration == null || b.duration! >= 10 * 60 ? 1 : 0); - return first.compareTo(second); - }).toList(); + final previewIds = fileDataService.previewIds; + final allFiles = + files.where((file) => previewIds[file.uploadedFileID] == null).toList(); // set all video status to in queue var n = allFiles.length, i = 0; while (i < n) { final enteFile = allFiles[i]; - - // elimination case for <=10 MB with H.264 - final (_, result, _) = await _checkFileForPreviewCreation(enteFile); final isFailure = _failureFiles?.contains(enteFile.uploadedFileID!) ?? false; - if (isFailure) { _items[enteFile.uploadedFileID!] = PreviewItem( status: PreviewItemStatus.failed, @@ -807,7 +818,7 @@ class PreviewVideoStore { error: failureFiles[enteFile.uploadedFileID!], ); } - if (result || isFailure) { + if (isFailure) { _logger.info( "[init] Ignoring file ${enteFile.displayName} for preview", ); @@ -825,7 +836,6 @@ class PreviewVideoStore { i++; } - Bus.instance.fire(PreviewUpdatedEvent(_items)); if (allFiles.isEmpty) { _logger.info("[init] No preview to cache"); return; @@ -835,15 +845,27 @@ class PreviewVideoStore { // take first file and put it for stream generation final file = allFiles.removeAt(0); - fileQueue.addAll(allFiles); + for (final enteFile in allFiles) { + if (_items.containsKey(enteFile.uploadedFileID!)) { + continue; + } + fileQueue[enteFile.uploadedFileID!] = enteFile; + } chunkAndUploadVideo(null, file).ignore(); } - void queueFiles() { - if (!_initSuccess) { - _putFilesForPreviewCreation(true).catchError((_) { - _initSuccess = false; - }); - } + bool _allowStream() { + return isVideoStreamingEnabled && + computeController.requestCompute(stream: true); + } + + void queueFiles({Duration duration = const Duration(seconds: 5)}) { + Future.delayed(duration, () { + if (!_hasQueuedFile && _allowStream()) { + _putFilesForPreviewCreation(true).catchError((_) { + _hasQueuedFile = false; + }); + } + }); } } diff --git a/mobile/lib/states/all_sections_examples_state.dart b/mobile/lib/states/all_sections_examples_state.dart index 2a9482f63f..a652dcdcfb 100644 --- a/mobile/lib/states/all_sections_examples_state.dart +++ b/mobile/lib/states/all_sections_examples_state.dart @@ -79,7 +79,7 @@ class _AllSectionsExamplesProviderState void onDataUpdate() { if (!isOnSearchTab) { if (kDebugMode) { - _logger.finest('Skip reload till user clicks on search tab'); + _logger.info('Skip reload till user clicks on search tab'); } hasPendingUpdate = true; } else { diff --git a/mobile/lib/ui/actions/collection/collection_sharing_actions.dart b/mobile/lib/ui/actions/collection/collection_sharing_actions.dart index 0583798dcf..e210b7df72 100644 --- a/mobile/lib/ui/actions/collection/collection_sharing_actions.dart +++ b/mobile/lib/ui/actions/collection/collection_sharing_actions.dart @@ -115,7 +115,7 @@ class CollectionActions { try { // create album with emptyName, use collectionCreationTime on UI to // show name - logger.finest("creating album for sharing files"); + logger.info("creating album for sharing files"); final EnteFile fileWithMinCreationTime = files.reduce( (a, b) => (a.creationTime ?? 0) < (b.creationTime ?? 0) ? a : b, ); @@ -136,9 +136,9 @@ class CollectionActions { req, ); newCollection = collection; - logger.finest("adding files to share to new album"); + logger.info("adding files to share to new album"); await collectionsService.addOrCopyToCollection(collection.id, files); - logger.finest("creating public link for the newly created album"); + logger.info("creating public link for the newly created album"); try { await CollectionsService.instance.createShareUrl(collection); } catch (e) { diff --git a/mobile/lib/ui/actions/file/file_actions.dart b/mobile/lib/ui/actions/file/file_actions.dart index 60dfeaf739..8a85125c70 100644 --- a/mobile/lib/ui/actions/file/file_actions.dart +++ b/mobile/lib/ui/actions/file/file_actions.dart @@ -2,6 +2,8 @@ import "dart:async"; import "package:flutter/cupertino.dart"; import "package:modal_bottom_sheet/modal_bottom_sheet.dart"; +import "package:photos/core/event_bus.dart"; +import "package:photos/events/details_sheet_event.dart"; import "package:photos/generated/l10n.dart"; import 'package:photos/models/file/file.dart'; import 'package:photos/models/file/file_type.dart'; @@ -138,7 +140,14 @@ Future showSingleFileDeleteSheet( Future showDetailsSheet(BuildContext context, EnteFile file) async { guardedCheckPanorama(file).ignore(); final colorScheme = getEnteColorScheme(context); - return showBarModalBottomSheet( + Bus.instance.fire( + DetailsSheetEvent( + localID: file.localID, + uploadedFileID: file.uploadedFileID, + opened: true, + ), + ); + await showBarModalBottomSheet( topControl: const SizedBox.shrink(), shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical( @@ -156,4 +165,11 @@ Future showDetailsSheet(BuildContext context, EnteFile file) async { ); }, ); + Bus.instance.fire( + DetailsSheetEvent( + localID: file.localID, + uploadedFileID: file.uploadedFileID, + opened: false, + ), + ); } diff --git a/mobile/lib/ui/collections/album/column_item.dart b/mobile/lib/ui/collections/album/column_item.dart index bf793d7214..1f52772790 100644 --- a/mobile/lib/ui/collections/album/column_item.dart +++ b/mobile/lib/ui/collections/album/column_item.dart @@ -10,7 +10,7 @@ import "package:photos/ui/components/buttons/icon_button_widget.dart"; import 'package:photos/ui/viewer/file/no_thumbnail_widget.dart'; import 'package:photos/ui/viewer/file/thumbnail_widget.dart'; -///https://www.figma.com/file/SYtMyLBs5SAOkTbfMMzhqt/ente-Visual-Design?node-id=7480%3A33462&t=H5AvR79OYDnB9ekw-4 +///https://www.figma.com/design/SYtMyLBs5SAOkTbfMMzhqt/Ente-Visual-Design?node-id=39181-172145&t=3qmSZWpXF3ZC4JGN-1 class AlbumColumnItemWidget extends StatelessWidget { final Collection collection; final List selectedCollections; @@ -36,7 +36,7 @@ class AlbumColumnItemWidget extends StatelessWidget { isSelected ? colorScheme.strokeMuted : colorScheme.strokeFainter, ), borderRadius: const BorderRadius.all( - Radius.circular(4), + Radius.circular(6), ), ), child: Row( @@ -47,9 +47,7 @@ class AlbumColumnItemWidget extends StatelessWidget { child: Row( children: [ ClipRRect( - borderRadius: const BorderRadius.horizontal( - left: Radius.circular(4), - ), + borderRadius: BorderRadius.circular(4), child: SizedBox( height: sideOfThumbnail, width: sideOfThumbnail, @@ -66,7 +64,7 @@ class AlbumColumnItemWidget extends StatelessWidget { ); } else { return const NoThumbnailWidget( - addBorder: false, + addBorder: false, ); } }, @@ -94,9 +92,7 @@ class AlbumColumnItemWidget extends StatelessWidget { snapshot.data!, NumberFormat().format(snapshot.data!), ), - style: textTheme.small.copyWith( - color: colorScheme.textMuted, - ), + style: textTheme.miniMuted, ); } else { if (snapshot.hasError) { diff --git a/mobile/lib/ui/collections/album/horizontal_list.dart b/mobile/lib/ui/collections/album/horizontal_list.dart index 53ea3232e0..fff5e67b7d 100644 --- a/mobile/lib/ui/collections/album/horizontal_list.dart +++ b/mobile/lib/ui/collections/album/horizontal_list.dart @@ -1,4 +1,5 @@ import "dart:async"; +import "dart:math"; import "package:flutter/cupertino.dart"; import "package:logging/logging.dart"; @@ -29,6 +30,10 @@ class _AlbumHorizontalListState extends State { _collectionUpdatesSubscription; late Logger _logger; + static const maxThumbnailWidth = 224.0; + static const crossAxisSpacing = 8.0; + static const horizontalPadding = 16.0; + @override void initState() { super.initState(); @@ -47,6 +52,12 @@ class _AlbumHorizontalListState extends State { @override Widget build(BuildContext context) { + final double screenWidth = MediaQuery.sizeOf(context).width; + final int albumsCountInRow = max(screenWidth ~/ maxThumbnailWidth, 3); + final totalHorizontalPadding = (albumsCountInRow - 1) * crossAxisSpacing; + final sideOfThumbnail = + (screenWidth - totalHorizontalPadding - horizontalPadding) / + albumsCountInRow; debugPrint('$runtimeType widget build'); return FutureBuilder>( future: widget.collectionsFuture(), @@ -75,20 +86,25 @@ class _AlbumHorizontalListState extends State { Align( alignment: Alignment.centerLeft, child: SizedBox( - height: 147, //139 + 8 (calculated from figma design) - child: ListView.separated( - separatorBuilder: (context, index) => - const SizedBox(width: 4), + height: sideOfThumbnail + 46, + child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: collections.length, - padding: const EdgeInsets.symmetric(horizontal: 8), + padding: const EdgeInsets.symmetric( + horizontal: horizontalPadding / 2, + ), itemBuilder: (context, index) { final item = collections[index]; - return AlbumRowItemWidget( - item, - 120, - showFileCount: false, - hasVerifiedLock: widget.hasVerifiedLock, + return Padding( + padding: const EdgeInsets.only( + right: horizontalPadding / 2, + ), + child: AlbumRowItemWidget( + item, + sideOfThumbnail, + showFileCount: true, + hasVerifiedLock: widget.hasVerifiedLock, + ), ); }, ), diff --git a/mobile/lib/ui/collections/album/list_item.dart b/mobile/lib/ui/collections/album/list_item.dart index 255d6de147..fb2690af4a 100644 --- a/mobile/lib/ui/collections/album/list_item.dart +++ b/mobile/lib/ui/collections/album/list_item.dart @@ -36,9 +36,7 @@ class AlbumListItemWidget extends StatelessWidget { child: Row( children: [ ClipRRect( - borderRadius: const BorderRadius.horizontal( - left: Radius.circular(4), - ), + borderRadius: BorderRadius.circular(4), child: SizedBox( height: sideOfThumbnail, width: sideOfThumbnail, @@ -53,7 +51,9 @@ class AlbumListItemWidget extends StatelessWidget { shouldShowOwnerAvatar: false, ); } else { - return const NoThumbnailWidget(addBorder: false); + return const NoThumbnailWidget( + addBorder: false, + ); } }, ), @@ -63,13 +63,15 @@ class AlbumListItemWidget extends StatelessWidget { Flexible( child: Column( crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, children: [ Text( collection.displayName, overflow: TextOverflow.ellipsis, ), FutureBuilder( - future: CollectionsService.instance.getFileCount(collection), + future: + CollectionsService.instance.getFileCount(collection), builder: (context, snapshot) { if (snapshot.hasData) { return Text( @@ -123,7 +125,7 @@ class AlbumListItemWidget extends StatelessWidget { ? colorScheme.strokeMuted : colorScheme.strokeFainter, ), - borderRadius: const BorderRadius.all(Radius.circular(4)), + borderRadius: const BorderRadius.all(Radius.circular(6)), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/mobile/lib/ui/collections/album/new_list_item.dart b/mobile/lib/ui/collections/album/new_list_item.dart index 735946f223..4277074552 100644 --- a/mobile/lib/ui/collections/album/new_list_item.dart +++ b/mobile/lib/ui/collections/album/new_list_item.dart @@ -3,7 +3,8 @@ import 'package:flutter/material.dart'; import "package:photos/generated/l10n.dart"; import 'package:photos/theme/ente_theme.dart'; -///https://www.figma.com/file/SYtMyLBs5SAOkTbfMMzhqt/ente-Visual-Design?node-id=10854%3A57947&t=H5AvR79OYDnB9ekw-4 +//https://www.figma.com/design/SYtMyLBs5SAOkTbfMMzhqt/Ente-Visual-Design?node-id=39181-172209&t=3qmSZWpXF3ZC4JGN-1 + class NewAlbumListItemWidget extends StatelessWidget { const NewAlbumListItemWidget({ super.key, @@ -22,12 +23,13 @@ class NewAlbumListItemWidget extends StatelessWidget { Row( children: [ ClipRRect( - borderRadius: const BorderRadius.horizontal( - left: Radius.circular(4), - ), - child: SizedBox( + borderRadius: BorderRadius.circular(4), + child: Container( height: sideOfThumbnail, width: sideOfThumbnail, + color: Theme.of(context).brightness == Brightness.light + ? colorScheme.backdropBase + : colorScheme.backdropFaint, child: Icon( Icons.add_outlined, color: colorScheme.strokeMuted, diff --git a/mobile/lib/ui/collections/album/new_row_item.dart b/mobile/lib/ui/collections/album/new_row_item.dart index 3e000cd12d..e9e4409ac3 100644 --- a/mobile/lib/ui/collections/album/new_row_item.dart +++ b/mobile/lib/ui/collections/album/new_row_item.dart @@ -23,6 +23,7 @@ class NewAlbumRowItemWidget extends StatelessWidget { @override Widget build(BuildContext context) { + final colorScheme = getEnteColorScheme(context); return GestureDetector( onTap: () async { final result = await showTextInputDialog( @@ -35,13 +36,18 @@ class NewAlbumRowItemWidget extends StatelessWidget { textCapitalization: TextCapitalization.words, popnavAfterSubmission: true, onSubmit: (String text) async { - if (text.trim() == "") { + text = text.trim(); + if (text == "") { return; } try { final Collection c = await CollectionsService.instance.createAlbum(text); + + // Close the dialog now so that it does not flash when leaving the album again. + Navigator.of(context).pop(); + // ignore: unawaited_futures await routeToPage( context, @@ -62,25 +68,31 @@ class NewAlbumRowItemWidget extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox( - height: height, - width: width, - child: DottedBorder( - borderType: BorderType.RRect, - strokeWidth: 1.5, - dashPattern: const [3.75, 3.75], - radius: const Radius.circular(2.35), - padding: EdgeInsets.zero, - color: getEnteColorScheme(context).strokeMuted, - child: Center( - child: Icon( - Icons.add, - color: getEnteColorScheme(context).strokeMuted, + ClipRRect( + borderRadius: BorderRadius.circular(12), + child: Container( + height: height, + width: width, + color: Theme.of(context).brightness == Brightness.light + ? colorScheme.backdropBase + : colorScheme.backdropFaint, + child: DottedBorder( + borderType: BorderType.RRect, + strokeWidth: 1.75, + dashPattern: const [3.75, 3.75], + radius: const Radius.circular(12), + padding: EdgeInsets.zero, + color: colorScheme.strokeFaint, + child: Center( + child: Icon( + Icons.add, + color: colorScheme.strokeFaint, + ), ), ), ), ), - const SizedBox(height: 4), + const SizedBox(height: 6), Text( S.of(context).addNew, style: getEnteTextTheme(context).smallFaint, diff --git a/mobile/lib/ui/collections/album/row_item.dart b/mobile/lib/ui/collections/album/row_item.dart index 5467a27a53..ffaaf04421 100644 --- a/mobile/lib/ui/collections/album/row_item.dart +++ b/mobile/lib/ui/collections/album/row_item.dart @@ -1,3 +1,4 @@ +import "package:figma_squircle/figma_squircle.dart"; import 'package:flutter/material.dart'; import "package:intl/intl.dart"; import "package:photos/core/configuration.dart"; @@ -24,6 +25,9 @@ class AlbumRowItemWidget extends StatelessWidget { final void Function(Collection)? onTapCallback; final void Function(Collection)? onLongPressCallback; final SelectedAlbums? selectedAlbums; + static const _borderWidth = 1.0; + static const _cornerRadius = 12.0; + static const _cornerSmoothing = 1.0; const AlbumRowItemWidget( this.c, @@ -56,125 +60,152 @@ class AlbumRowItemWidget extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Stack( - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(1), - child: SizedBox( - height: sideOfThumbnail, - width: sideOfThumbnail, - child: Stack( - children: [ - FutureBuilder( - future: CollectionsService.instance.getCover(c), - builder: (context, snapshot) { - EnteFile? thumbnail; - if (snapshot.hasData) { - thumbnail = snapshot.data!; - } else { - //Need to use cached thumbnail so that the hero - //animation works as expected. - thumbnail = - CollectionsService.instance.getCoverCache(c); - } - if (thumbnail != null) { - final bool isSelected = - selectedAlbums?.isAlbumSelected(c) ?? false; - final String heroTag = tagPrefix + thumbnail.tag; - final thumbnailWidget = ThumbnailWidget( - thumbnail, - shouldShowArchiveStatus: isOwner - ? c.isArchived() - : c.hasShareeArchived(), - showFavForAlbumOnly: true, - shouldShowSyncStatus: false, - shouldShowPinIcon: isOwner && c.isPinned, - key: Key(heroTag), - ); - return Hero( - tag: heroTag, - transitionOnUserGestures: true, - child: isSelected - ? ColorFiltered( - colorFilter: ColorFilter.mode( - Colors.black.withOpacity( - 0.4, - ), - BlendMode.darken, - ), - child: thumbnailWidget, - ) - : thumbnailWidget, - ); - } else { - return const NoThumbnailWidget(); - } - }, - ), - if (isOwner && (c.hasSharees || c.hasLink)) - Hero( - tag: tagPrefix + "_sharees", - transitionOnUserGestures: true, - child: Align( - alignment: Alignment.topLeft, - child: AlbumSharesIcons( - padding: const EdgeInsets.only(left: 4, top: 4), - sharees: c.getSharees(), - type: AvatarType.mini, - trailingWidget: linkIcon, - ), - ), - ), - Positioned( - top: 5, - right: 5, - child: Hero( - tag: tagPrefix + "_album_selection", - transitionOnUserGestures: true, - child: ListenableBuilder( - listenable: selectedAlbums ?? ValueNotifier(false), - builder: (context, _) { + SizedBox( + height: sideOfThumbnail, + width: sideOfThumbnail, + child: Stack( + clipBehavior: Clip.none, + alignment: Alignment.center, + children: [ + ClipSmoothRect( + radius: SmoothBorderRadius( + cornerRadius: _cornerRadius + _borderWidth, + cornerSmoothing: _cornerSmoothing, + ), + child: Container( + color: getEnteColorScheme(context).strokeFaint, + width: sideOfThumbnail, + height: sideOfThumbnail, + ), + ), + ClipSmoothRect( + radius: SmoothBorderRadius( + cornerRadius: _cornerRadius, + cornerSmoothing: _cornerSmoothing, + ), + child: SizedBox( + height: sideOfThumbnail - _borderWidth * 2, + width: sideOfThumbnail - _borderWidth * 2, + child: Stack( + children: [ + FutureBuilder( + future: CollectionsService.instance.getCover(c), + builder: (context, snapshot) { + EnteFile? thumbnail; + if (snapshot.hasData) { + thumbnail = snapshot.data!; + } else { + //Need to use cached thumbnail so that the hero + //animation works as expected. + thumbnail = + CollectionsService.instance.getCoverCache(c); + } + if (thumbnail != null) { final bool isSelected = selectedAlbums?.isAlbumSelected(c) ?? false; - return AnimatedSwitcher( - duration: const Duration(milliseconds: 200), - switchInCurve: Curves.easeOut, - switchOutCurve: Curves.easeIn, - child: isSelected - ? const Icon( - Icons.check_circle_rounded, - color: Colors.white, - size: 22, - ) - : null, + final String heroTag = tagPrefix + thumbnail.tag; + final thumbnailWidget = ThumbnailWidget( + thumbnail, + shouldShowArchiveStatus: isOwner + ? c.isArchived() + : c.hasShareeArchived(), + showFavForAlbumOnly: true, + shouldShowSyncStatus: false, + shouldShowPinIcon: isOwner && c.isPinned, + key: Key(heroTag), ); - }, - ), + return Hero( + tag: heroTag, + transitionOnUserGestures: true, + child: isSelected + ? ColorFiltered( + colorFilter: ColorFilter.mode( + Colors.black.withOpacity( + 0.4, + ), + BlendMode.darken, + ), + child: thumbnailWidget, + ) + : thumbnailWidget, + ); + } else { + return Container( + color: getEnteColorScheme(context).backdropBase, + child: const NoThumbnailWidget( + borderRadius: 12, + addBorder: false, + ), + ); + } + }, ), - ), - if (!isOwner) - Align( - alignment: Alignment.bottomRight, - child: Hero( - tag: tagPrefix + "_owner_other", + if (isOwner && (c.hasSharees || c.hasLink)) + Hero( + tag: tagPrefix + "_sharees", transitionOnUserGestures: true, - child: Padding( - padding: - const EdgeInsets.only(right: 4, bottom: 4), - child: UserAvatarWidget( - c.owner, - thumbnailView: true, + child: Align( + alignment: Alignment.topLeft, + child: AlbumSharesIcons( + padding: const EdgeInsets.only(left: 4, top: 4), + sharees: c.getSharees(), + type: AvatarType.mini, + trailingWidget: linkIcon, ), ), ), + Positioned( + top: 5, + right: 5, + child: Hero( + tag: tagPrefix + "_album_selection", + transitionOnUserGestures: true, + child: ListenableBuilder( + listenable: + selectedAlbums ?? ValueNotifier(false), + builder: (context, _) { + final bool isSelected = + selectedAlbums?.isAlbumSelected(c) ?? false; + return AnimatedSwitcher( + duration: const Duration(milliseconds: 200), + switchInCurve: Curves.easeOut, + switchOutCurve: Curves.easeIn, + child: isSelected + ? const Icon( + Icons.check_circle_rounded, + color: Colors.white, + size: 22, + ) + : null, + ); + }, + ), + ), ), - ], + if (!isOwner) + Align( + alignment: Alignment.bottomRight, + child: Hero( + tag: tagPrefix + "_owner_other", + transitionOnUserGestures: true, + child: Padding( + padding: + const EdgeInsets.only(right: 4, bottom: 4), + child: UserAvatarWidget( + c.owner, + thumbnailView: true, + ), + ), + ), + ), + ], + ), ), ), - ), - ], + ], + ), ), - const SizedBox(height: 4), + const SizedBox(height: 6), Hero( tag: tagPrefix + "_title", transitionOnUserGestures: true, @@ -214,7 +245,7 @@ class AlbumRowItemWidget extends StatelessWidget { const SizedBox(height: 2), RichText( text: TextSpan( - style: enteTextTheme.tinyMuted, + style: enteTextTheme.miniMuted, children: [ TextSpan(text: textCount), ], diff --git a/mobile/lib/ui/collections/album/vertical_list.dart b/mobile/lib/ui/collections/album/vertical_list.dart index 321b62e9b9..7704b5ead3 100644 --- a/mobile/lib/ui/collections/album/vertical_list.dart +++ b/mobile/lib/ui/collections/album/vertical_list.dart @@ -5,6 +5,7 @@ import "package:flutter/services.dart"; import 'package:logging/logging.dart'; import 'package:photos/core/configuration.dart'; import "package:photos/core/event_bus.dart"; +import "package:photos/events/create_new_album_event.dart"; import "package:photos/events/tab_changed_event.dart"; import "package:photos/generated/l10n.dart"; import 'package:photos/models/collection/collection.dart'; @@ -183,31 +184,35 @@ class _AlbumVerticalListWidgetState extends State { } if (collection != null) { - if (await _runCollectionAction( - context, - collection, - showProgressDialog: false, - )) { - if (widget.actionType == CollectionActionType.restoreFiles) { - showShortToast( - context, - 'Restored files to album ' + albumName, - ); - } else { - showShortToast( - context, - "Album '" + albumName + "' created.", - ); - } - - Navigator.pop(context); - Navigator.pop(context); - - await _navigateToCollection( + if (widget.enableSelection) { + Bus.instance.fire(CreateNewAlbumEvent(collection)); + } else { + if (await _runCollectionAction( context, collection, - hasVerifiedLock: hasVerifiedLock, - ); + showProgressDialog: false, + )) { + if (widget.actionType == CollectionActionType.restoreFiles) { + showShortToast( + context, + 'Restored files to album ' + albumName, + ); + } else { + showShortToast( + context, + "Album '" + albumName + "' created.", + ); + } + + Navigator.pop(context); + Navigator.pop(context); + + await _navigateToCollection( + context, + collection, + hasVerifiedLock: hasVerifiedLock, + ); + } } } } @@ -290,8 +295,6 @@ class _AlbumVerticalListWidgetState extends State { return _restoreFilesToCollection(context, collection.id); case CollectionActionType.shareCollection: return _showShareCollectionPage(context, collection); - case CollectionActionType.collectPhotos: - return _createCollaborativeLink(context, collection); case CollectionActionType.moveToHiddenCollection: return _moveFilesToCollection(context, collection.id); case CollectionActionType.addToHiddenAlbum: @@ -313,76 +316,6 @@ class _AlbumVerticalListWidgetState extends State { ); } - Future _createCollaborativeLink( - BuildContext context, - Collection collection, - ) async { - final CollectionActions collectionActions = - CollectionActions(CollectionsService.instance); - - if (collection.hasLink) { - if (collection.publicURLs.first.enableCollect) { - if (Configuration.instance.getUserID() == collection.owner.id) { - unawaited( - routeToPage( - context, - ShareCollectionPage(collection), - ), - ); - } - showShortToast( - context, - S.of(context).thisAlbumAlreadyHDACollaborativeLink, - ); - return Future.value(false); - } else { - try { - unawaited( - routeToPage( - context, - ShareCollectionPage(collection), - ), - ); - // ignore: unawaited_futures - CollectionsService.instance - .updateShareUrl(collection, {'enableCollect': true}).then( - (value) => showShortToast( - context, - S.of(context).collaborativeLinkCreatedFor(collection.displayName), - ), - ); - return true; - } catch (e) { - await showGenericErrorDialog(context: context, error: e); - return false; - } - } - } - final bool result = await collectionActions.enableUrl( - context, - collection, - enableCollect: true, - ); - if (result) { - showShortToast( - context, - S.of(context).collaborativeLinkCreatedFor(collection.displayName), - ); - if (Configuration.instance.getUserID() == collection.owner.id) { - unawaited( - routeToPage( - context, - ShareCollectionPage(collection), - ), - ); - } else { - await showGenericErrorDialog(context: context, error: result); - _logger.severe("Cannot share collections owned by others"); - } - } - return result; - } - Future _showShareCollectionPage( BuildContext context, Collection collection, diff --git a/mobile/lib/ui/collections/collection_action_sheet.dart b/mobile/lib/ui/collections/collection_action_sheet.dart index f056dc9732..99c41f59fc 100644 --- a/mobile/lib/ui/collections/collection_action_sheet.dart +++ b/mobile/lib/ui/collections/collection_action_sheet.dart @@ -5,6 +5,8 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; import "package:photos/core/configuration.dart"; +import "package:photos/core/event_bus.dart"; +import "package:photos/events/create_new_album_event.dart"; import "package:photos/generated/l10n.dart"; import 'package:photos/models/collection/collection.dart'; import 'package:photos/models/selected_files.dart'; @@ -30,11 +32,16 @@ enum CollectionActionType { restoreFiles, unHide, shareCollection, - collectPhotos, addToHiddenAlbum, moveToHiddenCollection, } +extension CollectionActionTypeExtension on CollectionActionType { + bool get isHiddenAction => + this == CollectionActionType.moveToHiddenCollection || + this == CollectionActionType.addToHiddenAlbum; +} + String _actionName( BuildContext context, CollectionActionType type, @@ -57,9 +64,6 @@ String _actionName( case CollectionActionType.shareCollection: text = S.of(context).share; break; - case CollectionActionType.collectPhotos: - text = S.of(context).share; - break; case CollectionActionType.addToHiddenAlbum: text = S.of(context).addToHiddenAlbum; break; @@ -123,16 +127,29 @@ class _CollectionActionSheetState extends State { static const int okButtonSize = 80; String _searchQuery = ""; final _selectedCollections = []; + final _recentlyCreatedCollections = []; + late StreamSubscription _createNewAlbumSubscription; @override void initState() { super.initState(); - _showOnlyHiddenCollections = - widget.actionType == CollectionActionType.moveToHiddenCollection || - widget.actionType == CollectionActionType.addToHiddenAlbum; + _showOnlyHiddenCollections = widget.actionType.isHiddenAction; _enableSelection = (widget.actionType == CollectionActionType.addFiles || widget.actionType == CollectionActionType.addToHiddenAlbum) && (widget.sharedFiles == null || widget.sharedFiles!.isEmpty); + _createNewAlbumSubscription = + Bus.instance.on().listen((event) { + setState(() { + _recentlyCreatedCollections.insert(0, event.collection); + _selectedCollections.add(event.collection); + }); + }); + } + + @override + void dispose() { + _createNewAlbumSubscription.cancel(); + super.dispose(); } @override @@ -187,7 +204,7 @@ class _CollectionActionSheetState extends State { prefixIcon: Icons.search_rounded, onChange: (value) { setState(() { - _searchQuery = value; + _searchQuery = value.trim(); }); }, isClearable: true, @@ -323,24 +340,32 @@ class _CollectionActionSheetState extends State { Future> _getCollections() async { if (_showOnlyHiddenCollections) { + final List recentlyCreated = []; + final List hidden = []; + final hiddenCollections = CollectionsService.instance .getHiddenCollections(includeDefaultHidden: false); - hiddenCollections.sort((first, second) { + for (final collection in hiddenCollections) { + if (_recentlyCreatedCollections.contains(collection)) { + recentlyCreated.add(collection); + } else { + hidden.add(collection); + } + } + hidden.sort((first, second) { return compareAsciiLowerCaseNatural( first.displayName, second.displayName, ); }); - return hiddenCollections; + return recentlyCreated + hidden; } else { - final bool includeUncategorized = - widget.actionType == CollectionActionType.restoreFiles; final List collections = CollectionsService.instance.getCollectionsForUI( // in collections where user is a collaborator, only addTo and remove // action can to be performed includeCollab: widget.actionType == CollectionActionType.addFiles, - includeUncategorized: includeUncategorized, + includeUncategorized: true, ); collections.sort((first, second) { return compareAsciiLowerCaseNatural( @@ -350,31 +375,37 @@ class _CollectionActionSheetState extends State { }); final List pinned = []; final List unpinned = []; + final List recentlyCreated = []; // show uncategorized collection only for restore files action Collection? uncategorized; for (final collection in collections) { if (collection.isQuickLinkCollection() || collection.type == CollectionType.favorites || collection.type == CollectionType.uncategorized) { - if (collection.type == CollectionType.uncategorized && - includeUncategorized) { + if (collection.type == CollectionType.uncategorized) { uncategorized = collection; } continue; } + if (_recentlyCreatedCollections.contains(collection)) { + recentlyCreated.add(collection); + continue; + } if (collection.isPinned) { pinned.add(collection); } else { unpinned.add(collection); } } - return pinned + unpinned + (uncategorized != null ? [uncategorized] : []); + + return uncategorized != null + ? [uncategorized] + recentlyCreated + pinned + unpinned + : recentlyCreated + pinned + unpinned; } } void _removeIncomingCollections(List items) { - if (widget.actionType == CollectionActionType.shareCollection || - widget.actionType == CollectionActionType.collectPhotos) { + if (widget.actionType == CollectionActionType.shareCollection) { final ownerID = Configuration.instance.getUserID(); items.removeWhere( (e) => !e.isOwner(ownerID!), diff --git a/mobile/lib/ui/collections/collection_list_page.dart b/mobile/lib/ui/collections/collection_list_page.dart index 3bc168a9d6..607d89413a 100644 --- a/mobile/lib/ui/collections/collection_list_page.dart +++ b/mobile/lib/ui/collections/collection_list_page.dart @@ -1,6 +1,7 @@ import "dart:async"; import 'package:flutter/material.dart'; +import "package:flutter_svg/flutter_svg.dart"; import "package:photos/core/event_bus.dart"; import "package:photos/events/album_sort_order_change_event.dart"; import "package:photos/events/collection_updated_event.dart"; @@ -142,7 +143,7 @@ class _CollectionListPageState extends State { Widget _sortMenu(List collections) { final colorTheme = getEnteColorScheme(context); - + final isLightMode = Theme.of(context).brightness == Brightness.light; Widget sortOptionText(AlbumSortKey key) { String text = key.toString(); switch (key) { @@ -180,12 +181,7 @@ class _CollectionListPageState extends State { ), child: Row( children: [ - IconButtonWidget( - icon: albumViewType == AlbumViewType.grid - ? Icons.view_list_outlined - : Icons.grid_view_outlined, - iconButtonType: IconButtonType.secondary, - iconColor: colorTheme.blurStrokePressed, + GestureDetector( onTap: () async { setState(() { albumViewType = albumViewType == AlbumViewType.grid @@ -194,6 +190,24 @@ class _CollectionListPageState extends State { }); await localSettings.setAlbumViewType(albumViewType!); }, + child: Padding( + padding: const EdgeInsets.all(12.0), + child: SizedBox( + height: 24, + width: 24, + child: albumViewType == AlbumViewType.grid + ? SvgPicture.asset( + isLightMode + ? "assets/icons/list_view_icon_light.svg" + : "assets/icons/list_view_icon_dark.svg", + ) + : Icon( + Icons.grid_view, + color: colorTheme.textMuted, + size: 22, + ), + ), + ), ), GestureDetector( onTapDown: (TapDownDetails details) async { @@ -226,9 +240,9 @@ class _CollectionListPageState extends State { } }, child: IconButtonWidget( - icon: Icons.sort_outlined, + icon: Icons.sort_rounded, iconButtonType: IconButtonType.secondary, - iconColor: colorTheme.blurStrokePressed, + iconColor: colorTheme.textMuted, ), ), ], diff --git a/mobile/lib/ui/collections/device/device_folder_item.dart b/mobile/lib/ui/collections/device/device_folder_item.dart index 64d0eef739..e7817b169e 100644 --- a/mobile/lib/ui/collections/device/device_folder_item.dart +++ b/mobile/lib/ui/collections/device/device_folder_item.dart @@ -1,6 +1,8 @@ +import "package:figma_squircle/figma_squircle.dart"; import 'package:flutter/material.dart'; import 'package:photos/ente_theme_data.dart'; import 'package:photos/models/device_collection.dart'; +import "package:photos/theme/ente_theme.dart"; import 'package:photos/ui/viewer/file/file_icons_widget.dart'; import 'package:photos/ui/viewer/file/thumbnail_widget.dart'; import 'package:photos/ui/viewer/gallery/device_folder_page.dart'; @@ -9,6 +11,11 @@ import 'package:photos/utils/navigation_util.dart'; class DeviceFolderItem extends StatelessWidget { final DeviceCollection deviceCollection; final double sideOfThumbnail; + + static const _cornerRadius = 12.0; + static const _cornerSmoothing = 1.0; + static const _borderWidth = 1.0; + const DeviceFolderItem( this.deviceCollection, { ///120 is default for the 'on device' scrollview in albums section @@ -23,36 +30,60 @@ class DeviceFolderItem extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ClipRRect( - borderRadius: BorderRadius.circular(1), - child: SizedBox( - height: sideOfThumbnail, - width: sideOfThumbnail, - child: Hero( - tag: "device_folder:" + - deviceCollection.name + - deviceCollection.thumbnail!.tag, - transitionOnUserGestures: true, - child: Stack( - children: [ - ThumbnailWidget( - deviceCollection.thumbnail!, - shouldShowSyncStatus: false, - key: Key( - "device_folder:" + - deviceCollection.name + - deviceCollection.thumbnail!.tag, + SizedBox( + height: sideOfThumbnail, + width: sideOfThumbnail, + child: Stack( + clipBehavior: Clip.none, + alignment: Alignment.center, + children: [ + ClipSmoothRect( + radius: SmoothBorderRadius( + cornerRadius: _cornerRadius + _borderWidth, + cornerSmoothing: _cornerSmoothing, + ), + child: Container( + color: getEnteColorScheme(context).strokeFaint, + width: sideOfThumbnail, + height: sideOfThumbnail, + ), + ), + ClipSmoothRect( + radius: SmoothBorderRadius( + cornerRadius: _cornerRadius, + cornerSmoothing: _cornerSmoothing, + ), + child: SizedBox( + height: sideOfThumbnail - _borderWidth * 2, + width: sideOfThumbnail - _borderWidth * 2, + child: Hero( + tag: "device_folder:" + + deviceCollection.name + + deviceCollection.thumbnail!.tag, + transitionOnUserGestures: true, + child: Stack( + children: [ + ThumbnailWidget( + deviceCollection.thumbnail!, + shouldShowSyncStatus: false, + key: Key( + "device_folder:" + + deviceCollection.name + + deviceCollection.thumbnail!.tag, + ), + ), + isBackedUp + ? const SizedBox.shrink() + : const UnSyncedIcon(), + ], ), ), - isBackedUp ? const SizedBox.shrink() : const UnSyncedIcon(), - ], + ), ), - ), + ], ), ), - const SizedBox( - height: 2, - ), + const SizedBox(height: 6), SizedBox( width: sideOfThumbnail, child: Text( @@ -62,6 +93,17 @@ class DeviceFolderItem extends StatelessWidget { overflow: TextOverflow.ellipsis, ), ), + const SizedBox(height: 2), + SizedBox( + width: sideOfThumbnail, + child: Text( + deviceCollection.count.toString(), + textAlign: TextAlign.left, + style: + Theme.of(context).colorScheme.enteTheme.textTheme.miniMuted, + overflow: TextOverflow.ellipsis, + ), + ), ], ), onTap: () { diff --git a/mobile/lib/ui/collections/device/device_folders_grid_view.dart b/mobile/lib/ui/collections/device/device_folders_grid_view.dart index d6c04e0bed..e68d58c80e 100644 --- a/mobile/lib/ui/collections/device/device_folders_grid_view.dart +++ b/mobile/lib/ui/collections/device/device_folders_grid_view.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import "dart:math"; import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; @@ -33,6 +34,9 @@ class _DeviceFoldersGridViewState extends State { executionInterval: const Duration(seconds: 5), leading: true, ); + static const maxThumbnailWidth = 224.0; + static const horizontalPadding = 16.0; + static const crossAxisSpacing = 8.0; @override void initState() { @@ -57,9 +61,18 @@ class _DeviceFoldersGridViewState extends State { @override Widget build(BuildContext context) { + final double screenWidth = MediaQuery.sizeOf(context).width; + final int albumsCountInCrossAxis = max(screenWidth ~/ maxThumbnailWidth, 3); + + final double totalCrossAxisSpacing = + (albumsCountInCrossAxis - 1) * crossAxisSpacing; + final double sideOfThumbnail = + (screenWidth - totalCrossAxisSpacing - horizontalPadding) / + albumsCountInCrossAxis; + debugPrint("${(DeviceFoldersGridView).toString()} - $_loadReason"); return SizedBox( - height: 170, + height: sideOfThumbnail + 46, child: Align( alignment: Alignment.centerLeft, child: FutureBuilder>( @@ -72,19 +85,28 @@ class _DeviceFoldersGridViewState extends State { padding: EdgeInsets.all(22), child: EmptyState(), ) - : ListView.builder( - scrollDirection: Axis.horizontal, - padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), - physics: const ScrollPhysics(), - // to disable GridView's scrolling - itemBuilder: (context, index) { - final deviceCollection = snapshot.data![index]; - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 2), - child: DeviceFolderItem(deviceCollection), - ); - }, - itemCount: snapshot.data!.length, + : Padding( + padding: const EdgeInsets.symmetric( + horizontal: horizontalPadding / 2, + ), + child: ListView.builder( + scrollDirection: Axis.horizontal, + physics: const ScrollPhysics(), + // to disable GridView's scrolling + itemBuilder: (context, index) { + final deviceCollection = snapshot.data![index]; + return Padding( + padding: const EdgeInsets.only( + right: horizontalPadding / 2, + ), + child: DeviceFolderItem( + deviceCollection, + sideOfThumbnail: sideOfThumbnail, + ), + ); + }, + itemCount: snapshot.data!.length, + ), ); } else if (snapshot.hasError) { _logger.severe("failed to load device gallery", snapshot.error); diff --git a/mobile/lib/ui/collections/device/device_folders_vertical_grid_view.dart b/mobile/lib/ui/collections/device/device_folders_vertical_grid_view.dart index 0e5a19edf6..1c765ed0bf 100644 --- a/mobile/lib/ui/collections/device/device_folders_vertical_grid_view.dart +++ b/mobile/lib/ui/collections/device/device_folders_vertical_grid_view.dart @@ -62,13 +62,12 @@ class _DeviceFolderVerticalGridViewBodyState executionInterval: const Duration(seconds: 4), ); /* - Aspect ratio 1:1 Max width 224 Fixed gap 8 - Width changes dynamically with screen width such that we can fit 2 in one row. - Keep the width integral (center the albums to distribute excess pixels) - */ - static const maxThumbnailWidth = 170.0; - static const fixedGapBetweenAlbum = 2.0; - static const minGapForHorizontalPadding = 8.0; + Aspect ratio 1:1 + Width changes dynamically with screen width + */ + static const maxThumbnailWidth = 224.0; + static const horizontalPadding = 16.0; + static const crossAxisSpacing = 8.0; @override void initState() { @@ -101,30 +100,28 @@ class _DeviceFolderVerticalGridViewBodyState FilesDB.instance.getDeviceCollections(includeCoverThumbnail: true), builder: (context, snapshot) { if (snapshot.hasData) { - final double screenWidth = MediaQuery.of(context).size.width; - final int albumsCountInOneRow = + final double screenWidth = MediaQuery.sizeOf(context).width; + final int albumsCountInCrossAxis = max(screenWidth ~/ maxThumbnailWidth, 3); - final double gapBetweenAlbums = - (albumsCountInOneRow - 1) * fixedGapBetweenAlbum; - final double gapOnSizeOfAlbums = minGapForHorizontalPadding + - (screenWidth - - gapBetweenAlbums - - (2 * minGapForHorizontalPadding)) % - albumsCountInOneRow; + final double totalCrossAxisSpacing = + (albumsCountInCrossAxis - 1) * crossAxisSpacing; final double sideOfThumbnail = - (screenWidth - gapOnSizeOfAlbums - gapBetweenAlbums) / - albumsCountInOneRow; + (screenWidth - totalCrossAxisSpacing - horizontalPadding) / + albumsCountInCrossAxis; return snapshot.data!.isEmpty ? const SliverFillRemaining(child: EmptyState()) : SliverPadding( - padding: const EdgeInsets.symmetric(horizontal: 8), + padding: const EdgeInsets.only( + left: horizontalPadding / 2, + right: horizontalPadding / 2, + ), sliver: SliverGrid( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: albumsCountInOneRow, - mainAxisSpacing: 4, - crossAxisSpacing: gapBetweenAlbums, + crossAxisCount: albumsCountInCrossAxis, + mainAxisSpacing: 8, + crossAxisSpacing: crossAxisSpacing, childAspectRatio: sideOfThumbnail / (sideOfThumbnail + 46), ), diff --git a/mobile/lib/ui/collections/flex_grid_view.dart b/mobile/lib/ui/collections/flex_grid_view.dart index 5080167937..2267833b1a 100644 --- a/mobile/lib/ui/collections/flex_grid_view.dart +++ b/mobile/lib/ui/collections/flex_grid_view.dart @@ -109,9 +109,23 @@ class _CollectionsFlexiGridViewWidgetState @override Widget build(BuildContext context) { - return widget.albumViewType == AlbumViewType.grid - ? _buildGridView(context, const ValueKey("grid_view")) - : _buildListView(context, const ValueKey("list_view")); + return PopScope( + canPop: !isAnyAlbumSelected, + onPopInvokedWithResult: (didPop, _) { + if (didPop) { + return; + } + if (isAnyAlbumSelected) { + widget.selectedAlbums!.clearAll(); + setState(() { + isAnyAlbumSelected = false; + }); + } + }, + child: widget.albumViewType == AlbumViewType.grid + ? _buildGridView(context, const ValueKey("grid_view")) + : _buildListView(context, const ValueKey("list_view")), + ); } Widget _buildGridView(BuildContext context, Key key) { @@ -172,7 +186,7 @@ class _CollectionsFlexiGridViewWidgetState ), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: albumsCountInCrossAxis, - mainAxisSpacing: 2, + mainAxisSpacing: 8, crossAxisSpacing: CollectionsFlexiGridViewWidget.crossAxisSpacing, childAspectRatio: sideOfThumbnail / (sideOfThumbnail + 46), ), diff --git a/mobile/lib/ui/common/email_input.dart b/mobile/lib/ui/common/email_input.dart deleted file mode 100644 index 9fab4d44c5..0000000000 --- a/mobile/lib/ui/common/email_input.dart +++ /dev/null @@ -1,129 +0,0 @@ -import 'package:flutter/material.dart'; -import "package:photos/generated/l10n.dart"; -import "package:photos/models/api/collection/user.dart"; -import "package:photos/theme/ente_theme.dart"; -import "package:photos/ui/components/captioned_text_widget.dart"; -import "package:photos/ui/components/divider_widget.dart"; -import "package:photos/ui/components/menu_item_widget/menu_item_widget.dart"; -import "package:photos/ui/sharing/user_avator_widget.dart"; - -class EmailInputField extends StatelessWidget { - final List suggestions; - final ValueChanged? onChanged; - final ValueChanged? onSelected; - final String? initialValue; - - const EmailInputField({ - super.key, - required this.suggestions, - this.onChanged, - this.onSelected, - this.initialValue, - }); - - @override - Widget build(BuildContext context) { - return Autocomplete( - initialValue: - initialValue != null ? TextEditingValue(text: initialValue!) : null, - optionsBuilder: (TextEditingValue textEditingValue) { - if (textEditingValue.text == '') { - return const Iterable.empty(); - } - return suggestions.where((String option) { - return option - .toLowerCase() - .contains(textEditingValue.text.toLowerCase()); - }); - }, - onSelected: onSelected, - fieldViewBuilder: ( - BuildContext context, - TextEditingController controller, - FocusNode focusNode, - VoidCallback onFieldSubmitted, - ) { - return TextFormField( - controller: controller, - focusNode: focusNode, - onChanged: onChanged, - decoration: InputDecoration( - focusedBorder: OutlineInputBorder( - borderRadius: const BorderRadius.all(Radius.circular(8.0)), - borderSide: - BorderSide(color: getEnteColorScheme(context).strokeMuted), - ), - fillColor: getEnteColorScheme(context).fillFaint, - filled: true, - hintText: S.of(context).enterEmail, - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 14, - ), - border: UnderlineInputBorder( - borderSide: BorderSide.none, - borderRadius: BorderRadius.circular(8), - ), - ), - ); - }, - optionsViewBuilder: ( - BuildContext context, - AutocompleteOnSelected onSelected, - Iterable options, - ) { - return Align( - alignment: Alignment.topLeft, - child: Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Material( - elevation: 4, - borderRadius: BorderRadius.circular(8), - child: Container( - constraints: const BoxConstraints(maxHeight: 160), - width: MediaQuery.of(context).size.width - - 16, // Adjust padding as needed - child: ListView.builder( - padding: EdgeInsets.zero, - physics: const ClampingScrollPhysics(), - shrinkWrap: true, - itemCount: options.length, - itemBuilder: (BuildContext context, int index) { - final String option = options.elementAt(index); - return Column( - children: [ - MenuItemWidget( - captionedTextWidget: CaptionedTextWidget( - title: option, - ), - leadingIconSize: 24.0, - leadingIconWidget: UserAvatarWidget( - User(email: option, id: option.hashCode), - ), - menuItemColor: getEnteColorScheme(context).fillFaint, - pressedColor: getEnteColorScheme(context).fillFaint, - trailingIcon: null, - onTap: () async { - onSelected(option); - }, - isTopBorderRadiusRemoved: index > 0, - isBottomBorderRadiusRemoved: index < (options.length), - ), - (index == (options.length - 1)) - ? const SizedBox.shrink() - : DividerWidget( - dividerType: DividerType.menu, - bgColor: getEnteColorScheme(context).fillFaint, - ), - ], - ); - }, - ), - ), - ), - ), - ); - }, - ); - } -} diff --git a/mobile/lib/ui/components/bottom_action_bar/people_action_bar_widget.dart b/mobile/lib/ui/components/bottom_action_bar/people_action_bar_widget.dart new file mode 100644 index 0000000000..47c61ebcde --- /dev/null +++ b/mobile/lib/ui/components/bottom_action_bar/people_action_bar_widget.dart @@ -0,0 +1,86 @@ +import "package:flutter/material.dart"; +import "package:photos/generated/l10n.dart"; +import "package:photos/models/selected_people.dart"; +import "package:photos/theme/ente_theme.dart"; + +class PeopleActionBarWidget extends StatefulWidget { + final SelectedPeople? selectedPeople; + final VoidCallback? onCancel; + const PeopleActionBarWidget({ + super.key, + this.selectedPeople, + this.onCancel, + }); + + @override + State createState() => _PeopleActionBarWidgetState(); +} + +class _PeopleActionBarWidgetState extends State { + final ValueNotifier _selectedPeopleNotifier = ValueNotifier(0); + + @override + void initState() { + super.initState(); + widget.selectedPeople?.addListener(_selectedPeopleListener); + } + + @override + void dispose() { + widget.selectedPeople?.removeListener(_selectedPeopleListener); + _selectedPeopleNotifier.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final textTheme = getEnteTextTheme(context); + return SizedBox( + child: Padding( + padding: const EdgeInsets.fromLTRB(20, 8, 20, 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + flex: 1, + child: ValueListenableBuilder( + valueListenable: _selectedPeopleNotifier, + builder: (context, value, child) { + final count = widget.selectedPeople?.personIds.length ?? 0; + return Text( + S.of(context).selectedPhotos(count), + style: textTheme.miniMuted, + ); + }, + ), + ), + Flexible( + flex: 1, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 12), + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + widget.onCancel?.call(); + }, + child: Align( + alignment: Alignment.centerRight, + child: Text( + S.of(context).cancel, + style: textTheme.mini, + ), + ), + ), + ), + ), + ], + ), + ), + ); + } + + void _selectedPeopleListener() { + _selectedPeopleNotifier.value = + widget.selectedPeople?.personIds.length ?? 0; + } +} diff --git a/mobile/lib/ui/components/bottom_action_bar/people_bottom_action_bar_widget.dart b/mobile/lib/ui/components/bottom_action_bar/people_bottom_action_bar_widget.dart new file mode 100644 index 0000000000..db73e07a9f --- /dev/null +++ b/mobile/lib/ui/components/bottom_action_bar/people_bottom_action_bar_widget.dart @@ -0,0 +1,57 @@ +import "package:flutter/material.dart"; +import "package:photos/core/constants.dart"; +import "package:photos/models/selected_people.dart"; +import "package:photos/theme/ente_theme.dart"; +import "package:photos/ui/components/bottom_action_bar/people_action_bar_widget.dart"; +import "package:photos/ui/components/divider_widget.dart"; +import "package:photos/ui/viewer/actions/people_selection_action_widget.dart"; + +class PeopleBottomActionBarWidget extends StatelessWidget { + final SelectedPeople selectedPeople; + final VoidCallback? onCancel; + final Color? backgroundColor; + + const PeopleBottomActionBarWidget( + this.selectedPeople, { + super.key, + this.backgroundColor, + this.onCancel, + }); + + @override + Widget build(BuildContext context) { + final bottomPadding = MediaQuery.paddingOf(context).bottom; + final widthOfScreen = MediaQuery.sizeOf(context).width; + final colorScheme = getEnteColorScheme(context); + final double leftRightPadding = widthOfScreen > restrictedMaxWidth + ? (widthOfScreen - restrictedMaxWidth) / 2 + : 0; + return Container( + decoration: BoxDecoration( + color: backgroundColor ?? colorScheme.backgroundElevated2, + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(8), + topRight: Radius.circular(8), + ), + ), + padding: EdgeInsets.only( + top: 4, + bottom: bottomPadding, + right: leftRightPadding, + left: leftRightPadding, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(height: 8), + PeopleSelectionActionWidget(selectedPeople), + const DividerWidget(dividerType: DividerType.bottomBar), + PeopleActionBarWidget( + selectedPeople: selectedPeople, + onCancel: onCancel, + ), + ], + ), + ); + } +} diff --git a/mobile/lib/ui/components/buttons/icon_button_widget.dart b/mobile/lib/ui/components/buttons/icon_button_widget.dart index 3e51f87898..91573db4eb 100644 --- a/mobile/lib/ui/components/buttons/icon_button_widget.dart +++ b/mobile/lib/ui/components/buttons/icon_button_widget.dart @@ -110,9 +110,11 @@ class _IconButtonWidgetState extends State { _onTapUp(details) { Future.delayed(const Duration(milliseconds: 100), () { - setState(() { - iconStateColor = null; - }); + if (mounted) { + setState(() { + iconStateColor = null; + }); + } }); } diff --git a/mobile/lib/ui/components/home_header_widget.dart b/mobile/lib/ui/components/home_header_widget.dart index 3e37078cc5..836418136f 100644 --- a/mobile/lib/ui/components/home_header_widget.dart +++ b/mobile/lib/ui/components/home_header_widget.dart @@ -10,6 +10,7 @@ import 'package:photos/ui/components/buttons/icon_button_widget.dart'; import "package:photos/ui/settings/backup/backup_folder_selection_page.dart"; import "package:photos/utils/dialog_util.dart"; import "package:photos/utils/navigation_util.dart"; + class HomeHeaderWidget extends StatefulWidget { final Widget centerWidget; const HomeHeaderWidget({required this.centerWidget, super.key}); diff --git a/mobile/lib/ui/components/searchable_appbar.dart b/mobile/lib/ui/components/searchable_appbar.dart index 4290713552..bf447a952d 100644 --- a/mobile/lib/ui/components/searchable_appbar.dart +++ b/mobile/lib/ui/components/searchable_appbar.dart @@ -1,6 +1,6 @@ import "package:flutter/material.dart"; +import "package:flutter_svg/flutter_svg.dart"; import "package:photos/theme/ente_theme.dart"; -import "package:photos/ui/components/buttons/icon_button_widget.dart"; class SearchableAppBar extends StatefulWidget { final Widget title; @@ -56,6 +56,7 @@ class _SearchableAppBarState extends State { @override Widget build(BuildContext context) { + final isLightMode = Theme.of(context).brightness == Brightness.light; return SliverAppBar( floating: true, elevation: 0, @@ -81,11 +82,20 @@ class _SearchableAppBarState extends State { actions: _isSearchActive ? null : [ - IconButtonWidget( - icon: Icons.search, - iconButtonType: IconButtonType.secondary, + GestureDetector( onTap: _activateSearch, - iconColor: getEnteColorScheme(context).blurStrokePressed, + child: Padding( + padding: const EdgeInsets.all(12.0), + child: SizedBox( + height: 18, + width: 18, + child: SvgPicture.asset( + isLightMode + ? "assets/icons/search_icon_light.svg" + : "assets/icons/search_icon_dark.svg", + ), + ), + ), ), ...?widget.actions, ], diff --git a/mobile/lib/ui/home/landing_page_widget.dart b/mobile/lib/ui/home/landing_page_widget.dart index c3d2f1d7f7..bdc1e8a03e 100644 --- a/mobile/lib/ui/home/landing_page_widget.dart +++ b/mobile/lib/ui/home/landing_page_widget.dart @@ -42,10 +42,6 @@ class _LandingPageWidgetState extends State { void initState() { super.initState(); Future(_showAutoLogoutDialogIfRequired); - Future.delayed( - const Duration(seconds: 1), - _autoEnableResumableUpload, - ); } @override @@ -308,10 +304,6 @@ class _LandingPageWidgetState extends State { } } } - - void _autoEnableResumableUpload() { - localSettings.autoEnableMultiplePart(50).ignore(); - } } class FeatureItemWidget extends StatelessWidget { diff --git a/mobile/lib/ui/home/memories/all_memories_page.dart b/mobile/lib/ui/home/memories/all_memories_page.dart new file mode 100644 index 0000000000..955fe7a833 --- /dev/null +++ b/mobile/lib/ui/home/memories/all_memories_page.dart @@ -0,0 +1,106 @@ +import 'package:flutter/material.dart'; +import "package:photos/models/memories/memory.dart"; +import "package:photos/theme/colors.dart"; +import "package:photos/ui/home/memories/full_screen_memory.dart"; + +// TODO: Use a single instance variable for `allMemories` and `allTitles` +class AllMemoriesPage extends StatefulWidget { + final int initialPageIndex; + final int inititalFileIndex; + final List> allMemories; + final List allTitles; + final bool isFromWidgetOrNotifications; + + const AllMemoriesPage({ + super.key, + required this.allMemories, + required this.allTitles, + required this.initialPageIndex, + this.inititalFileIndex = 0, + this.isFromWidgetOrNotifications = false, + }); + + @override + State createState() => _AllMemoriesPageState(); +} + +class _AllMemoriesPageState extends State + with SingleTickerProviderStateMixin { + late PageController pageController; + bool isFirstLoad = true; + + @override + void initState() { + super.initState(); + pageController = PageController(initialPage: widget.initialPageIndex); + } + + @override + void dispose() { + pageController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + height: double.infinity, + color: backgroundBaseDark, + child: PageView.builder( + controller: pageController, + physics: const BouncingScrollPhysics(), + hitTestBehavior: HitTestBehavior.translucent, + itemCount: widget.allMemories.length, + itemBuilder: (context, index) { + final initialMemoryIndex = + widget.isFromWidgetOrNotifications && isFirstLoad + ? widget.inititalFileIndex + : _getNextMemoryIndex(index); + isFirstLoad = false; + return FullScreenMemoryDataUpdater( + initialIndex: initialMemoryIndex, + memories: widget.allMemories[index], + child: FullScreenMemory( + widget.allTitles[index], + initialMemoryIndex, + onNextMemory: index < widget.allMemories.length - 1 + ? () => pageController.nextPage( + duration: const Duration(milliseconds: 675), + curve: Curves.easeOutQuart, + ) + : null, + onPreviousMemory: index > 0 + ? () => pageController.previousPage( + duration: const Duration(milliseconds: 675), + curve: Curves.easeOutQuart, + ) + : null, + ), + ); + }, + ), + ); + } + + int _getNextMemoryIndex(int currentIndex) { + int lastSeenIndex = 0; + int lastSeenTimestamp = 0; + final allMemoriesLength = widget.allMemories[currentIndex].length; + for (var index = 0; index < allMemoriesLength; index++) { + final memory = widget.allMemories[currentIndex][index]; + if (!memory.isSeen()) { + return index; + } else { + if (memory.seenTime() > lastSeenTimestamp) { + lastSeenIndex = index; + lastSeenTimestamp = memory.seenTime(); + } + } + } + if (lastSeenIndex == widget.allMemories[currentIndex].length - 1) { + return 0; + } + return lastSeenIndex + 1; + } +} diff --git a/mobile/lib/ui/home/memories/custom_listener.dart b/mobile/lib/ui/home/memories/custom_listener.dart new file mode 100644 index 0000000000..981f9919cc --- /dev/null +++ b/mobile/lib/ui/home/memories/custom_listener.dart @@ -0,0 +1,150 @@ +import 'dart:async'; +import 'package:flutter/widgets.dart'; + +class ActivePointers with ChangeNotifier { + final Set _activePointers = {}; + bool get hasActivePointers => _activePointers.isNotEmpty; + bool activePointerWasPartOfMultitouch = false; + + void add(int pointer) { + if (_activePointers.isNotEmpty && !_activePointers.contains(pointer)) { + activePointerWasPartOfMultitouch = true; + } + _activePointers.add(pointer); + notifyListeners(); + } + + void remove(int pointer) { + _activePointers.remove(pointer); + if (_activePointers.isEmpty) { + activePointerWasPartOfMultitouch = false; + } + notifyListeners(); + } +} + +/// `onLongPress` and `onLongPressUp` have not been tested enough to make sure +/// it works as expected, so they are commented out for now. +class MemoriesPointerGestureListener extends StatefulWidget { + final Widget child; + final Function(PointerEvent)? onTap; + // final VoidCallback? onLongPress; + // final VoidCallback? onLongPressUp; + + /// How long the pointer must stay down before a long‐press fires. + final Duration longPressDuration; + + /// Maximum movement (in logical pixels) before we consider it a drag. + final double touchSlop; + + /// Notifier that indicates whether there are active pointers. + final ValueNotifier? hasPointerNotifier; + static const double kTouchSlop = 18.0; // Default touch slop value + + const MemoriesPointerGestureListener({ + super.key, + required this.child, + this.onTap, + // this.onLongPress, + // this.onLongPressUp, + this.hasPointerNotifier, + this.longPressDuration = const Duration(milliseconds: 500), + this.touchSlop = kTouchSlop, // from flutter/gestures/constants.dart + }); + + @override + MemoriesPointerGestureListenerState createState() => + MemoriesPointerGestureListenerState(); +} + +class MemoriesPointerGestureListenerState + extends State { + Timer? _longPressTimer; + bool _longPressFired = false; + Offset? _downPosition; + bool hasPointerMoved = false; + final _activePointers = ActivePointers(); + + @override + void initState() { + super.initState(); + _activePointers.addListener(_activatePointerListener); + } + + void _activatePointerListener() { + if (widget.hasPointerNotifier != null) { + widget.hasPointerNotifier!.value = _activePointers.hasActivePointers; + } + } + + void _handlePointerDown(PointerDownEvent event) { + _addPointer(event.pointer); + _downPosition = event.localPosition; + _longPressFired = false; + _longPressTimer?.cancel(); + _longPressTimer = Timer(widget.longPressDuration, () { + _longPressFired = true; + // widget.onLongPress?.call(); + }); + } + + void _handlePointerMove(PointerMoveEvent event) { + if (_longPressTimer != null && _downPosition != null) { + final distance = (event.localPosition - _downPosition!).distance; + if (distance > widget.touchSlop) { + // user started dragging – cancel long‐press + hasPointerMoved = true; + _longPressTimer!.cancel(); + _longPressTimer = null; + } + } + } + + void _handlePointerUp(PointerUpEvent event) { + _longPressTimer?.cancel(); + _longPressTimer = null; + + if (_longPressFired) { + // widget.onLongPressUp?.call(); + } else { + if (!_activePointers.activePointerWasPartOfMultitouch && + !hasPointerMoved) { + widget.onTap?.call(event); + } + } + _removePointer(event.pointer); + _reset(); + } + + void _handlePointerCancel(PointerCancelEvent event) { + _longPressTimer?.cancel(); + _longPressTimer = null; + _longPressFired = false; + _removePointer(event.pointer); + _reset(); + } + + void _removePointer(int pointer) { + _activePointers.remove(pointer); + } + + void _addPointer(int pointer) { + _activePointers.add(pointer); + } + + @override + Widget build(BuildContext context) { + return Listener( + onPointerDown: _handlePointerDown, + onPointerMove: _handlePointerMove, + onPointerUp: _handlePointerUp, + onPointerCancel: _handlePointerCancel, + behavior: HitTestBehavior.opaque, + child: widget.child, + ); + } + + void _reset() { + hasPointerMoved = false; + } +} diff --git a/mobile/lib/ui/home/memories/full_screen_memory.dart b/mobile/lib/ui/home/memories/full_screen_memory.dart index 7a09c80f2a..0fa74931a8 100644 --- a/mobile/lib/ui/home/memories/full_screen_memory.dart +++ b/mobile/lib/ui/home/memories/full_screen_memory.dart @@ -1,20 +1,28 @@ import "dart:async"; import "dart:io"; +import "dart:math"; +import "dart:ui"; import "package:flutter/cupertino.dart"; import "package:flutter/material.dart"; import "package:photos/core/configuration.dart"; +import "package:photos/core/event_bus.dart"; +import "package:photos/events/details_sheet_event.dart"; +import "package:photos/events/reset_zoom_of_photo_view_event.dart"; +import "package:photos/models/file/file_type.dart"; import "package:photos/models/memories/memory.dart"; import "package:photos/service_locator.dart"; import "package:photos/services/smart_memories_service.dart"; -import "package:photos/theme/ente_theme.dart"; +import "package:photos/theme/colors.dart"; import "package:photos/theme/text_style.dart"; import "package:photos/ui/actions/file/file_actions.dart"; +import "package:photos/ui/home/memories/custom_listener.dart"; +import "package:photos/ui/home/memories/memory_progress_indicator.dart"; import "package:photos/ui/viewer/file/file_widget.dart"; +import "package:photos/ui/viewer/file/thumbnail_widget.dart"; import "package:photos/ui/viewer/file_details/favorite_widget.dart"; import "package:photos/utils/file_util.dart"; import "package:photos/utils/share_util.dart"; -import "package:step_progress_indicator/step_progress_indicator.dart"; //There are two states of variables that FullScreenMemory depends on: //1. The list of memories @@ -32,6 +40,8 @@ import "package:step_progress_indicator/step_progress_indicator.dart"; //ValueNotifier inside the InheritedWidget and the widgets that need to change //are wrapped in a ValueListenableBuilder. +//TODO: Use better naming convention. "Memory" should be a whole memory and +//parts of the memory should be called "items". class FullScreenMemoryDataUpdater extends StatefulWidget { final List memories; final int initialIndex; @@ -118,9 +128,14 @@ class FullScreenMemoryData extends InheritedWidget { class FullScreenMemory extends StatefulWidget { final String title; final int initialIndex; + final VoidCallback? onNextMemory; + final VoidCallback? onPreviousMemory; + const FullScreenMemory( this.title, this.initialIndex, { + this.onNextMemory, + this.onPreviousMemory, super.key, }); @@ -129,198 +144,354 @@ class FullScreenMemory extends StatefulWidget { } class _FullScreenMemoryState extends State { - PageController? _pageController; final _showTitle = ValueNotifier(true); + AnimationController? _progressAnimationController; + AnimationController? _zoomAnimationController; + final ValueNotifier durationNotifier = + ValueNotifier(const Duration(seconds: 5)); + + /// Used to check if any pointer is on the screen. + final hasPointerOnScreenNotifier = ValueNotifier(false); + bool hasFinalFileLoaded = false; + + late final StreamSubscription + _detailSheetEventSubscription; @override void initState() { super.initState(); Future.delayed(const Duration(seconds: 3), () { - if (mounted) { - setState(() { - _showTitle.value = false; - }); + if (mounted) _showTitle.value = false; + }); + hasPointerOnScreenNotifier.addListener( + _hasPointerListener, + ); + + _detailSheetEventSubscription = + Bus.instance.on().listen((event) { + final inheritedData = FullScreenMemoryData.of(context); + if (inheritedData == null) return; + final index = inheritedData.indexNotifier.value; + final currentFile = inheritedData.memories[index].file; + + if (event.isSameFile( + uploadedFileID: currentFile.uploadedFileID, + localID: currentFile.localID, + )) { + _toggleAnimation(pause: event.opened); } }); } @override void dispose() { - _pageController?.dispose(); _showTitle.dispose(); + durationNotifier.dispose(); + hasPointerOnScreenNotifier.removeListener(_hasPointerListener); + _detailSheetEventSubscription.cancel(); super.dispose(); } + /// Used to check if user has touched the screen and then to pause animation + /// and once the pointer is removed from the screen, it resumes the animation + /// It also resets the zoom of the photo view to default for better user + /// experience after finger(s) is removed from the screen after zooming in by + /// pinching. + void _hasPointerListener() { + if (hasPointerOnScreenNotifier.value) { + _toggleAnimation(pause: true); + } else { + _toggleAnimation(pause: false); + final inheritedData = FullScreenMemoryData.of(context)!; + final currentFile = + inheritedData.memories[inheritedData.indexNotifier.value].file; + Bus.instance.fire( + ResetZoomOfPhotoView( + localID: currentFile.localID, + uploadedFileID: currentFile.uploadedFileID, + ), + ); + } + } + + void _toggleAnimation({required bool pause}) { + if (pause) { + _progressAnimationController?.stop(); + _zoomAnimationController?.stop(); + } else { + if (hasFinalFileLoaded) { + _progressAnimationController?.forward(); + _zoomAnimationController?.forward(); + } + } + } + + void _resetAnimation() { + _progressAnimationController + ?..stop() + ..reset(); + _zoomAnimationController + ?..stop() + ..reset(); + } + + void onFinalFileLoad(int duration) { + hasFinalFileLoaded = true; + if (_progressAnimationController?.isAnimating == true) { + _progressAnimationController!.stop(); + } + durationNotifier.value = Duration(seconds: duration); + _progressAnimationController + ?..stop() + ..reset() + ..duration = durationNotifier.value + ..forward(); + _zoomAnimationController + ?..stop() + ..reset() + ..forward(); + } + + void _goToNext(FullScreenMemoryData inheritedData) { + hasFinalFileLoaded = false; + final currentIndex = inheritedData.indexNotifier.value; + if (currentIndex < inheritedData.memories.length - 1) { + inheritedData.indexNotifier.value += 1; + _onPageChange(inheritedData, currentIndex + 1); + } else if (widget.onNextMemory != null) { + widget.onNextMemory!(); + } + } + + void _goToPrevious(FullScreenMemoryData inheritedData) { + hasFinalFileLoaded = false; + final currentIndex = inheritedData.indexNotifier.value; + if (currentIndex > 0) { + inheritedData.indexNotifier.value -= 1; + _onPageChange(inheritedData, currentIndex - 1); + } else if (widget.onPreviousMemory != null) { + widget.onPreviousMemory!(); + } + } + + void _onPageChange(FullScreenMemoryData inheritedData, int index) { + unawaited( + memoriesCacheService.markMemoryAsSeen( + inheritedData.memories[index], + false, + ), + ); + inheritedData.indexNotifier.value = index; + _resetAnimation(); + } + @override Widget build(BuildContext context) { final inheritedData = FullScreenMemoryData.of(context)!; final showStepProgressIndicator = inheritedData.memories.length < 60; - return Scaffold( - backgroundColor: Colors.black, - extendBodyBehindAppBar: true, - appBar: AppBar( - toolbarHeight: 84, - automaticallyImplyLeading: false, - title: ValueListenableBuilder( - valueListenable: inheritedData.indexNotifier, - child: InkWell( - onTap: () { - Navigator.pop(context); - }, - child: const Padding( - padding: EdgeInsets.fromLTRB(4, 8, 8, 8), - child: Icon( - Icons.close, - color: Colors.white, //same for both themes - ), - ), - ), - builder: (context, value, child) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - showStepProgressIndicator - ? StepProgressIndicator( - totalSteps: inheritedData.memories.length, - currentStep: value + 1, - size: 2, - selectedColor: Colors.white, //same for both themes - unselectedColor: Colors.white.withOpacity(0.4), - ) - : const SizedBox.shrink(), - const SizedBox( - height: 10, - ), - Row( - children: [ - child!, - Text( - SmartMemoriesService.getDateFormatted( - creationTime: - inheritedData.memories[value].file.creationTime!, - context: context, - ), - style: Theme.of(context).textTheme.titleMedium!.copyWith( - fontSize: 14, - color: Colors.white, - ), //same for both themes - ), - ], - ), - ], - ); - }, - ), - flexibleSpace: Container( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Colors.black.withOpacity(0.6), - Colors.black.withOpacity(0.5), - Colors.transparent, - ], - stops: const [0, 0.6, 1], - ), - ), - ), - backgroundColor: const Color(0x00000000), - elevation: 0, + + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 4.0, ), - body: Stack( - alignment: Alignment.bottomCenter, - children: [ - PageView.builder( - controller: _pageController ??= PageController( - initialPage: widget.initialIndex, + child: SafeArea( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: strokeFainterDark, + width: 1, ), - itemBuilder: (context, index) { - if (index < inheritedData.memories.length - 1) { - final nextFile = inheritedData.memories[index + 1].file; - preloadThumbnail(nextFile); - preloadFile(nextFile); - } - return GestureDetector( - onTapDown: (TapDownDetails details) { - final screenWidth = MediaQuery.of(context).size.width; - final edgeWidth = screenWidth * 0.20; - if (details.localPosition.dx < edgeWidth) { - if (index > 0) { - _pageController!.previousPage( - duration: const Duration(milliseconds: 250), - curve: Curves.ease, - ); - } - } else if (details.localPosition.dx > - screenWidth - edgeWidth) { - if (index < (inheritedData.memories.length - 1)) { - _pageController!.nextPage( - duration: const Duration(milliseconds: 250), - curve: Curves.ease, - ); - } - } - }, - child: FileWidget( - inheritedData.memories[index].file, - autoPlay: false, - tagPrefix: "memories", - backgroundDecoration: const BoxDecoration( - color: Colors.transparent, + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(16), + child: Scaffold( + backgroundColor: Colors.black, + extendBodyBehindAppBar: true, + appBar: AppBar( + toolbarHeight: 64, + primary: false, + automaticallyImplyLeading: false, + title: ValueListenableBuilder( + valueListenable: inheritedData.indexNotifier, + child: GestureDetector( + onTap: () => Navigator.pop(context), + child: const Padding( + padding: EdgeInsets.fromLTRB(4, 8, 8, 8), + child: Icon(Icons.close, color: Colors.white), + ), + ), + builder: (context, value, child) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 32), + showStepProgressIndicator + ? ValueListenableBuilder( + valueListenable: durationNotifier, + builder: (context, duration, _) { + return MemoryProgressIndicator( + totalSteps: inheritedData.memories.length, + currentIndex: value, + selectedColor: Colors.white, + unselectedColor: + Colors.white.withOpacity(0.4), + duration: duration, + animationController: (controller) { + _progressAnimationController = controller; + }, + onComplete: () { + _goToNext(inheritedData); + }, + ); + }, + ) + : const SizedBox.shrink(), + const SizedBox(height: 6), + Row( + children: [ + child!, + Text( + SmartMemoriesService.getDateFormatted( + creationTime: inheritedData + .memories[value].file.creationTime!, + context: context, + ), + style: Theme.of(context) + .textTheme + .titleMedium! + .copyWith( + fontSize: 14, + color: Colors.white, + ), + ), + ], + ), + ], + ); + }, + ), + flexibleSpace: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Color.fromARGB(75, 0, 0, 0), + Color.fromARGB(37, 0, 0, 0), + Colors.transparent, + Colors.transparent, + ], + stops: [0, 0.45, 0.8, 1], + ), ), ), - ); - }, - onPageChanged: (index) { - unawaited( - memoriesCacheService.markMemoryAsSeen( - inheritedData.memories[index], - inheritedData.memories.length == index + 1, - ), - ); - inheritedData.indexNotifier.value = index; - }, - itemCount: inheritedData.memories.length, - ), - SafeArea( - top: false, - child: Padding( - padding: const EdgeInsets.only(bottom: 72), - child: ValueListenableBuilder( - builder: (context, value, _) { - return AnimatedSwitcher( - duration: const Duration(milliseconds: 250), - switchInCurve: Curves.easeOut, - switchOutCurve: Curves.easeIn, - child: value - ? Padding( - padding: const EdgeInsets.fromLTRB(16, 4, 16, 12), - child: Hero( - tag: widget.title, - child: Text( - widget.title, - style: getEnteTextTheme(context) - .largeBold - .copyWith( - color: - Colors.white, //same for both themes + backgroundColor: Colors.transparent, + elevation: 0, + ), + body: Stack( + alignment: Alignment.bottomCenter, + children: [ + const _MemoryBlur(), + ValueListenableBuilder( + valueListenable: inheritedData.indexNotifier, + builder: (context, index, _) { + if (index < inheritedData.memories.length - 1) { + final nextFile = inheritedData.memories[index + 1].file; + preloadThumbnail(nextFile); + preloadFile(nextFile); + } + final currentMemory = inheritedData.memories[index]; + final isVideo = + currentMemory.file.fileType == FileType.video; + final currentFile = currentMemory.file; + + return MemoriesPointerGestureListener( + onTap: (PointerEvent event) { + final screenWidth = MediaQuery.sizeOf(context).width; + final goToPreviousTapAreaWidth = screenWidth * 0.20; + if (event.localPosition.dx < + goToPreviousTapAreaWidth) { + _goToPrevious(inheritedData); + } else { + _goToNext(inheritedData); + } + }, + hasPointerNotifier: hasPointerOnScreenNotifier, + child: MemoriesZoomWidget( + key: ValueKey( + currentFile.uploadedFileID ?? currentFile.localID, + ), + scaleController: (controller) { + _zoomAnimationController = controller; + }, + zoomIn: index % 2 == 0, + isVideo: isVideo, + child: FileWidget( + currentFile, + autoPlay: false, + tagPrefix: "memories", + backgroundDecoration: + const BoxDecoration(color: Colors.transparent), + isFromMemories: true, + playbackCallback: (isPlaying) { + _toggleAnimation(pause: !isPlaying); + }, + onFinalFileLoad: ({required int memoryDuration}) { + onFinalFileLoad(memoryDuration); + }, + ), + ), + ); + }, + ), + BottomGradient(showTitle: _showTitle), + Column( + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + ValueListenableBuilder( + valueListenable: _showTitle, + builder: (context, value, _) { + return AnimatedSwitcher( + duration: const Duration(milliseconds: 250), + switchInCurve: Curves.easeOut, + switchOutCurve: Curves.easeIn, + child: value + ? Padding( + padding: const EdgeInsets.fromLTRB( + 32, + 4, + 32, + 12, ), - ), - ), - ) - : showStepProgressIndicator - ? const SizedBox.shrink() - : const MemoryCounter(), - ); - }, - valueListenable: _showTitle, + child: Hero( + tag: widget.title, + child: Text( + widget.title, + style: const TextStyle( + color: Colors.white, + fontSize: 30, + fontFamily: "Montserrat", + ), + textAlign: TextAlign.left, + ), + ), + ) + : showStepProgressIndicator + ? const SizedBox.shrink() + : const MemoryCounter(), + ); + }, + ), + const BottomIcons(), + ], + ), + ], ), ), ), - const BottomGradient(), - const BottomIcons(), - ], + ), ), ); } @@ -332,6 +503,8 @@ class BottomIcons extends StatelessWidget { @override Widget build(BuildContext context) { final inheritedData = FullScreenMemoryData.of(context)!; + final fullScreenState = + context.findAncestorStateOfType<_FullScreenMemoryState>(); return ValueListenableBuilder( valueListenable: inheritedData.indexNotifier, @@ -343,8 +516,10 @@ class BottomIcons extends StatelessWidget { Platform.isAndroid ? Icons.info_outline : CupertinoIcons.info, color: Colors.white, //same for both themes ), - onPressed: () { - showDetailsSheet(context, currentFile); + onPressed: () async { + fullScreenState?._toggleAnimation(pause: true); + await showDetailsSheet(context, currentFile); + fullScreenState?._toggleAnimation(pause: false); }, ), ]; @@ -360,6 +535,7 @@ class BottomIcons extends StatelessWidget { color: Colors.white, //same for both themes ), onPressed: () async { + fullScreenState?._toggleAnimation(pause: true); await showSingleFileDeleteSheet( context, inheritedData @@ -372,6 +548,7 @@ class BottomIcons extends StatelessWidget { }, }, ); + fullScreenState?._toggleAnimation(pause: false); }, ), SizedBox( @@ -386,21 +563,20 @@ class BottomIcons extends StatelessWidget { Icons.adaptive.share, color: Colors.white, //same for both themes ), - onPressed: () { - share(context, [currentFile]); + onPressed: () async { + fullScreenState?._toggleAnimation(pause: true); + await share(context, [currentFile]); + fullScreenState?._toggleAnimation(pause: false); }, ), ); - return SafeArea( - top: false, - child: Container( - alignment: Alignment.bottomCenter, - padding: const EdgeInsets.fromLTRB(12, 0, 12, 20), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: rowChildren, - ), + return Container( + alignment: Alignment.bottomCenter, + padding: const EdgeInsets.fromLTRB(12, 0, 12, 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: rowChildren, ), ); }, @@ -427,26 +603,174 @@ class MemoryCounter extends StatelessWidget { } class BottomGradient extends StatelessWidget { - const BottomGradient({super.key}); + final ValueNotifier showTitle; + const BottomGradient({super.key, required this.showTitle}); @override Widget build(BuildContext context) { return IgnorePointer( - child: Container( - height: 124, - width: double.infinity, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.bottomCenter, - end: Alignment.topCenter, - colors: [ - Colors.black.withOpacity(0.5), //same for both themes - Colors.transparent, - ], - stops: const [0, 0.8], - ), - ), + child: ValueListenableBuilder( + valueListenable: showTitle, + builder: (context, value, _) { + return AnimatedContainer( + duration: const Duration(milliseconds: 875), + curve: Curves.easeOutQuart, + height: value ? 240 : 120, + width: double.infinity, + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + colors: [ + Color.fromARGB(97, 0, 0, 0), + Color.fromARGB(42, 0, 0, 0), + Colors.transparent, + ], + stops: [0, 0.5, 1.0], + ), + ), + ); + }, ), ); } } + +class _MemoryBlur extends StatelessWidget { + const _MemoryBlur(); + + @override + Widget build(BuildContext context) { + final inheritedData = FullScreenMemoryData.of(context)!; + return ValueListenableBuilder( + valueListenable: inheritedData.indexNotifier, + builder: (context, value, _) { + final currentFile = inheritedData.memories[value].file; + if (currentFile.fileType == FileType.video) { + return const SizedBox.shrink(); + } + return AnimatedSwitcher( + duration: const Duration(milliseconds: 750), + switchInCurve: Curves.easeOutExpo, + switchOutCurve: Curves.easeInExpo, + child: ImageFiltered( + key: ValueKey(inheritedData.indexNotifier.value), + imageFilter: ImageFilter.blur( + sigmaX: 100, + sigmaY: 100, + ), + child: ThumbnailWidget( + currentFile, + shouldShowSyncStatus: false, + shouldShowFavoriteIcon: false, + shouldShowVideoOverlayIcon: false, + ), + ), + ); + }, + ); + } +} + +class MemoriesZoomWidget extends StatefulWidget { + final Widget child; + final bool isVideo; + final void Function(AnimationController)? scaleController; + final bool zoomIn; + + const MemoriesZoomWidget({ + super.key, + required this.child, + required this.isVideo, + required this.zoomIn, + this.scaleController, + }); + + @override + State createState() => _MemoriesZoomWidgetState(); +} + +class _MemoriesZoomWidgetState extends State + with TickerProviderStateMixin { + late AnimationController _controller; + late Animation _scaleAnimation; + late Animation _panAnimation; + Random random = Random(); + + @override + void initState() { + super.initState(); + _initAnimation(); + } + + void _initAnimation() { + _controller = AnimationController( + vsync: this, + duration: const Duration( + seconds: 5, + ), + ); + + final startScale = widget.zoomIn ? 1.05 : 1.15; + final endScale = widget.zoomIn ? 1.15 : 1.05; + + final startX = (random.nextDouble() - 0.5) * 0.1; + final startY = (random.nextDouble() - 0.5) * 0.1; + final endX = (random.nextDouble() - 0.5) * 0.1; + final endY = (random.nextDouble() - 0.5) * 0.1; + + _scaleAnimation = Tween( + begin: startScale, + end: endScale, + ).animate( + CurvedAnimation( + parent: _controller, + curve: Curves.easeInOut, + ), + ); + + _panAnimation = Tween( + begin: Offset(startX, startY), + end: Offset(endX, endY), + ).animate( + CurvedAnimation( + parent: _controller, + curve: Curves.easeInOut, + ), + ); + + if (widget.scaleController != null) { + widget.scaleController!(_controller); + } + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.isVideo + ? widget.child + : ClipRect( + child: AnimatedBuilder( + animation: _controller, + child: widget.child, + builder: (context, child) { + return Transform.scale( + scale: _scaleAnimation.value, + child: Transform.translate( + offset: Offset( + _panAnimation.value.dx * 100, + _panAnimation.value.dy * 100, + ), + child: child, + ), + ); + }, + ), + ); + } +} diff --git a/mobile/lib/ui/home/memories/memories_widget.dart b/mobile/lib/ui/home/memories/memories_widget.dart index 03625648b7..52e9dd8a36 100644 --- a/mobile/lib/ui/home/memories/memories_widget.dart +++ b/mobile/lib/ui/home/memories/memories_widget.dart @@ -20,12 +20,11 @@ class MemoriesWidget extends StatefulWidget { } class _MemoriesWidgetState extends State { - late ScrollController _controller; late StreamSubscription _memoriesSettingSubscription; late StreamSubscription _memoriesChangedSubscription; late StreamSubscription _memorySeenSubscription; - late double _maxHeight; - late double _maxWidth; + late double _memoryheight; + late double _memoryWidth; @override void initState() { @@ -48,7 +47,6 @@ class _MemoriesWidgetState extends State { setState(() {}); } }); - _controller = ScrollController(); } @override @@ -57,8 +55,8 @@ class _MemoriesWidgetState extends State { final screenWidth = MediaQuery.sizeOf(context).width; //factor will be 2 for most phones in portrait mode final factor = (screenWidth / 220).ceil(); - _maxWidth = screenWidth / (factor * 2); - _maxHeight = _maxWidth / MemoryCoverWidget.aspectRatio; + _memoryWidth = screenWidth / (factor * 2); + _memoryheight = _memoryWidth / MemoryCoverWidget.aspectRatio; } @override @@ -66,7 +64,6 @@ class _MemoriesWidgetState extends State { _memoriesSettingSubscription.cancel(); _memoriesChangedSubscription.cancel(); _memorySeenSubscription.cancel(); - _controller.dispose(); super.dispose(); } @@ -84,7 +81,7 @@ class _MemoriesWidgetState extends State { builder: (context, snapshot) { if (snapshot.hasError || !snapshot.hasData) { return SizedBox( - height: _maxHeight + 12 + 10, + height: _memoryheight + 12 + 10, child: const EnteLoadingWidget(), ); } else { @@ -121,27 +118,22 @@ class _MemoriesWidgetState extends State { collatedMemories.addAll(seenMemories.map((e) => (e.memories, e.title))); return SizedBox( - height: _maxHeight + MemoryCoverWidget.outerStrokeWidth * 2, + height: _memoryheight + MemoryCoverWidget.outerStrokeWidth * 2, child: ListView.builder( physics: const AlwaysScrollableScrollPhysics( parent: BouncingScrollPhysics(), ), scrollDirection: Axis.horizontal, - controller: _controller, itemCount: collatedMemories.length, itemBuilder: (context, itemIndex) { - final maxScaleOffsetX = - _maxWidth + MemoryCoverWidget.horizontalPadding * 2; - final offsetOfItem = - (_maxWidth + MemoryCoverWidget.horizontalPadding * 2) * itemIndex; return MemoryCoverWidget( memories: collatedMemories[itemIndex].$1, - controller: _controller, - offsetOfItem: offsetOfItem, - maxHeight: _maxHeight, - maxWidth: _maxWidth, - maxScaleOffsetX: maxScaleOffsetX, + allMemories: collatedMemories.map((e) => e.$1).toList(), + height: _memoryheight, + width: _memoryWidth, title: collatedMemories[itemIndex].$2, + allTitle: collatedMemories.map((e) => e.$2).toList(), + currentMemoryIndex: itemIndex, ); }, ), diff --git a/mobile/lib/ui/home/memories/memory_cover_widget.dart b/mobile/lib/ui/home/memories/memory_cover_widget.dart index 55f8db652c..16665f6b2d 100644 --- a/mobile/lib/ui/home/memories/memory_cover_widget.dart +++ b/mobile/lib/ui/home/memories/memory_cover_widget.dart @@ -1,33 +1,34 @@ import "package:flutter/material.dart"; -import "package:flutter/scheduler.dart"; import "package:photos/models/memories/memory.dart"; import "package:photos/theme/colors.dart"; import "package:photos/theme/effects.dart"; import "package:photos/theme/ente_theme.dart"; -import "package:photos/ui/home/memories/full_screen_memory.dart"; +import "package:photos/ui/home/memories/all_memories_page.dart"; import "package:photos/ui/viewer/file/thumbnail_widget.dart"; +import "package:photos/utils/file_util.dart"; import "package:photos/utils/navigation_util.dart"; +// TODO: Use a single instance variable for `allMemories` and `allTitles` class MemoryCoverWidget extends StatefulWidget { final List memories; - final ScrollController controller; - final double offsetOfItem; - final double maxHeight; - final double maxWidth; + final List> allMemories; + final double height; + final double width; static const outerStrokeWidth = 1.0; static const aspectRatio = 0.68; static const horizontalPadding = 2.5; - final double maxScaleOffsetX; final String title; + final List allTitle; + final int currentMemoryIndex; const MemoryCoverWidget({ required this.memories, - required this.controller, - required this.offsetOfItem, - required this.maxHeight, - required this.maxWidth, - required this.maxScaleOffsetX, + required this.allMemories, + required this.height, + required this.width, required this.title, + required this.allTitle, + required this.currentMemoryIndex, super.key, }); @@ -36,6 +37,12 @@ class MemoryCoverWidget extends StatefulWidget { } class _MemoryCoverWidgetState extends State { + @override + void initState() { + super.initState(); + _preloadFirstUnseenMemory(); + } + @override Widget build(BuildContext context) { //memories will be empty if all memories are deleted and setState is called @@ -44,183 +51,180 @@ class _MemoryCoverWidgetState extends State { return const SizedBox.shrink(); } - final widthOfScreen = MediaQuery.sizeOf(context).width; final index = _getNextMemoryIndex(); final title = widget.title; final memory = widget.memories[index]; final isSeen = memory.isSeen(); - final brightness = - SchedulerBinding.instance.platformDispatcher.platformBrightness; + final brightness = Theme.of(context).brightness; - return AnimatedBuilder( - animation: widget.controller, - builder: (context, child) { - final diff = (widget.controller.offset - widget.offsetOfItem) + - widget.maxScaleOffsetX; - final scale = 1 - (diff / widthOfScreen).abs() / 3.7; - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: MemoryCoverWidget.horizontalPadding, - ), - child: GestureDetector( - onTap: () async { - await routeToPage( - context, - FullScreenMemoryDataUpdater( - initialIndex: index, - memories: widget.memories, - child: FullScreenMemory(title, index), - ), - forceCustomPageRoute: true, - ); - setState(() {}); - }, //Adding this row is a workaround for making height of memory cover - //render as [MemoryCoverWidgetNew.height] * scale. Without this, height of rendered memory - //cover will be [MemoryCoverWidgetNew.height]. - child: Row( - children: [ - Container( - height: widget.maxHeight * scale, - width: widget.maxWidth * scale, - decoration: BoxDecoration( - boxShadow: brightness == Brightness.dark - ? [ - const BoxShadow( - color: strokeFainterDark, - spreadRadius: MemoryCoverWidget.outerStrokeWidth, - blurRadius: 0, - ), - ] - : [...shadowFloatFaintestLight], - borderRadius: BorderRadius.circular(5), - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(5), - child: isSeen - ? ColorFiltered( - colorFilter: const ColorFilter.mode( - Color(0xFFBFBFBF), - BlendMode.hue, - ), - child: Stack( - fit: StackFit.expand, - alignment: Alignment.bottomCenter, - children: [ - child!, - Container( - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - Colors.black.withOpacity(0.5), - Colors.transparent, - ], - stops: const [0, 1], - begin: Alignment.bottomCenter, - end: Alignment.topCenter, - ), - ), - ), - Positioned( - bottom: 8 * scale, - child: Transform.scale( - scale: scale, - child: SizedBox( - width: widget.maxWidth, - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - ), - child: Hero( - tag: title, - child: Center( - child: Text( - title, - style: getEnteTextTheme(context) - .miniBold - .copyWith( - color: isSeen - ? textFaintDark - : Colors.white, - ), - textAlign: TextAlign.left, - ), - ), - ), - ), - ), - ), - ), - ], - ), - ) - : Stack( - fit: StackFit.expand, - alignment: Alignment.bottomCenter, - children: [ - child!, - Container( - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - Colors.black.withOpacity(0.5), - Colors.transparent, - ], - stops: const [0, 1], - begin: Alignment.bottomCenter, - end: Alignment.topCenter, - ), - ), - ), - Positioned( - bottom: 8 * scale, - child: Transform.scale( - scale: scale, - child: SizedBox( - width: widget.maxWidth, - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - ), - child: Hero( - tag: title, - child: Center( - child: Text( - title, - style: getEnteTextTheme(context) - .miniBold - .copyWith( - color: Colors.white, - ), - textAlign: TextAlign.left, - ), - ), - ), - ), - ), - ), - ), - ], - ), - ), - ), - ], + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: MemoryCoverWidget.horizontalPadding, + ), + child: GestureDetector( + onTap: () async { + await routeToPage( + context, + forceCustomPageRoute: true, + AllMemoriesPage( + initialPageIndex: widget.currentMemoryIndex, + allMemories: widget.allMemories, + allTitles: widget.allTitle, ), + ); + setState(() {}); + }, + child: Container( + height: widget.height, + width: widget.width, + decoration: BoxDecoration( + boxShadow: brightness == Brightness.dark + ? [ + const BoxShadow( + color: strokeFainterDark, + spreadRadius: MemoryCoverWidget.outerStrokeWidth, + blurRadius: 0, + ), + ] + : [...shadowFloatFaintestLight], + borderRadius: BorderRadius.circular(5), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(5), + child: isSeen + ? ColorFiltered( + colorFilter: const ColorFilter.mode( + Color(0xFFBFBFBF), + BlendMode.hue, + ), + child: Stack( + fit: StackFit.expand, + alignment: Alignment.bottomCenter, + children: [ + Hero( + tag: "memories" + memory.file.tag, + child: ThumbnailWidget( + memory.file, + shouldShowArchiveStatus: false, + shouldShowSyncStatus: false, + key: Key("memories" + memory.file.tag), + ), + ), + Container( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + Colors.black.withOpacity(0.5), + Colors.transparent, + ], + stops: const [0, 1], + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + ), + ), + ), + Positioned( + bottom: 8, + child: SizedBox( + width: widget.width, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + ), + child: Hero( + tag: title, + child: Center( + child: Text( + title, + style: getEnteTextTheme(context) + .miniBold + .copyWith( + color: isSeen + ? textFaintDark + : Colors.white, + ), + textAlign: TextAlign.left, + ), + ), + ), + ), + ), + ), + ], + ), + ) + : Stack( + fit: StackFit.expand, + alignment: Alignment.bottomCenter, + children: [ + Hero( + tag: "memories" + memory.file.tag, + child: ThumbnailWidget( + memory.file, + shouldShowArchiveStatus: false, + shouldShowSyncStatus: false, + key: Key("memories" + memory.file.tag), + ), + ), + Container( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + Colors.black.withOpacity(0.5), + Colors.transparent, + ], + stops: const [0, 1], + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + ), + ), + ), + Positioned( + bottom: 8, + child: SizedBox( + width: widget.width, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + ), + child: Hero( + tag: title, + child: Center( + child: Text( + title, + style: getEnteTextTheme(context) + .miniBold + .copyWith( + color: Colors.white, + ), + textAlign: TextAlign.left, + ), + ), + ), + ), + ), + ), + ], + ), ), - ); - }, - child: Hero( - tag: "memories" + memory.file.tag, - child: ThumbnailWidget( - memory.file, - shouldShowArchiveStatus: false, - shouldShowSyncStatus: false, - key: Key("memories" + memory.file.tag), ), ), ); } + void _preloadFirstUnseenMemory() { + Future.delayed(const Duration(seconds: 5), () { + if (mounted) { + if (widget.memories.isEmpty) return; + + final index = _getNextMemoryIndex(); + preloadThumbnail(widget.memories[index].file); + preloadFile(widget.memories[index].file); + } + }); + } + // Returns either the first unseen memory or the memory that succeeds the // last seen memory int _getNextMemoryIndex() { diff --git a/mobile/lib/ui/home/memories/memory_progress_indicator.dart b/mobile/lib/ui/home/memories/memory_progress_indicator.dart new file mode 100644 index 0000000000..0028215197 --- /dev/null +++ b/mobile/lib/ui/home/memories/memory_progress_indicator.dart @@ -0,0 +1,107 @@ +import "package:flutter/material.dart"; + +class MemoryProgressIndicator extends StatefulWidget { + final int totalSteps; + final int currentIndex; + final Duration duration; + final Color selectedColor; + final Color unselectedColor; + final double height; + final double gap; + final void Function(AnimationController)? animationController; + final VoidCallback? onComplete; + + const MemoryProgressIndicator({ + super.key, + required this.totalSteps, + required this.currentIndex, + this.duration = const Duration(seconds: 5), + this.selectedColor = Colors.white, + this.unselectedColor = Colors.white54, + this.height = 2.0, + this.gap = 4.0, + this.animationController, + this.onComplete, + }); + + @override + State createState() => + _MemoryProgressIndicatorState(); +} + +class _MemoryProgressIndicatorState extends State + with SingleTickerProviderStateMixin { + late AnimationController _animationController; + late Animation _animation; + + @override + void initState() { + super.initState(); + _animationController = AnimationController( + vsync: this, + duration: widget.duration, + ); + + _animation = + Tween(begin: 0.0, end: 1.0).animate(_animationController); + + if (widget.animationController != null) { + widget.animationController!(_animationController); + } + + _animationController.addStatusListener((status) { + if (status == AnimationStatus.completed && widget.onComplete != null) { + widget.onComplete!(); + } + }); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Row( + children: List.generate(widget.totalSteps, (index) { + return Expanded( + child: Padding( + padding: EdgeInsets.only(right: widget.gap), + child: index < widget.currentIndex + ? Container( + height: widget.height, + decoration: BoxDecoration( + color: widget.selectedColor, + borderRadius: BorderRadius.circular(12), + ), + ) + : index == widget.currentIndex + ? AnimatedBuilder( + animation: _animation, + builder: (context, child) { + return LinearProgressIndicator( + value: _animation.value, + backgroundColor: widget.unselectedColor, + valueColor: AlwaysStoppedAnimation( + widget.selectedColor, + ), + minHeight: widget.height, + borderRadius: BorderRadius.circular(12), + ); + }, + ) + : Container( + height: widget.height, + decoration: BoxDecoration( + color: widget.unselectedColor, + borderRadius: BorderRadius.circular(12), + ), + ), + ), + ); + }), + ); + } +} diff --git a/mobile/lib/ui/home/status_bar_widget.dart b/mobile/lib/ui/home/status_bar_widget.dart index f4cb9608ef..37c013e33c 100644 --- a/mobile/lib/ui/home/status_bar_widget.dart +++ b/mobile/lib/ui/home/status_bar_widget.dart @@ -39,6 +39,7 @@ class _StatusBarWidgetState extends State { bool _showStatus = false; bool _showErrorBanner = false; bool _showMlBanner = !flagService.hasGrantedMLConsent && + flagService.hasSyncedAccountFlags() && !localSettings.hasSeenMLEnablingBanner; Error? _syncError; diff --git a/mobile/lib/ui/notification/update/change_log_page.dart b/mobile/lib/ui/notification/update/change_log_page.dart index 84b95e3262..e386546fb2 100644 --- a/mobile/lib/ui/notification/update/change_log_page.dart +++ b/mobile/lib/ui/notification/update/change_log_page.dart @@ -1,5 +1,8 @@ +import "dart:io"; + import 'package:flutter/material.dart'; import "package:photos/generated/l10n.dart"; +import "package:photos/l10n/l10n.dart"; import "package:photos/service_locator.dart"; import 'package:photos/theme/ente_theme.dart'; import 'package:photos/ui/components/buttons/button_widget.dart'; @@ -33,11 +36,10 @@ class _ChangeLogPageState extends State { ), Container( alignment: Alignment.centerLeft, - child: const Padding( - padding: EdgeInsets.symmetric(horizontal: 16.0), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), child: TitleBarTitleWidget( - // title: S.of(context).whatsNew, - title: "v1.1.0", + title: S.of(context).whatsNew, ), ), ), @@ -101,28 +103,29 @@ class _ChangeLogPageState extends State { final List items = []; items.addAll([ ChangeLogEntry( - "On This Day", - "You can now see a new memory called \"On This Day\" showing photos of a date across multiple years. Moreover, you will receive an opt-out notification every morning to check out this new memory.", + context.l10n.cLTitle4, + context.l10n.cLDesc4, ), ChangeLogEntry( - "New Widgets", - "We have added new widgets for albums and people. You can customise which albums or people you want to see in these widgets as well.", + context.l10n.cLTitle3, + context.l10n.cLDesc3, ), ChangeLogEntry( - "Shareable Favorites", - "You can now share your favorites to your contacts just like any other album.", + context.l10n.cLTitle5, + context.l10n.cLDesc5, + ), + if (!Platform.isAndroid) + ChangeLogEntry( + context.l10n.cLTitle2, + context.l10n.cLDesc2, + ), + ChangeLogEntry( + context.l10n.cLTitle6, + context.l10n.cLDesc6, ), ChangeLogEntry( - "Albums Improvements", - "We have redesigned the albums screen so you can select multiple albums and take actions like share, hide, archive, delete on all selected albums quickly.", - ), - ChangeLogEntry( - "Add to Multiple Albums", - "You can now select multiple albums when you want to add a photo to an album.", - ), - ChangeLogEntry( - "Albums in Contact Page", - "We have updated the contacts page to show you all the albums shared with you by the contact, so you can browse someone's shared library easily.", + context.l10n.cLTitle1, + context.l10n.cLDesc1, ), ]); diff --git a/mobile/lib/ui/payment/payment_web_page.dart b/mobile/lib/ui/payment/payment_web_page.dart index 23b1b66a74..ba2cf497ef 100644 --- a/mobile/lib/ui/payment/payment_web_page.dart +++ b/mobile/lib/ui/payment/payment_web_page.dart @@ -182,7 +182,7 @@ class _PaymentWebPageState extends State { Future _handlePaymentResponse(Uri uri) async { final queryParams = uri.queryParameters; final paymentStatus = uri.queryParameters['status'] ?? ''; - _logger.fine('handle payment response with status $paymentStatus'); + _logger.info('handle payment response with status $paymentStatus'); if (paymentStatus == 'success') { await _handlePaymentSuccess(queryParams); } else if (paymentStatus == 'fail') { diff --git a/mobile/lib/ui/settings/advanced_settings_screen.dart b/mobile/lib/ui/settings/advanced_settings_screen.dart index 4da030fdd2..d1b9ccfbd1 100644 --- a/mobile/lib/ui/settings/advanced_settings_screen.dart +++ b/mobile/lib/ui/settings/advanced_settings_screen.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import "package:photos/core/error-reporting/super_logging.dart"; import "package:photos/generated/l10n.dart"; import "package:photos/service_locator.dart"; -import "package:photos/services/preview_video_store.dart"; +import "package:photos/services/video_preview_service.dart"; import 'package:photos/theme/ente_theme.dart'; import 'package:photos/ui/components/buttons/icon_button_widget.dart'; import 'package:photos/ui/components/captioned_text_widget.dart'; @@ -139,13 +139,13 @@ class AdvancedSettingsScreen extends StatelessWidget { singleBorderRadius: 8, alignCaptionedTextToLeft: true, trailingWidget: ToggleSwitchWidget( - value: () => PreviewVideoStore + value: () => VideoPreviewService .instance.isVideoStreamingEnabled, onChanged: () async { - final isEnabled = PreviewVideoStore + final isEnabled = VideoPreviewService .instance.isVideoStreamingEnabled; - await PreviewVideoStore.instance + await VideoPreviewService.instance .setIsVideoStreamingEnabled(!isEnabled); }, ), diff --git a/mobile/lib/ui/settings/debug/ml_debug_section_widget.dart b/mobile/lib/ui/settings/debug/ml_debug_section_widget.dart index b63944fa72..7cffcf77f0 100644 --- a/mobile/lib/ui/settings/debug/ml_debug_section_widget.dart +++ b/mobile/lib/ui/settings/debug/ml_debug_section_widget.dart @@ -11,7 +11,6 @@ import "package:photos/services/machine_learning/face_ml/person/person_service.d import "package:photos/services/machine_learning/ml_indexing_isolate.dart"; import 'package:photos/services/machine_learning/ml_service.dart'; import "package:photos/services/machine_learning/semantic_search/semantic_search_service.dart"; -import "package:photos/services/memory_home_widget_service.dart"; import "package:photos/services/notification_service.dart"; import 'package:photos/theme/ente_theme.dart'; import 'package:photos/ui/components/captioned_text_widget.dart'; @@ -117,7 +116,6 @@ class _MLDebugSectionWidgetState extends State { onTap: () async { try { await NotificationService.instance.scheduleNotification( - "test", "test", id: 10, dateTime: DateTime.now().add( @@ -142,7 +140,6 @@ class _MLDebugSectionWidgetState extends State { onTap: () async { try { await NotificationService.instance.scheduleNotification( - "test", "test", id: 11, dateTime: DateTime.now().add( @@ -167,7 +164,6 @@ class _MLDebugSectionWidgetState extends State { onTap: () async { try { await NotificationService.instance.scheduleNotification( - "test", "test", id: 12, dateTime: DateTime.now().add( @@ -435,28 +431,6 @@ class _MLDebugSectionWidgetState extends State { }, ), sectionOptionSpacing, - MenuItemWidget( - captionedTextWidget: const CaptionedTextWidget( - title: "Force memory widget data refresh", - ), - pressedColor: getEnteColorScheme(context).fillFaint, - trailingIcon: Icons.chevron_right_outlined, - trailingIconIsMuted: true, - onTap: () async => - await MemoryHomeWidgetService.instance.initMemoryHomeWidget(true), - ), - sectionOptionSpacing, - MenuItemWidget( - captionedTextWidget: const CaptionedTextWidget( - title: "Change memory widget picture", - ), - pressedColor: getEnteColorScheme(context).fillFaint, - trailingIcon: Icons.chevron_right_outlined, - trailingIconIsMuted: true, - onTap: () async => await MemoryHomeWidgetService.instance - .initMemoryHomeWidget(false), - ), - sectionOptionSpacing, MenuItemWidget( captionedTextWidget: const CaptionedTextWidget( title: "Sync person mappings ", diff --git a/mobile/lib/ui/settings/gallery_settings_screen.dart b/mobile/lib/ui/settings/gallery_settings_screen.dart index 2fc5864cc3..4cbb43182d 100644 --- a/mobile/lib/ui/settings/gallery_settings_screen.dart +++ b/mobile/lib/ui/settings/gallery_settings_screen.dart @@ -107,10 +107,11 @@ class _GallerySettingsScreenState extends State { await memoriesCacheService.setShowAnyMemories( !memoriesCacheService.showAnyMemories, ); - unawaited( - MemoryHomeWidgetService.instance - .initMemoryHomeWidget(true), - ); + if (!memoriesCacheService.showAnyMemories) { + unawaited( + MemoryHomeWidgetService.instance.clearWidget(), + ); + } setState(() {}); }, ), diff --git a/mobile/lib/ui/settings/general_section_widget.dart b/mobile/lib/ui/settings/general_section_widget.dart index b1ebd21927..e4f5df18cc 100644 --- a/mobile/lib/ui/settings/general_section_widget.dart +++ b/mobile/lib/ui/settings/general_section_widget.dart @@ -46,7 +46,6 @@ class GeneralSectionWidget extends StatelessWidget { routeToPage( context, const ReferralScreen(), - forceCustomPageRoute: true, ); }, ), diff --git a/mobile/lib/ui/settings/ml/machine_learning_settings_page.dart b/mobile/lib/ui/settings/ml/machine_learning_settings_page.dart index 5db7a028ac..82c81e3967 100644 --- a/mobile/lib/ui/settings/ml/machine_learning_settings_page.dart +++ b/mobile/lib/ui/settings/ml/machine_learning_settings_page.dart @@ -54,7 +54,7 @@ class _MachineLearningSettingsPageState enable: true, wakeLockFor: WakeLockFor.machineLearningSettingsScreen, ); - machineLearningController.forceOverrideML(turnOn: true); + computeController.forceOverrideML(turnOn: true); if (!MLIndexingIsolate.instance.areModelsDownloaded) { _timer = Timer.periodic(const Duration(seconds: 10), (timer) { if (mounted) { @@ -74,7 +74,7 @@ class _MachineLearningSettingsPageState enable: false, wakeLockFor: WakeLockFor.machineLearningSettingsScreen, ); - machineLearningController.forceOverrideML(turnOn: false); + computeController.forceOverrideML(turnOn: false); _timer?.cancel(); _advancedOptionsTimer?.cancel(); } @@ -429,13 +429,13 @@ class MLStatusWidget extends StatefulWidget { class MLStatusWidgetState extends State { Timer? _timer; - bool _isDeviceHealthy = machineLearningController.isDeviceHealthy; + bool _isDeviceHealthy = computeController.isDeviceHealthy; @override void initState() { super.initState(); _timer = Timer.periodic(const Duration(seconds: 10), (timer) { MLService.instance.triggerML(); - _isDeviceHealthy = machineLearningController.isDeviceHealthy; + _isDeviceHealthy = computeController.isDeviceHealthy; setState(() {}); }); } diff --git a/mobile/lib/ui/settings/notification_settings_screen.dart b/mobile/lib/ui/settings/notification_settings_screen.dart index de4df89574..ee9862fe4b 100644 --- a/mobile/lib/ui/settings/notification_settings_screen.dart +++ b/mobile/lib/ui/settings/notification_settings_screen.dart @@ -102,9 +102,36 @@ class NotificationSettingsScreen extends StatelessWidget { alignCaptionedTextToLeft: true, isGestureDetectorDisabled: true, ), + MenuSectionDescriptionWidget( + content: S + .of(context) + .onThisDayNotificationExplanation, + ), + sectionOptionSpacing, + MenuItemWidget( + captionedTextWidget: CaptionedTextWidget( + title: S.of(context).birthdays, + ), + menuItemColor: colorScheme.fillFaint, + trailingWidget: ToggleSwitchWidget( + value: () => + NotificationService.instance + .hasGrantedPermissions() && + localSettings.birthdayNotificationsEnabled, + onChanged: () async { + await NotificationService.instance + .requestPermissions(); + await memoriesCacheService + .toggleBirthdayNotifications(); + }, + ), + singleBorderRadius: 8, + alignCaptionedTextToLeft: true, + isGestureDetectorDisabled: true, + ), MenuSectionDescriptionWidget( content: - S.of(context).onThisDayNotificationExplanation, + S.of(context).receiveRemindersOnBirthdays, ), ], ), diff --git a/mobile/lib/ui/settings/pending_sync/pending_sync_info_screen.dart b/mobile/lib/ui/settings/pending_sync/pending_sync_info_screen.dart index e00dce529b..4c51486d57 100644 --- a/mobile/lib/ui/settings/pending_sync/pending_sync_info_screen.dart +++ b/mobile/lib/ui/settings/pending_sync/pending_sync_info_screen.dart @@ -82,6 +82,12 @@ class _PendingSyncInfoScreenState extends State { ".decrypted", allowCacheClear: false, ), + PathInfoStorageItem.name( + tempDownload, + "Partial Download", + "_part", + allowCacheClear: true, + ), PathInfoStorageItem.name( tempDownload, "Video Preview", diff --git a/mobile/lib/ui/settings/widgets/albums_widget_settings.dart b/mobile/lib/ui/settings/widgets/albums_widget_settings.dart index 03ec9e9b42..e6cbf9b867 100644 --- a/mobile/lib/ui/settings/widgets/albums_widget_settings.dart +++ b/mobile/lib/ui/settings/widgets/albums_widget_settings.dart @@ -101,10 +101,8 @@ class _AlbumsWidgetSettingsState extends State { .map((e) => e.id.toString()) .toList(); await AlbumHomeWidgetService.instance - .setSelectedAlbums(albums); + .updateSelectedAlbums(albums); Navigator.pop(context); - await AlbumHomeWidgetService.instance - .albumsChanged(); } : null, isDisabled: _selectedAlbums.albums.isEmpty, @@ -124,7 +122,7 @@ class _AlbumsWidgetSettingsState extends State { flexibleSpaceTitle: TitleBarTitleWidget( title: S.of(context).albums, ), - expandedHeight: 120, + expandedHeight: MediaQuery.textScalerOf(context).scale(120), flexibleSpaceCaption: hasInstalledAny ? S.of(context).albumsWidgetDesc : context.l10n.addAlbumWidgetPrompt, diff --git a/mobile/lib/ui/settings/widgets/memories_widget_settings.dart b/mobile/lib/ui/settings/widgets/memories_widget_settings.dart index 51a0d6310c..7deecfdf73 100644 --- a/mobile/lib/ui/settings/widgets/memories_widget_settings.dart +++ b/mobile/lib/ui/settings/widgets/memories_widget_settings.dart @@ -11,6 +11,7 @@ import "package:photos/ui/components/menu_item_widget/menu_item_widget.dart"; import 'package:photos/ui/components/title_bar_title_widget.dart'; import 'package:photos/ui/components/title_bar_widget.dart'; import "package:photos/ui/components/toggle_switch_widget.dart"; +import "package:photos/utils/standalone/debouncer.dart"; class MemoriesWidgetSettings extends StatefulWidget { const MemoriesWidgetSettings({super.key}); @@ -28,6 +29,8 @@ class _MemoriesWidgetSettingsState extends State { late final bool isMLEnabled; + late Debouncer _changeMemoriesSettings; + @override void initState() { super.initState(); @@ -44,13 +47,14 @@ class _MemoriesWidgetSettingsState extends State { } Future initVariables() async { + _changeMemoriesSettings = Debouncer(const Duration(milliseconds: 2500)); isMLEnabled = flagService.hasGrantedMLConsent; isYearlyMemoriesEnabled = - await MemoryHomeWidgetService.instance.getSelectedLastYearMemories(); + MemoryHomeWidgetService.instance.hasLastYearMemoriesSelected(); isSmartMemoriesEnabled = - await MemoryHomeWidgetService.instance.getSelectedMLMemories(); + MemoryHomeWidgetService.instance.getMLMemoriesSelected(); isOnThisDayMemoriesEnabled = - await MemoryHomeWidgetService.instance.getSelectedOnThisDayMemories(); + MemoryHomeWidgetService.instance.getOnThisDayMemoriesSelected(); if (isYearlyMemoriesEnabled == null || isSmartMemoriesEnabled == null || @@ -78,12 +82,13 @@ class _MemoriesWidgetSettingsState extends State { } Future updateVariables() async { + _changeMemoriesSettings.run(MemoryHomeWidgetService.instance.memoryChanged); await MemoryHomeWidgetService.instance - .setSelectedLastYearMemories(isYearlyMemoriesEnabled!); + .setLastYearMemoriesSelected(isYearlyMemoriesEnabled!); await MemoryHomeWidgetService.instance .setSelectedMLMemories(isSmartMemoriesEnabled!); await MemoryHomeWidgetService.instance - .setSelectedOnThisDayMemories(isOnThisDayMemoriesEnabled!); + .setOnThisDayMemoriesSelected(isOnThisDayMemoriesEnabled!); await MemoryHomeWidgetService.instance.memoryChanged(); } @@ -99,7 +104,7 @@ class _MemoriesWidgetSettingsState extends State { flexibleSpaceTitle: TitleBarTitleWidget( title: S.of(context).memories, ), - expandedHeight: 120, + expandedHeight: MediaQuery.textScalerOf(context).scale(120), flexibleSpaceCaption: hasInstalledAny ? S.of(context).memoriesWidgetDesc : context.l10n.addMemoriesWidgetPrompt, @@ -161,7 +166,7 @@ class _MemoriesWidgetSettingsState extends State { isYearlyMemoriesEnabled = !isYearlyMemoriesEnabled!; }); - await updateVariables(); + updateVariables().ignore(); }, ), singleBorderRadius: 8, @@ -184,7 +189,7 @@ class _MemoriesWidgetSettingsState extends State { isOnThisDayMemoriesEnabled = !isOnThisDayMemoriesEnabled!; }); - await updateVariables(); + updateVariables().ignore(); }, ), singleBorderRadius: 8, @@ -208,7 +213,8 @@ class _MemoriesWidgetSettingsState extends State { isSmartMemoriesEnabled = !isSmartMemoriesEnabled!; }); - await updateVariables(); + + updateVariables().ignore(); }, ), singleBorderRadius: 8, diff --git a/mobile/lib/ui/settings/widgets/people_widget_settings.dart b/mobile/lib/ui/settings/widgets/people_widget_settings.dart index 760d7df100..fc78d8332f 100644 --- a/mobile/lib/ui/settings/widgets/people_widget_settings.dart +++ b/mobile/lib/ui/settings/widgets/people_widget_settings.dart @@ -1,3 +1,5 @@ +import "dart:async"; + import 'package:flutter/material.dart'; import "package:photos/generated/l10n.dart"; import "package:photos/l10n/l10n.dart"; @@ -66,13 +68,13 @@ class _PeopleWidgetSettingsState extends State { onTap: _selectedPeople.personIds.isEmpty ? null : () async { - await PeopleHomeWidgetService.instance - .setSelectedPeople( - _selectedPeople.personIds.toList(), + unawaited( + PeopleHomeWidgetService.instance + .setSelectedPeople( + _selectedPeople.personIds.toList(), + ), ); Navigator.pop(context); - await PeopleHomeWidgetService.instance - .peopleChanged(); }, ); }, @@ -86,7 +88,7 @@ class _PeopleWidgetSettingsState extends State { flexibleSpaceTitle: TitleBarTitleWidget( title: S.of(context).people, ), - expandedHeight: 120, + expandedHeight: MediaQuery.textScalerOf(context).scale(120), flexibleSpaceCaption: hasInstalledAny ? S.of(context).peopleWidgetDesc : context.l10n.addPeopleWidgetPrompt, @@ -122,7 +124,7 @@ class _PeopleWidgetSettingsState extends State { ), ) else - SliverToBoxAdapter( + SliverFillRemaining( child: PeopleSectionAllWidget( selectedPeople: _selectedPeople, namedOnly: true, diff --git a/mobile/lib/ui/sharing/user_avator_widget.dart b/mobile/lib/ui/sharing/user_avator_widget.dart index 7acd869f87..baab01b249 100644 --- a/mobile/lib/ui/sharing/user_avator_widget.dart +++ b/mobile/lib/ui/sharing/user_avator_widget.dart @@ -1,6 +1,5 @@ import "dart:async"; -import "package:collection/collection.dart"; import 'package:flutter/material.dart'; import "package:logging/logging.dart"; import "package:photos/core/configuration.dart"; @@ -8,11 +7,10 @@ import "package:photos/core/event_bus.dart"; import "package:photos/events/people_changed_event.dart"; import "package:photos/extensions/user_extension.dart"; import "package:photos/models/api/collection/user.dart"; -import "package:photos/models/file/file.dart"; import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; import "package:photos/theme/colors.dart"; import 'package:photos/theme/ente_theme.dart'; -import "package:photos/ui/viewer/search/result/person_face_widget.dart"; +import "package:photos/ui/viewer/people/person_face_widget.dart"; import "package:photos/utils/standalone/debouncer.dart"; import 'package:tuple/tuple.dart'; @@ -39,7 +37,8 @@ class UserAvatarWidget extends StatefulWidget { class _UserAvatarWidgetState extends State { Future? _personID; - EnteFile? _faceThumbnail; + bool _canUsePersonFaceWidget = false; + int lastSyncTimeForKey = 0; final _logger = Logger("_UserAvatarWidgetState"); late final StreamSubscription _peopleChangedSubscription; final _debouncer = Debouncer( @@ -70,22 +69,17 @@ class _UserAvatarWidgetState extends State { Future _reload() async { _debouncer.run(() async { + if (!mounted) return; setState(() { - if (PersonService - .instance.emailToPartialPersonDataMapCache[widget.user.email] != - null) { - _personID = PersonService.instance.getPersons().then((people) async { - final person = people.firstWhereOrNull( - (person) => person.data.email == widget.user.email, - ); - if (person != null) { - _faceThumbnail = - await PersonService.instance.getThumbnailFileOfPerson(person); - } - return person?.remoteID; - }); + final data = PersonService + .instance.emailToPartialPersonDataMapCache[widget.user.email]; + if (data != null && data.containsKey(PersonService.kPersonIDKey)) { + _canUsePersonFaceWidget = true; + _personID = Future.value(data[PersonService.kPersonIDKey]); + lastSyncTimeForKey = PersonService.instance.lastRemoteSyncTime(); } else { - _personID = null; + _canUsePersonFaceWidget = false; + _personID = Future.value(null); } }); }); @@ -94,7 +88,6 @@ class _UserAvatarWidgetState extends State { @override Widget build(BuildContext context) { final double size = getAvatarSize(widget.type); - return _personID != null ? Container( padding: const EdgeInsets.all(0.5), @@ -117,24 +110,24 @@ class _UserAvatarWidgetState extends State { if (snapshot.hasData) { final personID = snapshot.data as String; return ClipOval( - child: _faceThumbnail == null - ? _FirstLetterCircularAvatar( - user: widget.user, - currentUserID: widget.currentUserID, - thumbnailView: widget.thumbnailView, - type: widget.type, - ) - : PersonFaceWidget( - _faceThumbnail!, + child: _canUsePersonFaceWidget + ? PersonFaceWidget( + key: ValueKey('$personID-$lastSyncTimeForKey'), personId: personID, onErrorCallback: () { if (mounted) { setState(() { _personID = null; - _faceThumbnail = null; + _canUsePersonFaceWidget = false; }); } }, + ) + : _FirstLetterCircularAvatar( + user: widget.user, + currentUserID: widget.currentUserID, + thumbnailView: widget.thumbnailView, + type: widget.type, ), ); } else if (snapshot.hasError) { diff --git a/mobile/lib/ui/tabs/home_widget.dart b/mobile/lib/ui/tabs/home_widget.dart index 7414637e70..247907446b 100644 --- a/mobile/lib/ui/tabs/home_widget.dart +++ b/mobile/lib/ui/tabs/home_widget.dart @@ -67,6 +67,7 @@ import "package:photos/ui/settings_page.dart"; import "package:photos/ui/tabs/shared_collections_tab.dart"; import "package:photos/ui/tabs/user_collections_tab.dart"; import "package:photos/ui/viewer/actions/file_viewer.dart"; +import "package:photos/ui/viewer/file/detail_page.dart"; import "package:photos/ui/viewer/gallery/collection_page.dart"; import "package:photos/ui/viewer/gallery/shared_public_collection_page.dart"; import "package:photos/ui/viewer/search/search_widget.dart"; @@ -127,9 +128,7 @@ class _HomeWidgetState extends State { super.initState(); if (LocalSyncService.instance.hasCompletedFirstImport()) { - MemoryHomeWidgetService.instance.checkPendingMemorySync(); - PeopleHomeWidgetService.instance.checkPendingPeopleSync(); - AlbumHomeWidgetService.instance.checkPendingAlbumsSync(); + syncWidget(); } _tabChangedEventSubscription = Bus.instance.on().listen((event) { @@ -160,6 +159,8 @@ class _HomeWidgetState extends State { _accountConfiguredEvent = Bus.instance.on().listen((event) { setState(() {}); + // fetch user flags on login + flagService.flags; }); _triggerLogoutEvent = Bus.instance.on().listen((event) async { @@ -193,9 +194,7 @@ class _HomeWidgetState extends State { () { if (mounted) { setState(() {}); - MemoryHomeWidgetService.instance.checkPendingMemorySync(); - AlbumHomeWidgetService.instance.checkPendingAlbumsSync(); - PeopleHomeWidgetService.instance.checkPendingPeopleSync(); + syncWidget(); } }, ); @@ -276,8 +275,33 @@ class _HomeWidgetState extends State { } } - Future _handlePublicAlbumLink(Uri uri) async { + Future syncWidget() async { + await Future.delayed(const Duration(seconds: 5)); + + _logger.info("Syncing home widget"); + await AlbumHomeWidgetService.instance.checkPendingAlbumsSync(); + await PeopleHomeWidgetService.instance.checkPendingPeopleSync(); + await MemoryHomeWidgetService.instance.checkPendingMemorySync(); + } + + final Map _linkedPublicAlbums = {}; + Future _handlePublicAlbumLink(Uri uri, String via) async { try { + _logger.info("Handling public album link: via $via"); + final int currentTime = DateTime.now().millisecondsSinceEpoch; + final bool isInitialStream = via.toLowerCase().contains('initial'); + if (_linkedPublicAlbums.containsKey(uri)) { + final (lastInitialLink, lastTime) = _linkedPublicAlbums[uri]!; + // for initial stream, wait for 30 seconds to ignore duplicate links event + if (currentTime - lastTime < (lastInitialLink ? 30000 : 2000)) { + _logger.info( + "ignore was it has handled $lastInitialLink at epoch $lastTime", + ); + return; + } + } + _linkedPublicAlbums[uri] = (isInitialStream, currentTime); + final Collection collection = await CollectionsService.instance .getCollectionFromPublicLink(context, uri); final existingCollection = @@ -372,7 +396,7 @@ class _HomeWidgetState extends State { ); await dialog.hide(); - await routeToPage( + routeToPage( context, SharedPublicCollectionPage( files: sharedFiles, @@ -381,7 +405,19 @@ class _HomeWidgetState extends State { null, ), ), - ); + ).ignore(); + if (sharedFiles.length == 1) { + await routeToPage( + context, + DetailPage( + DetailPageConfiguration( + sharedFiles, + 0, + "sharedPublicCollection", + ), + ), + ); + } } } catch (e, s) { _logger.severe("Failed to handle public album link", e, s); @@ -453,7 +489,7 @@ class _HomeWidgetState extends State { } if (value[0].path.contains("albums.ente.io")) { final uri = Uri.parse(value[0].path); - _handlePublicAlbumLink(uri); + _handlePublicAlbumLink(uri, "sharedIntent.getMediaStream"); return; } @@ -520,7 +556,7 @@ class _HomeWidgetState extends State { if (mounted) { if (value.isNotEmpty && value[0].path.contains("albums.ente.io")) { final uri = Uri.parse(value[0].path); - _handlePublicAlbumLink(uri); + _handlePublicAlbumLink(uri, "sharedIntent.getInitialMedia"); return; } @@ -553,7 +589,7 @@ class _HomeWidgetState extends State { final initialUri = await appLinks.getInitialLink(); if (initialUri != null) { if (initialUri.toString().contains("albums.ente.io")) { - await _handlePublicAlbumLink(initialUri); + await _handlePublicAlbumLink(initialUri, "appLinks.getInitialLink"); } else { _logger.info( "uri doesn't contain 'albums.ente.io' in initial public album deep link", @@ -572,7 +608,7 @@ class _HomeWidgetState extends State { (Uri? uri) { if (uri != null) { if (uri.toString().contains("albums.ente.io")) { - _handlePublicAlbumLink(uri); + _handlePublicAlbumLink(uri, "appLinks.uriLinkStream"); } else { _logger.info( "uri doesn't contain 'albums.ente.io' in public album link subscription", @@ -611,10 +647,16 @@ class _HomeWidgetState extends State { } else { Navigator.pop(context); } - } else { - Bus.instance - .fire(TabChangedEvent(0, TabChangedEventSource.backButton)); + return; } + if (_selectedTabIndex == 1) { + if (_selectedAlbums.albums.isNotEmpty) { + _selectedAlbums.clearAll(); + return; + } + } + Bus.instance + .fire(TabChangedEvent(0, TabChangedEventSource.backButton)); }, child: Scaffold( drawerScrimColor: getEnteColorScheme(context).strokeFainter, @@ -661,7 +703,7 @@ class _HomeWidgetState extends State { } if (!permissionService.hasGrantedPermissions()) { entityService.syncEntities().then((_) { - PersonService.instance.resetEmailToPartialPersonDataCache(); + PersonService.instance.refreshPersonCache(); }); return const GrantPermissionsWidget(); } @@ -792,7 +834,7 @@ class _HomeWidgetState extends State { // Parse the link and warn the user, if it is not correct, // but keep in mind it could be `null`. if (initialLink != null) { - _logger.info("Initial link received: " + initialLink.toString()); + _logger.info("Initial link received: host ${initialLink.host}"); _getCredentials(context, initialLink); return true; } else { @@ -807,7 +849,7 @@ class _HomeWidgetState extends State { // Attach a listener to the stream appLinks.uriLinkStream.listen( (link) { - _logger.info("Link received: " + link.toString()); + _logger.info("Link received: host ${link.host}"); _getCredentials(context, link); }, onError: (err) { @@ -862,9 +904,16 @@ class _HomeWidgetState extends State { if (payload != null) { debugPrint('notification payload: $payload'); if (payload.toLowerCase().contains("onthisday")) { + _logger.info("On this day notification received"); // ignore: unawaited_futures memoriesCacheService.goToOnThisDayMemory(context); + } else if (payload.toLowerCase().contains("birthday")) { + _logger.info("Birthday notification received"); + final personID = payload.substring("birthday_".length); + // ignore: unawaited_futures + memoriesCacheService.goToPersonMemory(context, personID); } else { + _logger.info("Album notification received"); final collectionID = Uri.parse(payload).queryParameters["collectionID"]; if (collectionID != null) { final collection = CollectionsService.instance diff --git a/mobile/lib/ui/tabs/shared/quick_link_album_item.dart b/mobile/lib/ui/tabs/shared/quick_link_album_item.dart index f5bf9fd6da..8153d37543 100644 --- a/mobile/lib/ui/tabs/shared/quick_link_album_item.dart +++ b/mobile/lib/ui/tabs/shared/quick_link_album_item.dart @@ -35,7 +35,7 @@ class QuickLinkAlbumItem extends StatelessWidget { isSelected ? colorScheme.strokeMuted : colorScheme.strokeFainter, ), borderRadius: const BorderRadius.all( - Radius.circular(2), + Radius.circular(6), ), ), child: Row( @@ -57,9 +57,7 @@ class QuickLinkAlbumItem extends StatelessWidget { return Hero( tag: heroTag, child: ClipRRect( - borderRadius: const BorderRadius.horizontal( - left: Radius.circular(2), - ), + borderRadius: BorderRadius.circular(4), child: ThumbnailWidget( snapshot.data!, key: ValueKey(heroTag), diff --git a/mobile/lib/ui/tabs/shared_collections_tab.dart b/mobile/lib/ui/tabs/shared_collections_tab.dart index a3d9ec0e1e..9f81a2428c 100644 --- a/mobile/lib/ui/tabs/shared_collections_tab.dart +++ b/mobile/lib/ui/tabs/shared_collections_tab.dart @@ -60,6 +60,10 @@ class _SharedCollectionsTabState extends State const Duration(milliseconds: 500), ); + static const maxThumbnailWidth = 224.0; + static const crossAxisSpacing = 8.0; + static const horizontalPadding = 16.0; + @override void initState() { super.initState(); @@ -135,9 +139,14 @@ class _SharedCollectionsTabState extends State } Widget _getSharedCollectionsGallery(SharedCollections collections) { - const maxThumbnailWidth = 160.0; const maxQuickLinks = 4; final numberOfQuickLinks = collections.quickLinks.length; + final double screenWidth = MediaQuery.sizeOf(context).width; + final int albumsCountInRow = max(screenWidth ~/ maxThumbnailWidth, 3); + final totalHorizontalPadding = (albumsCountInRow - 1) * crossAxisSpacing; + final sideOfThumbnail = + (screenWidth - totalHorizontalPadding - horizontalPadding) / + albumsCountInRow; const quickLinkTitleHeroTag = "quick_link_title"; final SectionTitle sharedWithYou = SectionTitle(title: S.of(context).sharedWithYou); @@ -150,195 +159,188 @@ class _SharedCollectionsTabState extends State margin: const EdgeInsets.only(bottom: 50), child: Column( children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - SectionOptions( - onTap: collections.incoming.isNotEmpty - ? () { - unawaited( - routeToPage( - context, - CollectionListPage( - collections.incoming, - sectionType: - UISectionType.incomingCollections, - tag: "incoming", - appTitle: sharedWithYou, - ), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + SectionOptions( + onTap: collections.incoming.isNotEmpty + ? () { + unawaited( + routeToPage( + context, + CollectionListPage( + collections.incoming, + sectionType: + UISectionType.incomingCollections, + tag: "incoming", + appTitle: sharedWithYou, + ), + ), + ); + } + : null, + Hero(tag: "incoming", child: sharedWithYou), + trailingWidget: collections.incoming.isNotEmpty + ? IconButtonWidget( + icon: Icons.chevron_right, + iconButtonType: IconButtonType.secondary, + iconColor: colorTheme.blurStrokePressed, + ) + : null, + ), + const SizedBox(height: 2), + collections.incoming.isNotEmpty + ? SizedBox( + height: sideOfThumbnail + 46, + child: ListView.builder( + padding: const EdgeInsets.symmetric( + horizontal: horizontalPadding / 2, + ), + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.only( + right: horizontalPadding / 2, + ), + child: AlbumRowItemWidget( + collections.incoming[index], + sideOfThumbnail, + tag: "incoming", + showFileCount: true, ), ); - } - : null, - Hero(tag: "incoming", child: sharedWithYou), - trailingWidget: collections.incoming.isNotEmpty - ? IconButtonWidget( - icon: Icons.chevron_right, - iconButtonType: IconButtonType.secondary, - iconColor: colorTheme.blurStrokePressed, - ) - : null, - ), - const SizedBox(height: 2), - collections.incoming.isNotEmpty - ? SizedBox( - height: maxThumbnailWidth + 24, - child: ListView.builder( - padding: const EdgeInsets.symmetric( - horizontal: 8, - ), - scrollDirection: Axis.horizontal, - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.only(right: 8.0), - child: AlbumRowItemWidget( - collections.incoming[index], - maxThumbnailWidth, - tag: "incoming", - showFileCount: false, - ), - ); - }, - itemCount: collections.incoming.length, - ), - ) - : const IncomingAlbumEmptyState(), - ], - ), + }, + itemCount: collections.incoming.length, + ), + ) + : const IncomingAlbumEmptyState(), + ], ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - SectionOptions( - onTap: collections.outgoing.isNotEmpty - ? () { - unawaited( - routeToPage( - context, - CollectionListPage( - collections.outgoing, - sectionType: - UISectionType.outgoingCollections, - tag: "outgoing", - appTitle: sharedByYou, - ), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + SectionOptions( + onTap: collections.outgoing.isNotEmpty + ? () { + unawaited( + routeToPage( + context, + CollectionListPage( + collections.outgoing, + sectionType: + UISectionType.outgoingCollections, + tag: "outgoing", + appTitle: sharedByYou, + ), + ), + ); + } + : null, + Hero(tag: "outgoing", child: sharedByYou), + trailingWidget: collections.outgoing.isNotEmpty + ? IconButtonWidget( + icon: Icons.chevron_right, + iconButtonType: IconButtonType.secondary, + iconColor: colorTheme.blurStrokePressed, + ) + : null, + ), + const SizedBox(height: 2), + collections.outgoing.isNotEmpty + ? SizedBox( + height: sideOfThumbnail + 46, + child: ListView.builder( + padding: const EdgeInsets.symmetric( + horizontal: 8, + ), + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.only( + right: horizontalPadding / 2, + ), + child: AlbumRowItemWidget( + collections.outgoing[index], + sideOfThumbnail, + tag: "outgoing", + showFileCount: true, ), ); - } - : null, - Hero(tag: "outgoing", child: sharedByYou), - trailingWidget: collections.outgoing.isNotEmpty - ? IconButtonWidget( - icon: Icons.chevron_right, - iconButtonType: IconButtonType.secondary, - iconColor: colorTheme.blurStrokePressed, - ) - : null, - ), - const SizedBox(height: 2), - collections.outgoing.isNotEmpty - ? SizedBox( - height: maxThumbnailWidth + 24, - child: ListView.builder( - padding: const EdgeInsets.symmetric( - horizontal: 8, - ), - scrollDirection: Axis.horizontal, - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.only(right: 8.0), - child: AlbumRowItemWidget( - collections.outgoing[index], - maxThumbnailWidth, - tag: "outgoing", - showFileCount: false, - ), - ); - }, - itemCount: collections.outgoing.length, - ), - ) - : const OutgoingAlbumEmptyState(), - ], - ), + }, + itemCount: collections.outgoing.length, + ), + ) + : const OutgoingAlbumEmptyState(), + ], ), numberOfQuickLinks > 0 - ? Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, - ), - child: Column( - children: [ - SectionOptions( - onTap: numberOfQuickLinks > maxQuickLinks - ? () { - unawaited( - routeToPage( - context, - AllQuickLinksPage( - titleHeroTag: quickLinkTitleHeroTag, - quickLinks: collections.quickLinks, - ), - ), - ); - } - : null, - Hero( - tag: quickLinkTitleHeroTag, - child: SectionTitle( - title: S.of(context).quickLinks, - ), - ), - trailingWidget: numberOfQuickLinks > maxQuickLinks - ? IconButtonWidget( - icon: Icons.chevron_right, - iconButtonType: IconButtonType.secondary, - iconColor: colorTheme.blurStrokePressed, - ) - : null, - ), - const SizedBox(height: 2), - ListView.separated( - shrinkWrap: true, - padding: const EdgeInsets.only( - bottom: 12, - left: 12, - right: 12, - ), - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) { - return GestureDetector( - onTap: () async { - final thumbnail = await CollectionsService - .instance - .getCover(collections.quickLinks[index]); - final page = CollectionPage( - CollectionWithThumbnail( - collections.quickLinks[index], - thumbnail, + ? Column( + children: [ + SectionOptions( + onTap: numberOfQuickLinks > maxQuickLinks + ? () { + unawaited( + routeToPage( + context, + AllQuickLinksPage( + titleHeroTag: quickLinkTitleHeroTag, + quickLinks: collections.quickLinks, ), - tagPrefix: heroTagPrefix, - ); - // ignore: unawaited_futures - routeToPage(context, page); - }, - child: QuickLinkAlbumItem( - c: collections.quickLinks[index], - ), - ); - }, - separatorBuilder: (context, index) { - return const SizedBox(height: 4); - }, - itemCount: min(numberOfQuickLinks, maxQuickLinks), + ), + ); + } + : null, + Hero( + tag: quickLinkTitleHeroTag, + child: SectionTitle( + title: S.of(context).quickLinks, ), - ], + ), + trailingWidget: numberOfQuickLinks > maxQuickLinks + ? IconButtonWidget( + icon: Icons.chevron_right, + iconButtonType: IconButtonType.secondary, + iconColor: colorTheme.blurStrokePressed, + ) + : null, ), - ) + const SizedBox(height: 2), + ListView.separated( + shrinkWrap: true, + padding: const EdgeInsets.only( + bottom: 12, + left: 12, + right: 12, + ), + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + return GestureDetector( + onTap: () async { + final thumbnail = await CollectionsService + .instance + .getCover(collections.quickLinks[index]); + final page = CollectionPage( + CollectionWithThumbnail( + collections.quickLinks[index], + thumbnail, + ), + tagPrefix: heroTagPrefix, + ); + // ignore: unawaited_futures + routeToPage(context, page); + }, + child: QuickLinkAlbumItem( + c: collections.quickLinks[index], + ), + ); + }, + separatorBuilder: (context, index) { + return const SizedBox(height: 4); + }, + itemCount: min(numberOfQuickLinks, maxQuickLinks), + ), + ], + ) : const SizedBox.shrink(), const SizedBox(height: 2), ValueListenableBuilder( @@ -368,7 +370,6 @@ class _SharedCollectionsTabState extends State : const EnteLoadingWidget(); }, ), - const SizedBox(height: 4), const CollectPhotosCardWidget(), const SizedBox(height: 32), ], diff --git a/mobile/lib/ui/tools/debug/app_storage_viewer.dart b/mobile/lib/ui/tools/debug/app_storage_viewer.dart index bb7abf3e51..87ba10f1b0 100644 --- a/mobile/lib/ui/tools/debug/app_storage_viewer.dart +++ b/mobile/lib/ui/tools/debug/app_storage_viewer.dart @@ -50,6 +50,8 @@ class _AppStorageViewerState extends State { "${appTemporaryDirectory.path}/image_manager_disk_cache/"; final String tempDownload = Configuration.instance.getTempDirectory(); + final String personFaceThumbnails = + Configuration.instance.getPersonFaceThumbnailCacheDirectory(); final String cacheDirectory = Configuration.instance.getThumbnailCacheDirectory(); final imageCachePath = @@ -94,6 +96,11 @@ class _AppStorageViewerState extends State { PathStorageItem.name(appDocumentsDirectory.path, "Documents"), PathStorageItem.name(appSupportDirectory.path, "Support"), PathStorageItem.name(appTemporaryDirectory.path, "App Temp"), + PathStorageItem.name( + personFaceThumbnails, + "Person Face Thumbnails", + allowCacheClear: true, + ), ]); if (!Platform.isAndroid) { paths.add(PathStorageItem.name(iosTempDirectoryPath, "/tmp")); diff --git a/mobile/lib/ui/tools/lock_screen.dart b/mobile/lib/ui/tools/lock_screen.dart index e81cc2b8bc..dfaf389322 100644 --- a/mobile/lib/ui/tools/lock_screen.dart +++ b/mobile/lib/ui/tools/lock_screen.dart @@ -337,7 +337,7 @@ class _LockScreenState extends State context.l10n.authToViewYourMemories, isOpeningApp: true, ); - _logger.finest("LockScreen Result $result"); + _logger.info("LockScreen Result $result"); _isShowingLockScreen = false; if (result) { lastAuthenticatingTime = DateTime.now().millisecondsSinceEpoch; diff --git a/mobile/lib/ui/viewer/actions/delete_empty_albums.dart b/mobile/lib/ui/viewer/actions/delete_empty_albums.dart index 18b817f067..c25f7845e0 100644 --- a/mobile/lib/ui/viewer/actions/delete_empty_albums.dart +++ b/mobile/lib/ui/viewer/actions/delete_empty_albums.dart @@ -7,6 +7,7 @@ import 'package:photos/models/collection/collection.dart'; import 'package:photos/models/file/file.dart'; import 'package:photos/services/collections_service.dart'; import "package:photos/services/sync/remote_sync_service.dart"; +import "package:photos/theme/ente_theme.dart"; import 'package:photos/ui/components/action_sheet_widget.dart'; import 'package:photos/ui/components/buttons/button_widget.dart'; import 'package:photos/ui/components/models/button_type.dart'; @@ -59,16 +60,33 @@ class _DeleteEmptyAlbumsState extends State { } Widget _buildDeleteButton() { + final colorScheme = getEnteColorScheme(context); + final textTheme = getEnteTextTheme(context); return Padding( padding: const EdgeInsets.fromLTRB(8.5, 4, 8, 12), child: Align( alignment: Alignment.centerLeft, - child: ButtonWidget( - buttonSize: ButtonSize.small, - buttonType: ButtonType.secondary, - labelText: S.of(context).deleteEmptyAlbums, - icon: Icons.delete_sweep_outlined, - shouldSurfaceExecutionStates: false, + child: GestureDetector( + child: Container( + decoration: BoxDecoration( + color: colorScheme.fillFaint, + borderRadius: const BorderRadius.all(Radius.circular(4)), + ), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 12), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.delete_sweep_outlined, size: 18), + const SizedBox(width: 8), + Text( + S.of(context).deleteEmptyAlbums, + style: textTheme.smallBold, + ), + ], + ), + ), + ), onTap: () async { await showActionSheet( context: context, diff --git a/mobile/lib/ui/viewer/actions/people_selection_action_widget.dart b/mobile/lib/ui/viewer/actions/people_selection_action_widget.dart new file mode 100644 index 0000000000..38afe7a9b9 --- /dev/null +++ b/mobile/lib/ui/viewer/actions/people_selection_action_widget.dart @@ -0,0 +1,276 @@ +import "package:flutter/material.dart"; +import "package:logging/logging.dart"; +import "package:photos/core/event_bus.dart"; +import "package:photos/events/people_changed_event.dart"; +import "package:photos/generated/l10n.dart"; +import "package:photos/models/ml/face/person.dart"; +import "package:photos/models/selected_people.dart"; +import "package:photos/services/machine_learning/face_ml/feedback/cluster_feedback.dart"; +import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; +import "package:photos/ui/components/bottom_action_bar/selection_action_button_widget.dart"; +import "package:photos/ui/viewer/people/person_cluster_suggestion.dart"; +import "package:photos/ui/viewer/people/save_or_edit_person.dart"; +import "package:photos/utils/dialog_util.dart"; +import "package:photos/utils/navigation_util.dart"; + +class PeopleSelectionActionWidget extends StatefulWidget { + final SelectedPeople selectedPeople; + + const PeopleSelectionActionWidget( + this.selectedPeople, { + super.key, + }); + + @override + State createState() => + _PeopleSelectionActionWidgetState(); +} + +class _PeopleSelectionActionWidgetState + extends State { + late Future> personEntitiesMapFuture; + final _logger = Logger("PeopleSelectionActionWidget"); + + @override + void initState() { + super.initState(); + widget.selectedPeople.addListener(_selectionChangedListener); + personEntitiesMapFuture = PersonService.instance.getPersonsMap(); + } + + @override + void dispose() { + widget.selectedPeople.removeListener(_selectionChangedListener); + super.dispose(); + } + + List _getSelectedPersonIds() { + return widget.selectedPeople.personIds + .where((id) => !id.startsWith('cluster_')) + .toList(); + } + + List _getSelectedClusterIds() { + return widget.selectedPeople.personIds + .where((id) => id.startsWith('cluster_')) + .toList(); + } + + void _selectionChangedListener() { + if (mounted) { + setState(() {}); + } + } + + @override + Widget build(BuildContext context) { + if (widget.selectedPeople.personIds.isEmpty) { + return const SizedBox.shrink(); + } + + final List items = []; + final selectedPersonIds = _getSelectedPersonIds(); + final selectedClusterIds = _getSelectedClusterIds(); + final onlyOnePerson = + selectedPersonIds.length == 1 && selectedClusterIds.isEmpty; + final onePersonAndClusters = + selectedPersonIds.length == 1 && selectedClusterIds.isNotEmpty; + final anythingSelected = + selectedPersonIds.isNotEmpty || selectedClusterIds.isNotEmpty; + + items.add( + SelectionActionButton( + labelText: S.of(context).edit, + icon: Icons.edit_outlined, + onTap: _onEditPerson, + shouldShow: onlyOnePerson, + ), + ); + items.add( + SelectionActionButton( + labelText: S.of(context).review, + icon: Icons.search_outlined, + onTap: _onReviewSuggestion, + shouldShow: onlyOnePerson, + ), + ); + items.add( + SelectionActionButton( + labelText: S.of(context).ignore, + icon: Icons.hide_image_outlined, + onTap: _onIgnore, + shouldShow: anythingSelected, + ), + ); + items.add( + SelectionActionButton( + labelText: S.of(context).merge, + icon: Icons.merge_outlined, + onTap: _onMerge, + shouldShow: onePersonAndClusters, + ), + ); + items.add( + SelectionActionButton( + labelText: S.of(context).reset, + icon: Icons.remove_outlined, + onTap: _onResetPerson, + shouldShow: onlyOnePerson, + ), + ); + + return MediaQuery( + data: MediaQuery.of(context).removePadding(removeBottom: true), + child: SafeArea( + child: Scrollbar( + radius: const Radius.circular(1), + thickness: 2, + thumbVisibility: true, + child: SingleChildScrollView( + physics: const BouncingScrollPhysics( + decelerationRate: ScrollDecelerationRate.fast, + ), + scrollDirection: Axis.horizontal, + child: Container( + padding: const EdgeInsets.only(bottom: 24), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(width: 4), + ...items, + const SizedBox(width: 4), + ], + ), + ), + ), + ), + ), + ); + } + + Future _onEditPerson() async { + final selectedPersonIds = _getSelectedPersonIds(); + if (selectedPersonIds.length != 1) return; + final personID = selectedPersonIds.first; + final personMap = await personEntitiesMapFuture; + final person = personMap[personID]; + if (person == null) return; + + await routeToPage( + context, + SaveOrEditPerson( + person.data.assigned.first.id, + person: person, + isEditing: true, + ), + ); + widget.selectedPeople.clearAll(); + } + + Future _onReviewSuggestion() async { + final selectedPersonIds = _getSelectedPersonIds(); + if (selectedPersonIds.length != 1) return; + final personID = selectedPersonIds.first; + final personMap = await personEntitiesMapFuture; + final person = personMap[personID]; + if (person == null) return; + + await routeToPage( + context, + PersonReviewClusterSuggestion(person), + ); + widget.selectedPeople.clearAll(); + } + + Future _onResetPerson() async { + final selectedPersonIds = _getSelectedPersonIds(); + if (selectedPersonIds.length != 1) return; + final personID = selectedPersonIds.first; + final personMap = await personEntitiesMapFuture; + final person = personMap[personID]; + if (person == null) return; + + await showChoiceDialog( + context, + title: S.of(context).areYouSureYouWantToResetThisPerson, + body: S.of(context).allPersonGroupingWillReset, + firstButtonLabel: S.of(context).yesResetPerson, + firstButtonOnTap: () async { + try { + await PersonService.instance.deletePerson(person.remoteID); + widget.selectedPeople.clearAll(); + } on Exception catch (e, s) { + _logger.severe('Failed to delete person', e, s); + } + }, + ); + } + + Future _onIgnore() async { + final selectedPersonIds = _getSelectedPersonIds(); + final selectedClusterIds = _getSelectedClusterIds(); + if (selectedPersonIds.isEmpty && selectedClusterIds.isEmpty) return; + final multiple = (selectedPersonIds.length + selectedClusterIds.length) > 1; + + await showChoiceDialog( + context, + title: multiple + ? S.of(context).areYouSureYouWantToIgnoreThesePersons + : S.of(context).areYouSureYouWantToIgnoreThisPerson, + body: multiple + ? S.of(context).thePersonGroupsWillNotBeDisplayed + : S.of(context).thePersonWillNotBeDisplayed, + firstButtonLabel: S.of(context).yesIgnore, + firstButtonOnTap: () async { + try { + for (final clusterID in selectedClusterIds) { + await ClusterFeedbackService.instance.ignoreCluster(clusterID); + } + final personMap = await personEntitiesMapFuture; + for (final personID in selectedPersonIds) { + final person = personMap[personID]; + if (person == null) continue; + final ignoredPerson = person.copyWith( + data: person.data.copyWith(name: "", isHidden: true), + ); + await PersonService.instance.updatePerson(ignoredPerson); + } + Bus.instance.fire(PeopleChangedEvent()); + widget.selectedPeople.clearAll(); + } catch (e, s) { + _logger.severe('Ignoring a cluster failed', e, s); + } + }, + ); + } + + Future _onMerge() async { + final selectedPersonIds = _getSelectedPersonIds(); + final selectedClusterIds = _getSelectedClusterIds(); + if (selectedPersonIds.length != 1 || selectedClusterIds.isEmpty) return; + + await showChoiceDialog( + context, + title: S.of(context).areYouSureYouWantToMergeThem, + body: S.of(context).allUnnamedGroupsWillBeMergedIntoTheSelectedPerson, + firstButtonLabel: S.of(context).confirm, + firstButtonOnTap: () async { + try { + final personMap = await personEntitiesMapFuture; + final personID = selectedPersonIds.first; + final person = personMap[personID]; + if (person == null) return; + for (final clusterID in selectedClusterIds) { + await ClusterFeedbackService.instance.addClusterToExistingPerson( + clusterID: clusterID, + person: person, + ); + } + widget.selectedPeople.clearAll(); + } catch (e, s) { + _logger.severe('Merging clusters failed', e, s); + } + }, + ); + } +} diff --git a/mobile/lib/ui/viewer/file/detail_page.dart b/mobile/lib/ui/viewer/file/detail_page.dart index 9ee0fa222f..2df8e6520b 100644 --- a/mobile/lib/ui/viewer/file/detail_page.dart +++ b/mobile/lib/ui/viewer/file/detail_page.dart @@ -269,7 +269,7 @@ class _DetailPageState extends State { shouldDisableScroll: (value) { if (_shouldDisableScroll != value) { setState(() { - _logger.fine('setState $_shouldDisableScroll to $value'); + _logger.info('setState $_shouldDisableScroll to $value'); _shouldDisableScroll = value; }); } diff --git a/mobile/lib/ui/viewer/file/file_app_bar.dart b/mobile/lib/ui/viewer/file/file_app_bar.dart index bf7e7cb996..79ac731279 100644 --- a/mobile/lib/ui/viewer/file/file_app_bar.dart +++ b/mobile/lib/ui/viewer/file/file_app_bar.dart @@ -20,7 +20,7 @@ import "package:photos/service_locator.dart"; import 'package:photos/services/collections_service.dart'; import 'package:photos/services/hidden_service.dart'; import "package:photos/services/local_authentication_service.dart"; -import "package:photos/services/preview_video_store.dart"; +import "package:photos/services/video_preview_service.dart"; import "package:photos/theme/ente_theme.dart"; import 'package:photos/ui/collections/collection_action_sheet.dart'; import 'package:photos/ui/notification/toast.dart'; @@ -84,7 +84,7 @@ class FileAppBarState extends State { @override Widget build(BuildContext context) { - _logger.fine("building app bar ${widget.file.generatedID?.toString()}"); + _logger.info("building app bar ${widget.file.generatedID?.toString()}"); //When the widget is initialized, the actions are not available. //Cannot call _getActions() in initState. @@ -379,7 +379,7 @@ class FileAppBarState extends State { await _onTapGuestView(); } else if (value == 99) { try { - await PreviewVideoStore.instance.chunkAndUploadVideo( + await VideoPreviewService.instance.chunkAndUploadVideo( context, widget.file, ); diff --git a/mobile/lib/ui/viewer/file/file_details_widget.dart b/mobile/lib/ui/viewer/file/file_details_widget.dart index 12f722b357..1fa5a5ba70 100644 --- a/mobile/lib/ui/viewer/file/file_details_widget.dart +++ b/mobile/lib/ui/viewer/file/file_details_widget.dart @@ -2,7 +2,7 @@ import "dart:async"; import "dart:developer"; import "dart:io"; -import "package:exif/exif.dart"; +import "package:exif_reader/exif_reader.dart"; import "package:flutter/foundation.dart"; import "package:flutter/material.dart"; import "package:logging/logging.dart"; @@ -18,7 +18,6 @@ import "package:photos/models/location/location.dart"; import "package:photos/models/metadata/file_magic.dart"; import "package:photos/service_locator.dart"; import "package:photos/services/file_magic_service.dart"; -import "package:photos/services/filedata/filedata_service.dart"; import 'package:photos/theme/ente_theme.dart'; import 'package:photos/ui/components/buttons/icon_button_widget.dart'; import "package:photos/ui/components/divider_widget.dart"; @@ -29,7 +28,7 @@ import "package:photos/ui/viewer/file_details/albums_item_widget.dart"; import 'package:photos/ui/viewer/file_details/backed_up_time_item_widget.dart'; import "package:photos/ui/viewer/file_details/creation_time_item_widget.dart"; import 'package:photos/ui/viewer/file_details/exif_item_widgets.dart'; -import "package:photos/ui/viewer/file_details/faces_item_widget.dart"; +import "package:photos/ui/viewer/file_details/file_info_faces_item_widget.dart"; import "package:photos/ui/viewer/file_details/file_properties_item_widget.dart"; import "package:photos/ui/viewer/file_details/location_tags_widget.dart"; import "package:photos/ui/viewer/file_details/preview_properties_item_widget.dart"; @@ -179,9 +178,8 @@ class _FileDetailsWidgetState extends State { ), const FileDetailsDivider(), if (widget.file.uploadedFileID != null && - (FileDataService.instance.previewIds - ?.containsKey(widget.file.uploadedFileID) ?? - false)) ...[ + (fileDataService.previewIds + .containsKey(widget.file.uploadedFileID))) ...[ ValueListenableBuilder( valueListenable: _exifNotifier, builder: (context, _, __) => PreviewPropertiesItemWidget( diff --git a/mobile/lib/ui/viewer/file/file_widget.dart b/mobile/lib/ui/viewer/file/file_widget.dart index a38f576c37..8d5e029720 100644 --- a/mobile/lib/ui/viewer/file/file_widget.dart +++ b/mobile/lib/ui/viewer/file/file_widget.dart @@ -12,6 +12,8 @@ class FileWidget extends StatelessWidget { final Function(bool)? playbackCallback; final BoxDecoration? backgroundDecoration; final bool? autoPlay; + final bool? isFromMemories; + final Function({required int memoryDuration})? onFinalFileLoad; const FileWidget( this.file, { @@ -20,6 +22,8 @@ class FileWidget extends StatelessWidget { this.playbackCallback, required this.tagPrefix, this.backgroundDecoration, + this.isFromMemories = false, + this.onFinalFileLoad, super.key, }); @@ -37,7 +41,9 @@ class FileWidget extends StatelessWidget { shouldDisableScroll: shouldDisableScroll, tagPrefix: tagPrefix, backgroundDecoration: backgroundDecoration, + isFromMemories: isFromMemories ?? false, key: key ?? ValueKey(fileKey), + onFinalFileLoad: onFinalFileLoad, ); } else if (file.fileType == FileType.video) { // use old video widget on iOS simulator as the new one crashes while @@ -54,6 +60,8 @@ class FileWidget extends StatelessWidget { file, tagPrefix: tagPrefix, playbackCallback: playbackCallback, + onFinalFileLoad: onFinalFileLoad, + isFromMemories: isFromMemories ?? false, key: key ?? ValueKey(fileKey), ); } else { diff --git a/mobile/lib/ui/viewer/file/no_thumbnail_widget.dart b/mobile/lib/ui/viewer/file/no_thumbnail_widget.dart index fd8262165e..3c37b1a0ed 100644 --- a/mobile/lib/ui/viewer/file/no_thumbnail_widget.dart +++ b/mobile/lib/ui/viewer/file/no_thumbnail_widget.dart @@ -3,14 +3,19 @@ import 'package:photos/theme/ente_theme.dart'; class NoThumbnailWidget extends StatelessWidget { final bool addBorder; - const NoThumbnailWidget({this.addBorder = true, super.key}); + final double borderRadius; + const NoThumbnailWidget({ + this.addBorder = true, + this.borderRadius = 1, + super.key, + }); @override Widget build(BuildContext context) { final enteColorScheme = getEnteColorScheme(context); return Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(1), + borderRadius: BorderRadius.circular(borderRadius), border: addBorder ? Border.all( color: enteColorScheme.strokeFaint, diff --git a/mobile/lib/ui/viewer/file/thumbnail_widget.dart b/mobile/lib/ui/viewer/file/thumbnail_widget.dart index f4d3e1cc3c..432dcae3c8 100644 --- a/mobile/lib/ui/viewer/file/thumbnail_widget.dart +++ b/mobile/lib/ui/viewer/file/thumbnail_widget.dart @@ -271,7 +271,7 @@ class _ThumbnailWidgetState extends State { return _loadWithRetry().then((thumbData) async { if (thumbData == null) { if (widget.file.isUploaded) { - _logger.fine("Removing localID reference for " + widget.file.tag); + _logger.info("Removing localID reference for " + widget.file.tag); widget.file.localID = null; if (widget.file.isTrash) { unawaited(TrashDB.instance.update(widget.file as TrashFile)); diff --git a/mobile/lib/ui/viewer/file/video_stream_change.dart b/mobile/lib/ui/viewer/file/video_stream_change.dart index 167506e937..af9a14f1d3 100644 --- a/mobile/lib/ui/viewer/file/video_stream_change.dart +++ b/mobile/lib/ui/viewer/file/video_stream_change.dart @@ -1,13 +1,7 @@ -import "dart:async"; - import "package:flutter/material.dart"; -import "package:photos/core/event_bus.dart"; -import "package:photos/events/preview_updated_event.dart"; import "package:photos/generated/l10n.dart"; import "package:photos/models/file/file.dart"; -import "package:photos/models/preview/preview_item.dart"; -import "package:photos/services/filedata/filedata_service.dart"; -import "package:photos/services/preview_video_store.dart"; +import "package:photos/service_locator.dart"; import "package:photos/theme/colors.dart"; class VideoStreamChangeWidget extends StatefulWidget { @@ -30,36 +24,20 @@ class VideoStreamChangeWidget extends StatefulWidget { } class _VideoStreamChangeWidgetState extends State { - StreamSubscription? previewSubscription; - late PreviewItem? preview = - PreviewVideoStore.instance.previews[widget.file.uploadedFileID]; - @override void initState() { super.initState(); - previewSubscription = - Bus.instance.on().listen((event) { - final newPreview = event.items[widget.file.uploadedFileID]; - if (newPreview != preview) { - setState(() { - preview = event.items[widget.file.uploadedFileID]; - }); - } - }); } @override void dispose() { - previewSubscription?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { final bool isPreviewAvailable = widget.file.uploadedFileID != null && - (FileDataService.instance.previewIds - ?.containsKey(widget.file.uploadedFileID) ?? - false); + (fileDataService.previewIds.containsKey(widget.file.uploadedFileID)); if (!isPreviewAvailable) { return const SizedBox(); } diff --git a/mobile/lib/ui/viewer/file/video_widget.dart b/mobile/lib/ui/viewer/file/video_widget.dart index 5d9b1b847b..2f7ef84d00 100644 --- a/mobile/lib/ui/viewer/file/video_widget.dart +++ b/mobile/lib/ui/viewer/file/video_widget.dart @@ -11,12 +11,11 @@ import "package:photos/models/file/extensions/file_props.dart"; import "package:photos/models/file/file.dart"; import "package:photos/models/preview/playlist_data.dart"; import "package:photos/service_locator.dart"; -import "package:photos/services/filedata/filedata_service.dart"; -import "package:photos/services/preview_video_store.dart"; +import "package:photos/services/video_preview_service.dart"; import "package:photos/theme/colors.dart"; import "package:photos/ui/common/loading_widget.dart"; import "package:photos/ui/notification/toast.dart"; -import "package:photos/ui/viewer/file/video_widget_media_kit_new.dart"; +import "package:photos/ui/viewer/file/video_widget_media_kit.dart"; import "package:photos/ui/viewer/file/video_widget_native.dart"; import "package:photos/utils/standalone/data.dart"; @@ -24,10 +23,15 @@ class VideoWidget extends StatefulWidget { final EnteFile file; final String? tagPrefix; final Function(bool)? playbackCallback; + final Function({required int memoryDuration})? onFinalFileLoad; + final bool isFromMemories; + const VideoWidget( this.file, { this.tagPrefix, this.playbackCallback, + this.onFinalFileLoad, + this.isFromMemories = false, super.key, }); @@ -58,9 +62,8 @@ class _VideoWidgetState extends State { }); }); if (widget.file.isUploaded) { - isPreviewLoadable = FileDataService.instance.previewIds - ?.containsKey(widget.file.uploadedFileID) ?? - false; + isPreviewLoadable = + fileDataService.previewIds.containsKey(widget.file.uploadedFileID); if (!widget.file.isOwner) { // For shared video, we need to on-demand check if the file is streamable // and if not, we need to set isPreviewLoadable to false @@ -79,7 +82,7 @@ class _VideoWidgetState extends State { Future _checkForPreview() async { if (!widget.file.isOwner) { final bool isStreamable = - await PreviewVideoStore.instance.isSharedFileStreamble(widget.file); + await VideoPreviewService.instance.isSharedFileStreamble(widget.file); if (!isStreamable && mounted) { isPreviewLoadable = false; setState(() {}); @@ -89,7 +92,7 @@ class _VideoWidgetState extends State { return; } widget.playbackCallback?.call(false); - final data = await PreviewVideoStore.instance + final data = await VideoPreviewService.instance .getPlaylist(widget.file) .onError((error, stackTrace) { if (!mounted) return; @@ -151,6 +154,7 @@ class _VideoWidgetState extends State { playbackCallback: widget.playbackCallback, playlistData: playlistData, selectedPreview: playPreview, + isFromMemories: widget.isFromMemories, onStreamChange: () { setState(() { selectPreviewForPlay = !selectPreviewForPlay; @@ -164,15 +168,17 @@ class _VideoWidgetState extends State { ); }); }, + onFinalFileLoad: widget.onFinalFileLoad, ); } - return VideoWidgetMediaKitNew( + return VideoWidgetMediaKit( widget.file, key: mediaKitKey, tagPrefix: widget.tagPrefix, playbackCallback: widget.playbackCallback, preview: playlistData?.preview, selectedPreview: playPreview, + isFromMemories: widget.isFromMemories, onStreamChange: () { setState(() { selectPreviewForPlay = !selectPreviewForPlay; @@ -186,6 +192,7 @@ class _VideoWidgetState extends State { ); }); }, + onFinalFileLoad: widget.onFinalFileLoad, ); } } diff --git a/mobile/lib/ui/viewer/file/video_widget_media_kit.dart b/mobile/lib/ui/viewer/file/video_widget_media_kit.dart index 50beceb5f8..80b9f438ca 100644 --- a/mobile/lib/ui/viewer/file/video_widget_media_kit.dart +++ b/mobile/lib/ui/viewer/file/video_widget_media_kit.dart @@ -1,24 +1,30 @@ import "dart:async"; import "dart:io"; -import "package:flutter/cupertino.dart"; import "package:flutter/material.dart"; import "package:logging/logging.dart"; import "package:media_kit/media_kit.dart"; import "package:media_kit_video/media_kit_video.dart"; import "package:photos/core/constants.dart"; import "package:photos/core/event_bus.dart"; +import "package:photos/events/file_caption_updated_event.dart"; import "package:photos/events/guest_view_event.dart"; import "package:photos/events/pause_video_event.dart"; +import "package:photos/events/stream_switched_event.dart"; import "package:photos/generated/l10n.dart"; import "package:photos/models/file/extensions/file_props.dart"; import "package:photos/models/file/file.dart"; +import "package:photos/module/download/task.dart"; +import "package:photos/service_locator.dart"; import "package:photos/services/files_service.dart"; +import "package:photos/services/wake_lock_service.dart"; import "package:photos/theme/colors.dart"; import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/actions/file/file_actions.dart"; +import "package:photos/ui/common/loading_widget.dart"; import "package:photos/ui/notification/toast.dart"; -import "package:photos/ui/viewer/file/thumbnail_widget.dart"; +import "package:photos/ui/viewer/file/video_widget_media_kit_common.dart" + as common; import "package:photos/utils/dialog_util.dart"; import "package:photos/utils/file_util.dart"; @@ -26,10 +32,21 @@ class VideoWidgetMediaKit extends StatefulWidget { final EnteFile file; final String? tagPrefix; final Function(bool)? playbackCallback; + final bool isFromMemories; + final void Function() onStreamChange; + final File? preview; + final bool selectedPreview; + final Function({required int memoryDuration})? onFinalFileLoad; + const VideoWidgetMediaKit( this.file, { this.tagPrefix, this.playbackCallback, + this.isFromMemories = false, + required this.onStreamChange, + this.preview, + required this.selectedPreview, + this.onFinalFileLoad, super.key, }); @@ -39,16 +56,19 @@ class VideoWidgetMediaKit extends StatefulWidget { class _VideoWidgetMediaKitState extends State with WidgetsBindingObserver { - final Logger _logger = Logger("VideoWidgetMediaKit"); - static const verticalMargin = 72.0; + final Logger _logger = Logger("VideoWidgetMediaKitNew"); late final player = Player(); VideoController? controller; final _progressNotifier = ValueNotifier(null); - late StreamSubscription playingStreamSubscription; bool _isAppInFG = true; late StreamSubscription pauseVideoSubscription; bool isGuestView = false; late final StreamSubscription _guestViewEventSubscription; + bool _isGuestView = false; + StreamSubscription? _streamSwitchedSubscription; + StreamSubscription? _downloadTaskSubscription; + late final StreamSubscription + _captionUpdatedSubscription; @override void initState() { @@ -57,6 +77,61 @@ class _VideoWidgetMediaKitState extends State ); super.initState(); WidgetsBinding.instance.addObserver(this); + + if (widget.selectedPreview) { + loadPreview(); + } else { + loadOriginal(); + } + + pauseVideoSubscription = Bus.instance.on().listen((event) { + player.pause(); + }); + _guestViewEventSubscription = + Bus.instance.on().listen((event) { + setState(() { + _isGuestView = event.isGuestView; + }); + }); + if (widget.file.isUploaded) { + _downloadTaskSubscription = downloadManager + .watchDownload(widget.file.uploadedFileID!) + .listen((event) { + if (mounted) { + setState(() { + _progressNotifier.value = event.progress; + }); + } + }); + } + + _streamSwitchedSubscription = + Bus.instance.on().listen((event) { + if (event.type != PlayerType.mediaKit || !mounted) return; + if (event.selectedPreview) { + loadPreview(); + } else { + loadOriginal(); + } + }); + + _captionUpdatedSubscription = + Bus.instance.on().listen((event) { + if (event.fileGeneratedID == widget.file.generatedID) { + if (mounted) { + setState(() {}); + } + } + }); + EnteWakeLockService.instance + .updateWakeLock(enable: true, wakeLockFor: WakeLockFor.videoPlayback); + } + + void loadPreview() { + _setVideoController(widget.preview!.path); + } + + void loadOriginal() { if (widget.file.isRemoteFile) { _loadNetworkVideo(); _setFileSizeIfNull(); @@ -84,21 +159,6 @@ class _VideoWidgetMediaKitState extends State } }); } - playingStreamSubscription = player.stream.playing.listen((event) { - if (widget.playbackCallback != null && mounted) { - widget.playbackCallback!(event); - } - }); - - pauseVideoSubscription = Bus.instance.on().listen((event) { - player.pause(); - }); - _guestViewEventSubscription = - Bus.instance.on().listen((event) { - setState(() { - isGuestView = event.isGuestView; - }); - }); } @override @@ -112,71 +172,92 @@ class _VideoWidgetMediaKitState extends State @override void dispose() { + _streamSwitchedSubscription?.cancel(); _guestViewEventSubscription.cancel(); pauseVideoSubscription.cancel(); removeCallBack(widget.file); _progressNotifier.dispose(); WidgetsBinding.instance.removeObserver(this); - playingStreamSubscription.cancel(); + if (_downloadTaskSubscription != null) { + _downloadTaskSubscription!.cancel(); + downloadManager.pause(widget.file.uploadedFileID!).ignore(); + } player.dispose(); + _captionUpdatedSubscription.cancel(); + if (EnteWakeLockService.instance.shouldKeepAppAwakeAcrossSessions) { + EnteWakeLockService.instance.updateWakeLock( + enable: true, + wakeLockFor: WakeLockFor.handlingMediaKitEdgeCase, + ); + } else { + EnteWakeLockService.instance.updateWakeLock( + enable: false, + wakeLockFor: WakeLockFor.videoPlayback, + ); + } super.dispose(); } @override Widget build(BuildContext context) { - return Hero( - tag: widget.tagPrefix! + widget.file.tag, - child: MaterialVideoControlsTheme( - normal: MaterialVideoControlsThemeData( - backdropColor: null, - automaticallyImplySkipNextButton: false, - automaticallyImplySkipPreviousButton: false, - seekOnDoubleTap: false, - displaySeekBar: true, - seekBarMargin: const EdgeInsets.only(bottom: verticalMargin), - bottomButtonBarMargin: const EdgeInsets.only(bottom: 112), - controlsHoverDuration: const Duration(seconds: 3), - seekBarHeight: 2, - seekBarThumbSize: 16, - seekBarBufferColor: Colors.transparent, - seekBarThumbColor: backgroundElevatedLight, - seekBarColor: fillMutedDark, - seekBarPositionColor: backgroundElevatedLight, - seekBarContainerHeight: 56, - seekBarAlignment: Alignment.center, - - ///topButtonBarMargin is needed for keeping the buffering loading - ///indicator to be center aligned - topButtonBarMargin: const EdgeInsets.only(top: verticalMargin), - bottomButtonBar: [ - const Spacer(), - PausePlayAndDuration(controller?.player), - const Spacer(), - ], - primaryButtonBar: [], - ), - fullscreen: const MaterialVideoControlsThemeData(), - child: GestureDetector( - onVerticalDragUpdate: isGuestView - ? null - : (d) => { - if (d.delta.dy > dragSensitivity) - { - Navigator.of(context).pop(), - } - else if (d.delta.dy < (dragSensitivity * -1)) - { - showDetailsSheet(context, widget.file), - }, + return GestureDetector( + onVerticalDragUpdate: _isGuestView + ? null + : (d) => { + if (d.delta.dy > dragSensitivity) + { + Navigator.of(context).pop(), + } + else if (d.delta.dy < (dragSensitivity * -1)) + { + showDetailsSheet(context, widget.file), }, - child: Center( - child: controller != null - ? Video( - controller: controller!, - ) - : _getLoadingWidget(), - ), - ), + }, + child: Center( + child: controller != null + ? common.VideoWidget( + widget.file, + controller!, + widget.playbackCallback, + isFromMemories: widget.isFromMemories, + onStreamChange: widget.onStreamChange, + isPreviewPlayer: widget.selectedPreview, + ) + : Center( + child: ValueListenableBuilder( + valueListenable: _progressNotifier, + builder: (BuildContext context, double? progress, _) { + return progress == null || progress == 1 + ? const EnteLoadingWidget( + size: 32, + color: fillBaseDark, + padding: 0, + ) + : Stack( + children: [ + CircularProgressIndicator( + backgroundColor: Colors.transparent, + value: progress, + valueColor: const AlwaysStoppedAnimation( + Color.fromRGBO(45, 194, 98, 1.0), + ), + strokeWidth: 2, + strokeCap: StrokeCap.round, + ), + Center( + child: Text( + "${(progress * 100).toStringAsFixed(0)}%", + style: + getEnteTextTheme(context).tiny.copyWith( + color: textBaseDark, + ), + ), + ), + ], + ); + }, + ), + ), ), ); } @@ -221,148 +302,26 @@ class _VideoWidgetMediaKitState extends State } } - Widget _getLoadingWidget() { - return Stack( - children: [ - _getThumbnail(), - Container( - color: Colors.black12, - constraints: const BoxConstraints.expand(), - ), - Center( - child: SizedBox.fromSize( - size: const Size.square(20), - child: ValueListenableBuilder( - valueListenable: _progressNotifier, - builder: (BuildContext context, double? progress, _) { - return progress == null || progress == 1 - ? const CupertinoActivityIndicator( - color: Colors.white, - ) - : CircularProgressIndicator( - backgroundColor: Colors.black, - value: progress, - valueColor: const AlwaysStoppedAnimation( - Color.fromRGBO(45, 194, 98, 1.0), - ), - ); - }, - ), - ), - ), - ], - ); - } - - Widget _getThumbnail() { - return Container( - color: Colors.black, - constraints: const BoxConstraints.expand(), - child: ThumbnailWidget( - widget.file, - fit: BoxFit.contain, - ), - ); - } - void _setVideoController(String url) { if (mounted) { setState(() { - player.setPlaylistMode(PlaylistMode.single); - controller = VideoController(player); + if (controller == null) { + player.setPlaylistMode( + localSettings.shouldLoopVideo() + ? PlaylistMode.single + : PlaylistMode.none, + ); + controller = VideoController(player); + } player.open(Media(url), play: _isAppInFG); }); + int duration = controller!.player.state.duration.inSeconds; + if (duration == 0) { + duration = 10; + } + widget.onFinalFileLoad?.call( + memoryDuration: duration, + ); } } } - -class PausePlayAndDuration extends StatefulWidget { - final Player? player; - const PausePlayAndDuration(this.player, {super.key}); - - @override - State createState() => _PausePlayAndDurationState(); -} - -class _PausePlayAndDurationState extends State { - Color backgroundColor = fillStrongLight; - @override - Widget build(BuildContext context) { - return GestureDetector( - onTapDown: (details) { - setState(() { - backgroundColor = fillMutedDark; - }); - }, - onTapUp: (details) { - Future.delayed(const Duration(milliseconds: 175), () { - if (mounted) { - setState(() { - backgroundColor = fillStrongLight; - }); - } - }); - }, - onTapCancel: () { - Future.delayed(const Duration(milliseconds: 175), () { - if (mounted) { - setState(() { - backgroundColor = fillStrongLight; - }); - } - }); - }, - onTap: () => widget.player!.playOrPause(), - child: AnimatedContainer( - duration: const Duration(milliseconds: 150), - curve: Curves.easeInBack, - padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8), - decoration: BoxDecoration( - color: backgroundColor, - border: Border.all( - color: strokeFaintDark, - width: 1, - ), - borderRadius: BorderRadius.circular(24), - ), - child: AnimatedSize( - duration: const Duration(seconds: 2), - curve: Curves.easeInOutExpo, - child: Row( - children: [ - StreamBuilder( - builder: (context, snapshot) { - final bool isPlaying = snapshot.data ?? false; - return AnimatedSwitcher( - duration: const Duration(milliseconds: 350), - switchInCurve: Curves.easeInOutCirc, - switchOutCurve: Curves.easeInOutCirc, - child: Icon( - key: ValueKey( - isPlaying ? "pause_button" : "play_button", - ), - isPlaying - ? Icons.pause_rounded - : Icons.play_arrow_rounded, - color: backdropBaseLight, - size: 24, - ), - ); - }, - initialData: widget.player?.state.playing, - stream: widget.player?.stream.playing, - ), - const SizedBox(width: 8), - MaterialPositionIndicator( - style: getEnteTextTheme(context).tiny.copyWith( - color: textBaseDark, - ), - ), - const SizedBox(width: 10), - ], - ), - ), - ), - ); - } -} diff --git a/mobile/lib/ui/viewer/file/video_widget_media_kit_common.dart b/mobile/lib/ui/viewer/file/video_widget_media_kit_common.dart index af7f048562..d5d5d3aa87 100644 --- a/mobile/lib/ui/viewer/file/video_widget_media_kit_common.dart +++ b/mobile/lib/ui/viewer/file/video_widget_media_kit_common.dart @@ -99,56 +99,79 @@ class _VideoWidgetState extends State { children: [ GestureDetector( behavior: HitTestBehavior.opaque, - onTap: () { - showControlsNotifier.value = !showControlsNotifier.value; - if (widget.playbackCallback != null) { - widget.playbackCallback!( - !showControlsNotifier.value, - ); + onTap: widget.isFromMemories + ? null + : () { + showControlsNotifier.value = + !showControlsNotifier.value; + if (widget.playbackCallback != null) { + widget.playbackCallback!( + !showControlsNotifier.value, + ); + } + }, + onLongPress: () { + if (widget.isFromMemories) { + widget.playbackCallback?.call(false); + if (widget.controller.player.state.playing) { + widget.controller.player.pause(); + } + } + }, + onLongPressUp: () { + if (widget.isFromMemories) { + widget.playbackCallback?.call(true); + if (!widget.controller.player.state.playing) { + widget.controller.player.play(); + } } }, child: Container( constraints: const BoxConstraints.expand(), ), ), - IgnorePointer( - ignoring: !value, - child: PlayPauseButtonMediaKit(widget.controller), - ), - Positioned( - bottom: verticalMargin, - right: 0, - left: 0, - child: IgnorePointer( - ignoring: !value, - child: SafeArea( - top: false, - left: false, - right: false, - child: Padding( - padding: EdgeInsets.only( - bottom: widget.isFromMemories ? 32 : 0, - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - VideoStreamChangeWidget( - showControls: value, - file: widget.file, - isPreviewPlayer: widget.isPreviewPlayer, - onStreamChange: widget.onStreamChange, + widget.isFromMemories + ? const SizedBox.shrink() + : IgnorePointer( + ignoring: !value, + child: PlayPauseButtonMediaKit(widget.controller), + ), + widget.isFromMemories + ? const SizedBox.shrink() + : Positioned( + bottom: verticalMargin, + right: 0, + left: 0, + child: IgnorePointer( + ignoring: !value, + child: SafeArea( + top: false, + left: false, + right: false, + child: Padding( + padding: EdgeInsets.only( + bottom: widget.isFromMemories ? 32 : 0, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + VideoStreamChangeWidget( + showControls: value, + file: widget.file, + isPreviewPlayer: widget.isPreviewPlayer, + onStreamChange: widget.onStreamChange, + ), + SeekBarAndDuration( + controller: widget.controller, + isSeekingNotifier: _isSeekingNotifier, + file: widget.file, + ), + ], + ), ), - SeekBarAndDuration( - controller: widget.controller, - isSeekingNotifier: _isSeekingNotifier, - file: widget.file, - ), - ], + ), ), ), - ), - ), - ), ], ), ); diff --git a/mobile/lib/ui/viewer/file/video_widget_media_kit_new.dart b/mobile/lib/ui/viewer/file/video_widget_media_kit_new.dart deleted file mode 100644 index 97fb663577..0000000000 --- a/mobile/lib/ui/viewer/file/video_widget_media_kit_new.dart +++ /dev/null @@ -1,265 +0,0 @@ -import "dart:async"; -import "dart:io"; - -import "package:flutter/material.dart"; -import "package:logging/logging.dart"; -import "package:media_kit/media_kit.dart"; -import "package:media_kit_video/media_kit_video.dart"; -import "package:photos/core/constants.dart"; -import "package:photos/core/event_bus.dart"; -import "package:photos/events/file_caption_updated_event.dart"; -import "package:photos/events/guest_view_event.dart"; -import "package:photos/events/pause_video_event.dart"; -import "package:photos/events/stream_switched_event.dart"; -import "package:photos/generated/l10n.dart"; -import "package:photos/models/file/extensions/file_props.dart"; -import "package:photos/models/file/file.dart"; -import "package:photos/service_locator.dart"; -import "package:photos/services/files_service.dart"; -import "package:photos/services/wake_lock_service.dart"; -import "package:photos/theme/colors.dart"; -import "package:photos/ui/actions/file/file_actions.dart"; -import "package:photos/ui/common/loading_widget.dart"; -import "package:photos/ui/notification/toast.dart"; -import "package:photos/ui/viewer/file/video_widget_media_kit_common.dart" - as common; -import "package:photos/utils/dialog_util.dart"; -import "package:photos/utils/file_util.dart"; - -class VideoWidgetMediaKitNew extends StatefulWidget { - final EnteFile file; - final String? tagPrefix; - final Function(bool)? playbackCallback; - final bool isFromMemories; - final void Function() onStreamChange; - final File? preview; - final bool selectedPreview; - - const VideoWidgetMediaKitNew( - this.file, { - this.tagPrefix, - this.playbackCallback, - this.isFromMemories = false, - required this.onStreamChange, - this.preview, - required this.selectedPreview, - super.key, - }); - - @override - State createState() => _VideoWidgetMediaKitNewState(); -} - -class _VideoWidgetMediaKitNewState extends State - with WidgetsBindingObserver { - final Logger _logger = Logger("VideoWidgetMediaKitNew"); - late final player = Player(); - VideoController? controller; - final _progressNotifier = ValueNotifier(null); - bool _isAppInFG = true; - late StreamSubscription pauseVideoSubscription; - bool isGuestView = false; - late final StreamSubscription _guestViewEventSubscription; - bool _isGuestView = false; - StreamSubscription? _streamSwitchedSubscription; - late final StreamSubscription - _captionUpdatedSubscription; - - @override - void initState() { - _logger.info( - 'initState for ${widget.file.generatedID} with tag ${widget.file.tag} and name ${widget.file.displayName}', - ); - super.initState(); - WidgetsBinding.instance.addObserver(this); - - if (widget.selectedPreview) { - loadPreview(); - } else { - loadOriginal(); - } - - pauseVideoSubscription = Bus.instance.on().listen((event) { - player.pause(); - }); - _guestViewEventSubscription = - Bus.instance.on().listen((event) { - setState(() { - _isGuestView = event.isGuestView; - }); - }); - - _streamSwitchedSubscription = - Bus.instance.on().listen((event) { - if (event.type != PlayerType.mediaKit || !mounted) return; - if (event.selectedPreview) { - loadPreview(); - } else { - loadOriginal(); - } - }); - - _captionUpdatedSubscription = - Bus.instance.on().listen((event) { - if (event.fileGeneratedID == widget.file.generatedID) { - if (mounted) { - setState(() {}); - } - } - }); - } - - void loadPreview() { - _setVideoController(widget.preview!.path); - } - - void loadOriginal() { - if (widget.file.isRemoteFile) { - _loadNetworkVideo(); - _setFileSizeIfNull(); - } else if (widget.file.isSharedMediaToAppSandbox) { - final localFile = File(getSharedMediaFilePath(widget.file)); - if (localFile.existsSync()) { - _setVideoController(localFile.path); - } else if (widget.file.uploadedFileID != null) { - _loadNetworkVideo(); - } - } else { - widget.file.getAsset.then((asset) async { - if (asset == null || !(await asset.exists)) { - if (widget.file.uploadedFileID != null) { - _loadNetworkVideo(); - } - } else { - // ignore: unawaited_futures - asset.getMediaUrl().then((url) { - _setVideoController( - url ?? - 'https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4', - ); - }); - } - }); - } - } - - @override - void didChangeAppLifecycleState(AppLifecycleState state) { - if (state == AppLifecycleState.resumed) { - _isAppInFG = true; - } else { - _isAppInFG = false; - } - } - - @override - void dispose() { - _streamSwitchedSubscription?.cancel(); - _guestViewEventSubscription.cancel(); - pauseVideoSubscription.cancel(); - removeCallBack(widget.file); - _progressNotifier.dispose(); - WidgetsBinding.instance.removeObserver(this); - player.dispose(); - _captionUpdatedSubscription.cancel(); - if (EnteWakeLockService.instance.shouldKeepAppAwakeAcrossSessions) { - EnteWakeLockService.instance.updateWakeLock( - enable: true, - wakeLockFor: WakeLockFor.handlingMediaKitEdgeCase, - ); - } - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return GestureDetector( - onVerticalDragUpdate: _isGuestView - ? null - : (d) => { - if (d.delta.dy > dragSensitivity) - { - Navigator.of(context).pop(), - } - else if (d.delta.dy < (dragSensitivity * -1)) - { - showDetailsSheet(context, widget.file), - }, - }, - child: Center( - child: controller != null - ? common.VideoWidget( - widget.file, - controller!, - widget.playbackCallback, - isFromMemories: widget.isFromMemories, - onStreamChange: widget.onStreamChange, - isPreviewPlayer: widget.selectedPreview, - ) - : const Center( - child: EnteLoadingWidget( - size: 32, - color: fillBaseDark, - padding: 0, - ), - ), - ), - ); - } - - void _loadNetworkVideo() { - getFileFromServer( - widget.file, - progressCallback: (count, total) { - if (!mounted) { - return; - } - _progressNotifier.value = count / (widget.file.fileSize ?? total); - if (_progressNotifier.value == 1) { - if (mounted) { - showShortToast(context, S.of(context).decryptingVideo); - } - } - }, - ).then((file) { - if (file != null) { - _setVideoController(file.path); - } - }).onError((error, stackTrace) { - showErrorDialog( - context, - S.of(context).error, - S.of(context).failedToDownloadVideo, - ); - }); - } - - void _setFileSizeIfNull() { - if (widget.file.fileSize == null && widget.file.canEditMetaInfo) { - FilesService.instance - .getFileSize(widget.file.uploadedFileID!) - .then((value) { - widget.file.fileSize = value; - if (mounted) { - setState(() {}); - } - }); - } - } - - void _setVideoController(String url) { - if (mounted) { - setState(() { - if (controller == null) { - player.setPlaylistMode( - localSettings.shouldLoopVideo() - ? PlaylistMode.single - : PlaylistMode.none, - ); - controller = VideoController(player); - } - player.open(Media(url), play: _isAppInFG); - }); - } - } -} diff --git a/mobile/lib/ui/viewer/file/video_widget_native.dart b/mobile/lib/ui/viewer/file/video_widget_native.dart index b84cdc0e3c..3b658e79ce 100644 --- a/mobile/lib/ui/viewer/file/video_widget_native.dart +++ b/mobile/lib/ui/viewer/file/video_widget_native.dart @@ -18,6 +18,7 @@ import "package:photos/generated/l10n.dart"; import "package:photos/models/file/extensions/file_props.dart"; import "package:photos/models/file/file.dart"; import "package:photos/models/preview/playlist_data.dart"; +import "package:photos/module/download/task.dart"; import "package:photos/service_locator.dart"; import "package:photos/services/files_service.dart"; import "package:photos/services/wake_lock_service.dart"; @@ -45,6 +46,7 @@ class VideoWidgetNative extends StatefulWidget { final void Function()? onStreamChange; final PlaylistData? playlistData; final bool selectedPreview; + final Function({required int memoryDuration})? onFinalFileLoad; const VideoWidgetNative( this.file, { @@ -54,6 +56,7 @@ class VideoWidgetNative extends StatefulWidget { required this.onStreamChange, super.key, this.playlistData, + this.onFinalFileLoad, required this.selectedPreview, }); @@ -78,10 +81,13 @@ class _VideoWidgetNativeState extends State bool _isCompletelyVisible = false; final _showControls = ValueNotifier(true); final _isSeeking = ValueNotifier(false); - final _debouncer = Debouncer(const Duration(milliseconds: 2000)); + final _debouncer = Debouncer( + const Duration(milliseconds: 2000), + ); final _elTooltipController = ElTooltipController(); StreamSubscription? _subscription; StreamSubscription? _streamSwitchedSubscription; + StreamSubscription? downloadTaskSubscription; late final StreamSubscription _captionUpdatedSubscription; int position = 0; @@ -128,6 +134,15 @@ class _VideoWidgetNativeState extends State } } }); + if (widget.file.isUploaded) { + downloadTaskSubscription = downloadManager + .watchDownload( + widget.file.uploadedFileID!, + ) + .listen((event) { + _progressNotifier.value = event.progress; + }); + } EnteWakeLockService.instance .updateWakeLock(enable: true, wakeLockFor: WakeLockFor.videoPlayback); @@ -201,6 +216,10 @@ class _VideoWidgetNativeState extends State void dispose() { _subscription?.cancel(); _controller?.dispose(); + if (downloadTaskSubscription != null) { + downloadTaskSubscription!.cancel(); + downloadManager.pause(widget.file.uploadedFileID!).ignore(); + } //https://github.com/fluttercandies/flutter_photo_manager/blob/8afba2745ebaac6af8af75de9cbded9157bc2690/README.md#clear-caches if (_shouldClearCache) { @@ -282,12 +301,27 @@ class _VideoWidgetNativeState extends State ), GestureDetector( behavior: HitTestBehavior.opaque, - onTap: () { - _showControls.value = !_showControls.value; - if (widget.playbackCallback != null) { - widget.playbackCallback!(!_showControls.value); + onTap: widget.isFromMemories + ? null + : () { + _showControls.value = !_showControls.value; + if (widget.playbackCallback != null) { + widget + .playbackCallback!(!_showControls.value); + } + _elTooltipController.hide(); + }, + onLongPress: () { + if (widget.isFromMemories) { + widget.playbackCallback?.call(false); + _controller?.pause(); + } + }, + onLongPressUp: () { + if (widget.isFromMemories) { + widget.playbackCallback?.call(true); + _controller?.play(); } - _elTooltipController.hide(); }, child: Container( constraints: const BoxConstraints.expand(), @@ -312,86 +346,101 @@ class _VideoWidgetNativeState extends State ), ) : const SizedBox.shrink(), - Positioned.fill( - child: Center( - child: ValueListenableBuilder( - builder: (BuildContext context, bool value, _) { - return value - ? ValueListenableBuilder( - builder: (context, bool value, _) { - return AnimatedOpacity( - duration: - const Duration(milliseconds: 200), - opacity: value ? 1 : 0, - curve: Curves.easeInOutQuad, - child: IgnorePointer( - ignoring: !value, - child: PlayPauseButton(_controller), - ), - ); - }, - valueListenable: _showControls, - ) - : const SizedBox(); - }, - valueListenable: _isPlaybackReady, - ), - ), - ), - Positioned( - bottom: verticalMargin, - right: 0, - left: 0, - child: SafeArea( - top: false, - left: false, - right: false, - child: Padding( - padding: EdgeInsets.only( - bottom: widget.isFromMemories ? 32 : 0, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - _VideoDescriptionAndSwitchToMediaKitButton( - file: widget.file, - showControls: _showControls, - elTooltipController: _elTooltipController, - controller: _controller, - selectedPreview: widget.selectedPreview, - ), - ValueListenableBuilder( - valueListenable: _showControls, - builder: (context, value, _) { - return VideoStreamChangeWidget( - showControls: value, - file: widget.file, - isPreviewPlayer: widget.selectedPreview, - onStreamChange: widget.onStreamChange, - ); - }, - ), - ValueListenableBuilder( - valueListenable: _isPlaybackReady, + widget.isFromMemories + ? const SizedBox.shrink() + : Positioned.fill( + child: Center( + child: ValueListenableBuilder( builder: (BuildContext context, bool value, _) { return value - ? _SeekBarAndDuration( - controller: _controller, - duration: duration, - showControls: _showControls, - isSeeking: _isSeeking, - position: position, - file: widget.file, + ? ValueListenableBuilder( + builder: (context, bool value, _) { + return AnimatedOpacity( + duration: const Duration( + milliseconds: 200, + ), + opacity: value ? 1 : 0, + curve: Curves.easeInOutQuad, + child: IgnorePointer( + ignoring: !value, + child: PlayPauseButton( + _controller, + ), + ), + ); + }, + valueListenable: _showControls, ) : const SizedBox(); }, + valueListenable: _isPlaybackReady, ), - ], + ), + ), + widget.isFromMemories + ? const SizedBox.shrink() + : Positioned( + bottom: verticalMargin, + right: 0, + left: 0, + child: SafeArea( + top: false, + left: false, + right: false, + child: Padding( + padding: EdgeInsets.only( + bottom: widget.isFromMemories ? 32 : 0, + ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + _VideoDescriptionAndSwitchToMediaKitButton( + file: widget.file, + showControls: _showControls, + elTooltipController: + _elTooltipController, + controller: _controller, + selectedPreview: widget.selectedPreview, + ), + ValueListenableBuilder( + valueListenable: _showControls, + builder: (context, value, _) { + return VideoStreamChangeWidget( + showControls: value, + file: widget.file, + isPreviewPlayer: + widget.selectedPreview, + onStreamChange: + widget.onStreamChange, + ); + }, + ), + ValueListenableBuilder( + valueListenable: _isPlaybackReady, + builder: ( + BuildContext context, + bool value, + _, + ) { + return value + ? _SeekBarAndDuration( + controller: _controller, + duration: duration, + showControls: _showControls, + isSeeking: _isSeeking, + position: position, + file: widget.file, + ) + : const SizedBox(); + }, + ), + ], + ), + ), + ), ), - ), - ), - ), ], ), ), @@ -444,6 +493,7 @@ class _VideoWidgetNativeState extends State } void _seekListener() { + if (widget.isFromMemories) return; if (!_isSeeking.value && _controller?.playbackStatus == PlaybackStatus.playing) { _debouncer.run(() async { @@ -462,6 +512,7 @@ class _VideoWidgetNativeState extends State } void _onPlaybackStatusChanged() { + if (widget.isFromMemories) return; final duration = widget.file.duration != null ? widget.file.duration! * 1000 : _controller?.videoInfo?.durationInMilliseconds; @@ -506,6 +557,8 @@ class _VideoWidgetNativeState extends State Future _onPlaybackReady() async { if (_isPlaybackReady.value) return; await _controller!.play(); + final durationInSeconds = durationToSeconds(duration) ?? 10; + widget.onFinalFileLoad?.call(memoryDuration: durationInSeconds); unawaited(_controller!.setVolume(1)); _isPlaybackReady.value = true; } @@ -604,14 +657,26 @@ class _VideoWidgetNativeState extends State color: fillBaseDark, padding: 0, ) - : CircularProgressIndicator( - backgroundColor: Colors.transparent, - value: progress, - valueColor: const AlwaysStoppedAnimation( - Color.fromRGBO(45, 194, 98, 1.0), - ), - strokeWidth: 2, - strokeCap: StrokeCap.round, + : Stack( + children: [ + CircularProgressIndicator( + backgroundColor: Colors.transparent, + value: progress, + valueColor: const AlwaysStoppedAnimation( + Color.fromRGBO(45, 194, 98, 1.0), + ), + strokeWidth: 2, + strokeCap: StrokeCap.round, + ), + Center( + child: Text( + "${(progress * 100).toStringAsFixed(0)}%", + style: getEnteTextTheme(context).tiny.copyWith( + color: textBaseDark, + ), + ), + ), + ], ); }, ), @@ -707,11 +772,7 @@ class _SeekBarAndDuration extends StatelessWidget { Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: showControls, - builder: ( - BuildContext context, - bool value, - _, - ) { + builder: (BuildContext context, bool value, _) { return AnimatedOpacity( duration: const Duration( milliseconds: 200, diff --git a/mobile/lib/ui/viewer/file/zoomable_image.dart b/mobile/lib/ui/viewer/file/zoomable_image.dart index 9300b8cacc..f29315a2f2 100644 --- a/mobile/lib/ui/viewer/file/zoomable_image.dart +++ b/mobile/lib/ui/viewer/file/zoomable_image.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:io'; +import 'dart:math'; import 'dart:typed_data' show Uint8List; import 'package:flutter/material.dart'; @@ -13,6 +14,7 @@ import 'package:photos/db/files_db.dart'; import "package:photos/events/file_caption_updated_event.dart"; import "package:photos/events/files_updated_event.dart"; import 'package:photos/events/local_photos_updated_event.dart'; +import "package:photos/events/reset_zoom_of_photo_view_event.dart"; import "package:photos/models/file/extensions/file_props.dart"; import 'package:photos/models/file/file.dart'; import "package:photos/states/detail_page_state.dart"; @@ -31,6 +33,7 @@ class ZoomableImage extends StatefulWidget { final Decoration? backgroundDecoration; final bool shouldCover; final bool isGuestView; + final Function({required int memoryDuration})? onFinalFileLoad; const ZoomableImage( this.photo, { @@ -40,6 +43,7 @@ class ZoomableImage extends StatefulWidget { this.backgroundDecoration, this.shouldCover = false, this.isGuestView = false, + this.onFinalFileLoad, }); @override @@ -62,10 +66,11 @@ class _ZoomableImageState extends State { final _scaleStateController = PhotoViewScaleStateController(); late final StreamSubscription _captionUpdatedSubscription; + late final StreamSubscription _resetZoomSubscription; // This is to prevent the app from crashing when loading 200MP images // https://github.com/flutter/flutter/issues/110331 - bool get isTooLargeImage => _photo.width * _photo.height > 160000000; + bool get isTooLargeImage => _photo.width * _photo.height > 100000000; //100MP @override void initState() { @@ -90,6 +95,16 @@ class _ZoomableImageState extends State { } } }); + + _resetZoomSubscription = + Bus.instance.on().listen((event) { + if (event.isSamePhoto( + uploadedFileID: widget.photo.uploadedFileID, + localID: widget.photo.localID, + )) { + _scaleStateController.scaleState = PhotoViewScaleState.initial; + } + }); } @override @@ -97,6 +112,7 @@ class _ZoomableImageState extends State { _photoViewController.dispose(); _scaleStateController.dispose(); _captionUpdatedSubscription.cancel(); + _resetZoomSubscription.cancel(); super.dispose(); } @@ -370,23 +386,18 @@ class _ZoomableImageState extends State { ImageProvider imageProvider; if (isTooLargeImage) { _logger.info( - "Handling very large image (${_photo.width}x${_photo.height}) to prevent crash", + "Handling very large image (${_photo.width}x${_photo.height}) by decreasing resolution to 50MP to prevent crash", ); final aspectRatio = _photo.width / _photo.height; - int targetWidth, targetHeight; - if (aspectRatio > 1) { - targetWidth = 4096; - targetHeight = (targetWidth / aspectRatio).round(); - } else { - targetHeight = 4096; - targetWidth = (targetHeight * aspectRatio).round(); - } + const maxPixels = 50000000; + final targetHeight = sqrt(maxPixels / aspectRatio); + final targetWidth = aspectRatio * targetHeight; imageProvider = Image.file( file, gaplessPlayback: true, - cacheWidth: targetWidth, - cacheHeight: targetHeight, + cacheWidth: targetWidth.round(), + cacheHeight: targetHeight.round(), ).image; } else { imageProvider = Image.file( @@ -426,6 +437,7 @@ class _ZoomableImageState extends State { _loadedFinalImage = true; _logger.info("Final image loaded"); }); + widget.onFinalFileLoad?.call(memoryDuration: 5); } Future _updatePhotoViewController({ @@ -466,23 +478,17 @@ class _ZoomableImageState extends State { Uint8List? compressedFile; if (isTooLargeImage) { _logger.info( - "Compressing very large image (${_photo.width}x${_photo.height}) more aggressively", + "Compressing very large image (${_photo.width}x${_photo.height}) more aggressively down to 50MP", ); final aspectRatio = _photo.width / _photo.height; - int targetWidth, targetHeight; - - if (aspectRatio > 1) { - targetWidth = 4096; - targetHeight = (targetWidth / aspectRatio).round(); - } else { - targetHeight = 4096; - targetWidth = (targetHeight * aspectRatio).round(); - } + const maxPixels = 50000000; + final targetHeight = sqrt(maxPixels / aspectRatio); + final targetWidth = aspectRatio * targetHeight; compressedFile = await FlutterImageCompress.compressWithFile( file.path, - minWidth: targetWidth, - minHeight: targetHeight, + minWidth: targetWidth.round(), + minHeight: targetHeight.round(), quality: 85, ); } else { diff --git a/mobile/lib/ui/viewer/file/zoomable_live_image_new.dart b/mobile/lib/ui/viewer/file/zoomable_live_image_new.dart index 65f05dbdd0..a3757ac2a3 100644 --- a/mobile/lib/ui/viewer/file/zoomable_live_image_new.dart +++ b/mobile/lib/ui/viewer/file/zoomable_live_image_new.dart @@ -23,13 +23,17 @@ class ZoomableLiveImageNew extends StatefulWidget { final Function(bool)? shouldDisableScroll; final String? tagPrefix; final Decoration? backgroundDecoration; - + final bool isFromMemories; + final Function({required int memoryDuration})? onFinalFileLoad; + const ZoomableLiveImageNew( this.enteFile, { super.key, this.shouldDisableScroll, required this.tagPrefix, this.backgroundDecoration, + this.isFromMemories = false, + this.onFinalFileLoad, }); @override @@ -94,13 +98,17 @@ class _ZoomableLiveImageNewState extends State shouldDisableScroll: widget.shouldDisableScroll, backgroundDecoration: widget.backgroundDecoration, isGuestView: isGuestView, + onFinalFileLoad: widget.onFinalFileLoad, ); } - return GestureDetector( - onLongPressStart: (_) => {_onLongPressEvent(true)}, - onLongPressEnd: (_) => {_onLongPressEvent(false)}, - child: content, - ); + if (!widget.isFromMemories) { + return GestureDetector( + onLongPressStart: (_) => _onLongPressEvent(true), + onLongPressEnd: (_) => _onLongPressEvent(false), + child: content, + ); + } + return content; } @override @@ -203,7 +211,7 @@ class _ZoomableLiveImageNewState extends State index: index, ); } else if (_enteFile.isMotionPhoto && _enteFile.canEditMetaInfo) { - _logger.finest('Incorrectly tagged as MP, reset tag ${_enteFile.tag}'); + _logger.info('Incorrectly tagged as MP, reset tag ${_enteFile.tag}'); FileMagicService.instance.updatePublicMagicMetadata( [_enteFile], {motionVideoIndexKey: 0}, diff --git a/mobile/lib/ui/viewer/file_details/added_by_widget.dart b/mobile/lib/ui/viewer/file_details/added_by_widget.dart index 12f9a0a528..f1009f07e5 100644 --- a/mobile/lib/ui/viewer/file_details/added_by_widget.dart +++ b/mobile/lib/ui/viewer/file_details/added_by_widget.dart @@ -16,11 +16,6 @@ class AddedByWidget extends StatelessWidget { if (!file.isUploaded) { return const SizedBox.shrink(); } - final bool fileIsFromSharedPublicLink = - CollectionsService.instance.isSharedPublicLink(file.collectionID!); - if (fileIsFromSharedPublicLink) { - return const SizedBox.shrink(); - } String? addedBy; if (file.isOwner && file.isCollect) { addedBy = file.uploaderName; diff --git a/mobile/lib/ui/viewer/file_details/exif_item_widgets.dart b/mobile/lib/ui/viewer/file_details/exif_item_widgets.dart index dead77781b..d77a44988e 100644 --- a/mobile/lib/ui/viewer/file_details/exif_item_widgets.dart +++ b/mobile/lib/ui/viewer/file_details/exif_item_widgets.dart @@ -1,4 +1,4 @@ -import "package:exif/exif.dart"; +import "package:exif_reader/exif_reader.dart"; import "package:flutter/material.dart"; import "package:photos/generated/l10n.dart"; import 'package:photos/models/file/file.dart'; diff --git a/mobile/lib/ui/viewer/file_details/face_widget.dart b/mobile/lib/ui/viewer/file_details/face_widget.dart deleted file mode 100644 index 5dd11df9ac..0000000000 --- a/mobile/lib/ui/viewer/file_details/face_widget.dart +++ /dev/null @@ -1,310 +0,0 @@ -import "dart:async"; -import "dart:developer" show log; -import "dart:typed_data"; - -import "package:flutter/cupertino.dart"; -import "package:flutter/foundation.dart" show kDebugMode; -import "package:flutter/material.dart"; -import "package:logging/logging.dart"; -import "package:photos/db/ml/db.dart"; -import "package:photos/generated/l10n.dart"; -import "package:photos/models/base/id.dart"; -import 'package:photos/models/file/file.dart'; -import "package:photos/models/ml/face/face.dart"; -import "package:photos/models/ml/face/person.dart"; -import "package:photos/services/machine_learning/face_ml/face_detection/detection.dart"; -import "package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart"; -import "package:photos/services/machine_learning/face_ml/feedback/cluster_feedback.dart"; -import "package:photos/services/machine_learning/ml_service.dart"; -import "package:photos/services/search_service.dart"; -import "package:photos/theme/ente_theme.dart"; -import "package:photos/ui/notification/toast.dart"; -import "package:photos/ui/viewer/file/no_thumbnail_widget.dart"; -import "package:photos/ui/viewer/people/cluster_page.dart"; -import "package:photos/ui/viewer/people/people_page.dart"; -import "package:photos/utils/face/face_box_crop.dart"; - -class FaceWidget extends StatefulWidget { - final EnteFile file; - final Face face; - final Future?>? faceCrops; - final PersonEntity? person; - final String? clusterID; - final bool highlight; - final bool editMode; - - const FaceWidget( - this.file, - this.face, { - this.faceCrops, - this.person, - this.clusterID, - this.highlight = false, - this.editMode = false, - super.key, - }); - - @override - State createState() => _FaceWidgetState(); -} - -class _FaceWidgetState extends State { - bool isJustRemoved = false; - - final _logger = Logger("FaceWidget"); - - @override - Widget build(BuildContext context) { - final bool givenFaces = widget.faceCrops != null; - return _buildFaceImageGenerated(givenFaces); - } - - Widget _buildFaceImageGenerated(bool givenFaces) { - late final mlDataDB = MLDataDB.instance; - return FutureBuilder?>( - future: givenFaces - ? widget.faceCrops - : getCachedFaceCrops(widget.file, [widget.face]), - builder: (context, snapshot) { - if (snapshot.hasData) { - final ImageProvider imageProvider = - MemoryImage(snapshot.data![widget.face.faceID]!); - - return GestureDetector( - onTap: () async { - if (widget.editMode) return; - - log( - "FaceWidget is tapped, with person ${widget.person?.data.name} and clusterID ${widget.clusterID}", - name: "FaceWidget", - ); - if (widget.person == null && widget.clusterID == null) { - // Double check that it doesn't belong to an existing clusterID. - final existingClusterID = - await mlDataDB.getClusterIDForFaceID(widget.face.faceID); - if (existingClusterID != null) { - final fileIdsToClusterIds = - await mlDataDB.getFileIdToClusterIds(); - final files = - await SearchService.instance.getAllFilesForSearch(); - final clusterFiles = files - .where( - (file) => - fileIdsToClusterIds[file.uploadedFileID] - ?.contains(existingClusterID) ?? - false, - ) - .toList(); - await Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => ClusterPage( - clusterFiles, - clusterID: existingClusterID, - ), - ), - ); - return; - } - if (widget.face.score <= kMinimumQualityFaceScore) { - // The face score is too low for automatic clustering, - // assigning a manual new clusterID so that the user can cluster it manually - final String clusterID = newClusterID(); - await mlDataDB.updateFaceIdToClusterId( - {widget.face.faceID: clusterID}, - ); - await Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => ClusterPage( - [widget.file], - clusterID: clusterID, - ), - ), - ); - return; - } - - showShortToast( - context, - S.of(context).faceNotClusteredYet, - ); - unawaited(MLService.instance.clusterAllImages(force: true)); - return; - } - if (widget.person != null) { - await Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => PeoplePage( - person: widget.person!, - searchResult: null, - ), - ), - ); - } else if (widget.clusterID != null) { - final fileIdsToClusterIds = - await mlDataDB.getFileIdToClusterIds(); - final files = - await SearchService.instance.getAllFilesForSearch(); - final clusterFiles = files - .where( - (file) => - fileIdsToClusterIds[file.uploadedFileID] - ?.contains(widget.clusterID) ?? - false, - ) - .toList(); - await Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => ClusterPage( - clusterFiles, - clusterID: widget.clusterID!, - ), - ), - ); - } - }, - child: Column( - children: [ - Stack( - children: [ - Container( - height: 60, - width: 60, - decoration: ShapeDecoration( - shape: RoundedRectangleBorder( - borderRadius: const BorderRadius.all( - Radius.elliptical(16, 12), - ), - side: widget.highlight - ? BorderSide( - color: getEnteColorScheme(context).primary700, - width: 1.0, - ) - : BorderSide.none, - ), - ), - child: ClipRRect( - borderRadius: - const BorderRadius.all(Radius.elliptical(16, 12)), - child: SizedBox( - width: 60, - height: 60, - child: Image( - image: imageProvider, - fit: BoxFit.cover, - ), - ), - ), - ), - // TODO: the edges of the green line are still not properly rounded around ClipRRect - if (widget.editMode) - Positioned( - right: 0, - top: 0, - child: GestureDetector( - onTap: _cornerIconPressed, - child: isJustRemoved - ? const Icon( - CupertinoIcons.add_circled_solid, - color: Colors.green, - ) - : const Icon( - Icons.cancel, - color: Colors.red, - ), - ), - ), - ], - ), - const SizedBox(height: 8), - if (widget.person != null) - Text( - widget.person!.data.isIgnored - ? '(' + S.of(context).ignored + ')' - : widget.person!.data.name.trim(), - style: Theme.of(context).textTheme.bodySmall, - overflow: TextOverflow.ellipsis, - maxLines: 1, - ), - if (kDebugMode) - Text( - 'S: ${widget.face.score.toStringAsFixed(3)} (I)', - style: Theme.of(context).textTheme.bodySmall, - maxLines: 1, - ), - if (kDebugMode) - Text( - 'B: ${widget.face.blur.toStringAsFixed(0)} (I)', - style: Theme.of(context).textTheme.bodySmall, - maxLines: 1, - ), - if (kDebugMode) - Text( - 'D: ${widget.face.detection.getFaceDirection().toDirectionString()} (I)', - style: Theme.of(context).textTheme.bodySmall, - maxLines: 1, - ), - if (kDebugMode) - Text( - 'Sideways: ${widget.face.detection.faceIsSideways().toString()} (I)', - style: Theme.of(context).textTheme.bodySmall, - maxLines: 1, - ), - if (kDebugMode && widget.face.score < kMinimumFaceShowScore) - Text( - 'Not visible to user (I)', - style: Theme.of(context).textTheme.bodySmall, - maxLines: 1, - ), - ], - ), - ); - } else { - if (snapshot.connectionState == ConnectionState.waiting) { - return const ClipRRect( - borderRadius: BorderRadius.all(Radius.elliptical(16, 12)), - child: SizedBox( - width: 60, - height: 60, - child: CircularProgressIndicator(), - ), - ); - } - if (snapshot.hasError) { - _logger.severe( - 'Error getting face: ${snapshot.error} ${snapshot.stackTrace}', - ); - } - return const ClipRRect( - borderRadius: BorderRadius.all(Radius.elliptical(16, 12)), - child: SizedBox( - width: 60, - height: 60, - child: NoThumbnailWidget(), - ), - ); - } - }, - ); - } - - void _cornerIconPressed() async { - log('face widget (file info) corner icon is pressed'); - try { - if (isJustRemoved) { - await ClusterFeedbackService.instance - .addFacesToCluster([widget.face.faceID], widget.clusterID!); - } else { - await ClusterFeedbackService.instance - .removeFilesFromCluster([widget.file], widget.clusterID!); - } - - setState(() { - isJustRemoved = !isJustRemoved; - }); - } catch (e, s) { - _logger.severe( - "removing face/file from cluster from file info widget failed: $e, \n $s", - ); - } - } -} diff --git a/mobile/lib/ui/viewer/file_details/faces_item_widget.dart b/mobile/lib/ui/viewer/file_details/faces_item_widget.dart deleted file mode 100644 index 8be39494a0..0000000000 --- a/mobile/lib/ui/viewer/file_details/faces_item_widget.dart +++ /dev/null @@ -1,209 +0,0 @@ -import "package:flutter/foundation.dart" show kDebugMode; -import "package:flutter/material.dart"; -import "package:logging/logging.dart"; -import "package:photos/db/ml/db.dart"; -import "package:photos/generated/l10n.dart"; -import "package:photos/models/file/file.dart"; -import "package:photos/models/ml/face/face.dart"; -import "package:photos/models/ml/face/person.dart"; -import "package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart"; -import "package:photos/services/machine_learning/face_ml/feedback/cluster_feedback.dart"; -import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; -import "package:photos/ui/components/buttons/chip_button_widget.dart"; -import "package:photos/ui/components/info_item_widget.dart"; -import "package:photos/ui/viewer/file_details/face_widget.dart"; -import "package:photos/utils/face/face_box_crop.dart"; - -final Logger _logger = Logger("FacesItemWidget"); - -class FacesItemWidget extends StatefulWidget { - final EnteFile file; - const FacesItemWidget(this.file, {super.key}); - - @override - State createState() => _FacesItemWidgetState(); -} - -class _FacesItemWidgetState extends State { - bool editMode = false; - - @override - void initState() { - super.initState(); - setState(() {}); - } - - @override - Widget build(BuildContext context) { - return InfoItemWidget( - key: const ValueKey("Faces"), - leadingIcon: Icons.face_retouching_natural_outlined, - subtitleSection: _faceWidgets(context, widget.file, editMode), - hasChipButtons: true, - biggerSpinner: true, - ); - } - - Future> _faceWidgets( - BuildContext context, - EnteFile file, - bool editMode, - ) async { - late final mlDataDB = MLDataDB.instance; - try { - if (file.uploadedFileID == null) { - return [const NoFaceChipButtonWidget(NoFacesReason.fileNotUploaded)]; - } - - final List? faces = - await mlDataDB.getFacesForGivenFileID(file.uploadedFileID!); - if (faces == null) { - return [const NoFaceChipButtonWidget(NoFacesReason.fileNotAnalyzed)]; - } - - // Remove faces with low scores - if (!kDebugMode) { - final beforeLength = faces.length; - final lowScores = faces - .where((face) => (face.score < kMinimumFaceShowScore)) - .toList(); - faces.removeWhere((face) => (face.score < kMinimumFaceShowScore)); - if (faces.length != beforeLength) { - _logger.warning( - 'File ${file.uploadedFileID} has ${beforeLength - faces.length} faces with low scores ($lowScores) that are not shown in the UI', - ); - } - } else { - faces.removeWhere((face) => (face.score < 0.5)); - } - - if (faces.isEmpty) { - return [const NoFaceChipButtonWidget(NoFacesReason.noFacesFound)]; - } - - final faceIdsToClusterIds = await mlDataDB - .getFaceIdsToClusterIds(faces.map((face) => face.faceID)); - final Map persons = - await PersonService.instance.getPersonsMap(); - final clusterIDToPerson = await mlDataDB.getClusterIDToPersonID(); - - // Sort faces by name and score - final faceIdToPersonID = {}; - for (final face in faces) { - final clusterID = faceIdsToClusterIds[face.faceID]; - if (clusterID != null) { - final personID = clusterIDToPerson[clusterID]; - if (personID != null) { - faceIdToPersonID[face.faceID] = personID; - } - } - } - faces.sort((Face a, Face b) { - final aPersonID = faceIdToPersonID[a.faceID]; - final bPersonID = faceIdToPersonID[b.faceID]; - if (aPersonID != null && bPersonID == null) { - return -1; - } else if (aPersonID == null && bPersonID != null) { - return 1; - } else { - return b.score.compareTo(a.score); - } - }); - // Make sure hidden faces are last - faces.sort((Face a, Face b) { - final aIsHidden = - persons[faceIdToPersonID[a.faceID]]?.data.isIgnored ?? false; - final bIsHidden = - persons[faceIdToPersonID[b.faceID]]?.data.isIgnored ?? false; - if (aIsHidden && !bIsHidden) { - return 1; - } else if (!aIsHidden && bIsHidden) { - return -1; - } else { - return 0; - } - }); - - final lastViewedClusterID = ClusterFeedbackService.lastViewedClusterID; - - final faceWidgets = []; - - // await generation of the face crops here, so that the file info shows one central loading spinner - final _ = await getCachedFaceCrops(file, faces); - - final faceCrops = getCachedFaceCrops(file, faces); - final List faceIDs = []; - final List faceScores = []; - for (final Face face in faces) { - final String? clusterID = faceIdsToClusterIds[face.faceID]; - final PersonEntity? person = clusterIDToPerson[clusterID] != null - ? persons[clusterIDToPerson[clusterID]!] - : null; - final highlight = - (clusterID == lastViewedClusterID) && (person == null); - faceIDs.add(face.faceID); - faceScores.add(face.score); - faceWidgets.add( - FaceWidget( - file, - face, - faceCrops: faceCrops, - clusterID: clusterID, - person: person, - highlight: highlight, - editMode: highlight ? editMode : false, - ), - ); - } - - _logger.info( - 'File ${file.uploadedFileID} has FaceIDs: $faceIDs with scores: $faceScores', - ); - - return faceWidgets; - } catch (e, s) { - _logger.severe('failed to get face widgets in file info', e, s); - return []; - } - } -} - -enum NoFacesReason { - fileNotUploaded, - fileNotAnalyzed, - noFacesFound, -} - -String getNoFaceReasonText( - BuildContext context, - NoFacesReason reason, -) { - switch (reason) { - case NoFacesReason.fileNotUploaded: - return S.of(context).fileNotUploadedYet; - case NoFacesReason.fileNotAnalyzed: - return S.of(context).imageNotAnalyzed; - case NoFacesReason.noFacesFound: - return S.of(context).noFacesFound; - } -} - -class NoFaceChipButtonWidget extends StatelessWidget { - final NoFacesReason reason; - - const NoFaceChipButtonWidget( - this.reason, { - super.key, - }); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(top: 5), - child: ChipButtonWidget( - getNoFaceReasonText(context, reason), - noChips: true, - ), - ); - } -} diff --git a/mobile/lib/ui/viewer/file_details/file_info_face_widget.dart b/mobile/lib/ui/viewer/file_details/file_info_face_widget.dart new file mode 100644 index 0000000000..e5f2c4b0af --- /dev/null +++ b/mobile/lib/ui/viewer/file_details/file_info_face_widget.dart @@ -0,0 +1,309 @@ +import "dart:async"; +import "dart:typed_data"; + +import "package:flutter/foundation.dart" show kDebugMode; +import "package:flutter/material.dart"; +import "package:logging/logging.dart"; +import "package:photos/db/ml/db.dart"; +import "package:photos/generated/l10n.dart"; +import "package:photos/models/base/id.dart"; +import 'package:photos/models/file/file.dart'; +import "package:photos/models/ml/face/face.dart"; +import "package:photos/models/ml/face/person.dart"; +import "package:photos/services/machine_learning/face_ml/face_detection/detection.dart"; +import "package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart"; +import "package:photos/services/machine_learning/face_ml/feedback/cluster_feedback.dart"; +import "package:photos/services/machine_learning/ml_service.dart"; +import "package:photos/services/search_service.dart"; +import "package:photos/theme/ente_theme.dart"; +import "package:photos/ui/components/buttons/button_widget.dart"; +import "package:photos/ui/components/models/button_type.dart"; +import "package:photos/ui/notification/toast.dart"; +import "package:photos/ui/viewer/people/cluster_page.dart"; +import "package:photos/ui/viewer/people/file_face_widget.dart"; +import "package:photos/ui/viewer/people/people_page.dart"; +import "package:photos/ui/viewer/people/save_or_edit_person.dart"; +import "package:photos/utils/dialog_util.dart"; + +final _logger = Logger("FileInfoFaceWidget"); + +class FileInfoFaceWidget extends StatefulWidget { + final EnteFile file; + final Face face; + final Uint8List faceCrop; + final PersonEntity? person; + final String? clusterID; + final double? width; + final bool highlight; + final bool isEditMode; + final Future Function() reloadAllFaces; + + const FileInfoFaceWidget( + this.file, + this.face, { + required this.faceCrop, + this.person, + this.clusterID, + this.highlight = false, + this.isEditMode = false, + this.width, + required this.reloadAllFaces, + super.key, + }); + + @override + State createState() => _FileInfoFaceWidgetState(); +} + +class _FileInfoFaceWidgetState extends State { + bool get hasPerson => widget.person != null; + bool get isEditMode => widget.isEditMode; + double get thumbnailWidth => widget.width ?? 68; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Stack( + clipBehavior: Clip.none, + children: [ + GestureDetector( + onTap: isEditMode + ? hasPerson + ? _onMinusIconTap + : _onPlusIconTap + : _routeToPersonOrClusterPage, + child: Container( + height: thumbnailWidth, + width: thumbnailWidth, + decoration: ShapeDecoration( + shape: RoundedRectangleBorder( + borderRadius: const BorderRadius.all( + Radius.elliptical(16, 12), + ), + side: widget.highlight + ? BorderSide( + color: getEnteColorScheme(context).primary700, + width: 1.0, + ) + : BorderSide.none, + ), + ), + child: ClipRRect( + child: SizedBox( + width: thumbnailWidth, + height: thumbnailWidth, + child: ClipPath( + clipper: ShapeBorderClipper( + shape: ContinuousRectangleBorder( + borderRadius: BorderRadius.circular(52), + ), + ), + child: FileFaceWidget( + key: ValueKey(widget.face.faceID), + widget.file, + faceCrop: widget.faceCrop, + ), + ), + ), + ), + ), + ), + if (isEditMode) _buildEditIcon(context), + ], + ), + const SizedBox(height: 8), + ..._buildFaceInfo(), + ], + ); + } + + List _buildFaceInfo() { + final List faceInfo = []; + if (widget.person != null) { + faceInfo.add( + SizedBox( + width: thumbnailWidth, + child: Center( + child: Text( + widget.person!.data.isIgnored + ? '(' + S.of(context).ignored + ')' + : widget.person!.data.name.trim(), + style: Theme.of(context).textTheme.bodySmall, + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), + ), + ), + ); + } + if (kDebugMode) { + faceInfo.add( + Text( + 'S:${widget.face.score.toStringAsFixed(2)}(I)', + style: Theme.of(context).textTheme.bodySmall, + maxLines: 1, + ), + ); + faceInfo.add( + Text( + 'B:${widget.face.blur.toStringAsFixed(0)}(I)', + style: Theme.of(context).textTheme.bodySmall, + maxLines: 1, + ), + ); + faceInfo.add( + Text( + 'D:${widget.face.detection.getFaceDirection().toDirectionString().substring(0, 3)}(I)', + style: Theme.of(context).textTheme.bodySmall, + maxLines: 1, + ), + ); + faceInfo.add( + Text( + 'Si:${widget.face.detection.faceIsSideways().toString()}(I)', + style: Theme.of(context).textTheme.bodySmall, + maxLines: 1, + ), + ); + } + return faceInfo; + } + + Future _routeToPersonOrClusterPage() async { + final mlDataDB = MLDataDB.instance; + if (widget.person != null) { + await Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => PeoplePage( + person: widget.person!, + searchResult: null, + ), + ), + ); + return; + } + final String? clusterID = widget.clusterID ?? + await mlDataDB.getClusterIDForFaceID(widget.face.faceID); + if (clusterID != null) { + final fileIdsToClusterIds = await mlDataDB.getFileIdToClusterIds(); + final files = await SearchService.instance.getAllFilesForSearch(); + final clusterFiles = files + .where( + (file) => + fileIdsToClusterIds[file.uploadedFileID]?.contains(clusterID) ?? + false, + ) + .toList(); + await Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => ClusterPage( + clusterFiles, + clusterID: clusterID, + ), + ), + ); + return; + } + if (widget.face.score <= kMinimumQualityFaceScore) { + // The face score is too low for automatic clustering, + // assigning a manual new clusterID so that the user can cluster it manually + final String clusterID = newClusterID(); + await mlDataDB.updateFaceIdToClusterId( + {widget.face.faceID: clusterID}, + ); + await Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => ClusterPage( + [widget.file], + clusterID: clusterID, + ), + ), + ); + return; + } + + showShortToast( + context, + S.of(context).faceNotClusteredYet, + ); + unawaited(MLService.instance.clusterAllImages(force: true)); + return; + } + + Future _onPlusIconTap() async { + try { + final newClusterIDValue = + await ClusterFeedbackService.instance.removeFaceFromCluster( + faceID: widget.face.faceID, + clusterID: widget.clusterID, + ); + await Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => SaveOrEditPerson( + newClusterIDValue, + file: widget.file, + isEditing: false, + ), + ), + ); + await widget.reloadAllFaces(); + } catch (e, s) { + _logger.severe('Error handling plus icon tap', e, s); + } + } + + Future _onMinusIconTap() async { + if (widget.person == null) return; + final result = await showChoiceActionSheet( + context, + title: S.of(context).removePersonLabel, + body: S.of(context).areYouSureRemoveThisFaceFromPerson, + firstButtonLabel: S.of(context).remove, + firstButtonType: ButtonType.critical, + secondButtonLabel: S.of(context).cancel, + isCritical: true, + ); + if (result?.action == ButtonAction.first) { + try { + await ClusterFeedbackService.instance.removeFaceFromPerson( + widget.face.faceID, + widget.person!, + ); + await widget.reloadAllFaces(); + } catch (e, s) { + _logger.severe('Error removing face from person', e, s); + } + } + } + + Widget _buildEditIcon(BuildContext context) { + return Positioned( + right: -5, + top: -5, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () => hasPerson ? _onMinusIconTap() : _onPlusIconTap(), + child: Container( + width: 20, + height: 20, + decoration: BoxDecoration( + color: hasPerson + ? getEnteColorScheme(context).warning500 + : getEnteColorScheme(context).primary500, + shape: BoxShape.circle, + border: Border.all( + color: getEnteColorScheme(context).backgroundBase, + width: 2, + ), + ), + child: Icon( + hasPerson ? Icons.remove : Icons.add, + size: 12, + color: getEnteColorScheme(context).backgroundBase, + ), + ), + ), + ); + } +} diff --git a/mobile/lib/ui/viewer/file_details/file_info_faces_item_widget.dart b/mobile/lib/ui/viewer/file_details/file_info_faces_item_widget.dart new file mode 100644 index 0000000000..4f46e85950 --- /dev/null +++ b/mobile/lib/ui/viewer/file_details/file_info_faces_item_widget.dart @@ -0,0 +1,449 @@ +import "dart:async"; +import "dart:typed_data"; + +import "package:flutter/material.dart"; +import "package:logging/logging.dart"; +import "package:photos/db/ml/db.dart"; +import "package:photos/generated/l10n.dart"; +import "package:photos/models/file/file.dart"; +import "package:photos/models/ml/face/face.dart"; +import "package:photos/models/ml/face/person.dart"; +import "package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart"; +import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; +import "package:photos/theme/ente_theme.dart"; +import "package:photos/ui/common/loading_widget.dart"; +import "package:photos/ui/components/buttons/chip_button_widget.dart"; +import "package:photos/ui/components/buttons/icon_button_widget.dart"; +import "package:photos/ui/viewer/file_details/file_info_face_widget.dart"; +import "package:photos/utils/face/face_thumbnail_cache.dart"; + +final Logger _logger = Logger("FacesItemWidget"); + +class FacesItemWidget extends StatefulWidget { + final EnteFile file; + const FacesItemWidget(this.file, {super.key}); + + @override + State createState() => _FacesItemWidgetState(); +} + +class _FacesItemWidgetState extends State { + bool _isEditMode = false; + bool _showRemainingFaces = false; + bool _isLoading = true; + List<_FaceInfo> _defaultFaces = []; + List<_FaceInfo> _remainingFaces = []; + NoFacesReason? _errorReason; + + @override + void initState() { + super.initState(); + loadFaces(); + } + + Future loadFaces({bool isRefresh = false}) async { + if (!isRefresh && mounted) { + setState(() => _isLoading = true); + } + + try { + final result = await _fetchFaceData(); + if (mounted) { + setState(() { + _defaultFaces = result.defaultFaces; + _remainingFaces = result.remainingFaces; + _errorReason = result.errorReason; + if (!isRefresh) { + _isLoading = false; + } + }); + } + } catch (e, s) { + _logger.severe('Failed to load faces', e, s); + if (!isRefresh && mounted) { + setState(() => _isLoading = false); + } + } + } + + @override + Widget build(BuildContext context) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const IconButtonWidget( + icon: Icons.face_retouching_natural_outlined, + iconButtonType: IconButtonType.secondary, + ), + const SizedBox(width: 12), + _buildContent(), + ], + ); + } + + Widget _buildContent() { + if (_isLoading) { + return const Expanded( + child: Padding( + padding: EdgeInsets.only(top: 8, right: 12), + child: Center( + child: EnteLoadingWidget( + padding: 6, + size: 20, + alignment: Alignment.center, + ), + ), + ), + ); + } + + if (_errorReason != null || + (_defaultFaces.isEmpty && _remainingFaces.isEmpty)) { + return _buildNoFacesWidget(); + } + + return Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(top: 12.0), + child: SizedBox( + height: 24, + child: Center( + child: Text( + S.of(context).faces, + style: getEnteTextTheme(context).small, + ), + ), + ), + ), + _editStateButton(), + ], + ), + const SizedBox(height: 20), + if (_defaultFaces.isNotEmpty) _buildFaceGrid(_defaultFaces), + if (_remainingFaces.isNotEmpty) ...[ + const SizedBox(height: 16), + _buildRemainingFacesSection(), + ], + ], + ), + ); + } + + Widget _buildFaceGrid(List<_FaceInfo> faceInfoList) { + final screenWidth = MediaQuery.of(context).size.width; + final thumbnailWidth = screenWidth * 0.16; + return Padding( + padding: const EdgeInsets.only(right: 12.0), + child: Wrap( + runSpacing: 8, + spacing: 12, + children: faceInfoList + .map( + (faceInfo) => FileInfoFaceWidget( + widget.file, + faceInfo.face, + faceCrop: faceInfo.faceCrop, + person: faceInfo.person, + clusterID: faceInfo.clusterID, + width: thumbnailWidth, + isEditMode: _isEditMode, + reloadAllFaces: () => loadFaces(isRefresh: true), + ), + ) + .toList(), + ), + ); + } + + Future> _buildFaceInfoList( + List faces, + Map faceIdsToClusterIds, + Map persons, + Map clusterIDToPerson, + Map faceCrops, + ) async { + final faceInfoList = <_FaceInfo>[]; + + // Build person mapping for sorting + final faceIdToPersonID = {}; + for (final face in faces) { + final clusterID = faceIdsToClusterIds[face.faceID]; + if (clusterID != null) { + final personID = clusterIDToPerson[clusterID]; + if (personID != null) { + faceIdToPersonID[face.faceID] = personID; + } + } + } + + // Sort faces: named first, then by score, hidden last + faces.sort((a, b) { + final aPersonID = faceIdToPersonID[a.faceID]; + final bPersonID = faceIdToPersonID[b.faceID]; + final aIsHidden = persons[aPersonID]?.data.isIgnored ?? false; + final bIsHidden = persons[bPersonID]?.data.isIgnored ?? false; + + if (aIsHidden != bIsHidden) return aIsHidden ? 1 : -1; + if ((aPersonID != null) != (bPersonID != null)) { + return aPersonID != null ? -1 : 1; + } + return b.score.compareTo(a.score); + }); + + // Create face info objects + for (final face in faces) { + final faceCrop = faceCrops[face.faceID]; + if (faceCrop == null) { + _logger.severe('Missing face crop for ${face.faceID}'); + continue; + } + + final clusterID = faceIdsToClusterIds[face.faceID]; + final person = clusterIDToPerson[clusterID] != null + ? persons[clusterIDToPerson[clusterID]!] + : null; + + faceInfoList.add( + _FaceInfo( + face: face, + faceCrop: faceCrop, + clusterID: clusterID, + person: person, + ), + ); + } + + return faceInfoList; + } + + Widget _buildNoFacesWidget() { + final reason = _errorReason ?? NoFacesReason.noFacesFound; + return Expanded( + child: Padding( + padding: const EdgeInsets.only(right: 12, top: 8), + child: ChipButtonWidget( + getNoFaceReasonText(context, reason), + noChips: true, + ), + ), + ); + } + + Widget _buildRemainingFacesSection() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(top: 4.0), + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: _toggleRemainingFaces, + child: Row( + children: [ + Text( + S.of(context).otherDetectedFaces, + style: getEnteTextTheme(context).miniMuted, + ), + const Spacer(), + Padding( + padding: const EdgeInsets.only(right: 12.0), + child: Icon( + _showRemainingFaces + ? Icons.keyboard_arrow_up + : Icons.keyboard_arrow_down, + size: 16, + color: getEnteColorScheme(context).textMuted, + ), + ), + ], + ), + ), + ), + if (_showRemainingFaces) ...[ + const SizedBox(height: 16), + _buildFaceGrid(_remainingFaces), + ], + ], + ); + } + + Widget _editStateButton() { + return SizedBox( + height: 36, + child: _isEditMode + ? Padding( + padding: const EdgeInsets.only(top: 12.0, right: 12.0), + child: Center( + child: GestureDetector( + onTap: _toggleEditMode, + child: Container( + padding: + const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + decoration: BoxDecoration( + border: Border.all( + color: getEnteColorScheme(context).primary500, + width: 1, + ), + borderRadius: BorderRadius.circular(12), + ), + child: Text( + S.of(context).done, + style: getEnteTextTheme(context).small.copyWith( + color: getEnteColorScheme(context).primary500, + ), + ), + ), + ), + ), + ) + : IconButtonWidget( + icon: Icons.edit, + iconButtonType: IconButtonType.secondary, + onTap: _toggleEditMode, + ), + ); + } + + Future<_FaceDataResult> _fetchFaceData() async { + if (widget.file.uploadedFileID == null) { + return _FaceDataResult( + defaultFaces: [], + remainingFaces: [], + errorReason: NoFacesReason.fileNotUploaded, + ); + } + + final mlDataDB = MLDataDB.instance; + final faces = + await mlDataDB.getFacesForGivenFileID(widget.file.uploadedFileID!); + + if (faces == null) { + return _FaceDataResult( + defaultFaces: [], + remainingFaces: [], + errorReason: NoFacesReason.fileNotAnalyzed, + ); + } + + // Get additional data + final faceIdsToClusterIds = await mlDataDB.getFaceIdsToClusterIds( + faces.map((face) => face.faceID).toList(), + ); + final persons = await PersonService.instance.getPersonsMap(); + final clusterIDToPerson = await mlDataDB.getClusterIDToPersonID(); + final faceCrops = + await getCachedFaceCrops(widget.file, faces, useTempCache: true); + final defaultFaces = []; + final remainingFaces = []; + + for (final face in faces) { + if (face.score >= kMinimumFaceShowScore) { + defaultFaces.add(face); + } else if (clusterIDToPerson[faceIdsToClusterIds[face.faceID] ?? ""] != + null) { + defaultFaces.add(face); + } else if (face.score >= kMinFaceDetectionScore) { + remainingFaces.add(face); + } + } + if (defaultFaces.isEmpty && remainingFaces.isEmpty) { + return _FaceDataResult( + defaultFaces: [], + remainingFaces: [], + errorReason: NoFacesReason.noFacesFound, + ); + } + + if (faceCrops == null) { + return _FaceDataResult( + defaultFaces: [], + remainingFaces: [], + errorReason: NoFacesReason.faceThumbnailGenerationFailed, + ); + } + for (final face in defaultFaces) { + if (faceCrops[face.faceID] == null) { + return _FaceDataResult( + defaultFaces: [], + remainingFaces: [], + errorReason: NoFacesReason.faceThumbnailGenerationFailed, + ); + } + } + + return _FaceDataResult( + defaultFaces: await _buildFaceInfoList( + defaultFaces, + faceIdsToClusterIds, + persons, + clusterIDToPerson, + faceCrops, + ), + remainingFaces: await _buildFaceInfoList( + remainingFaces, + faceIdsToClusterIds, + persons, + clusterIDToPerson, + faceCrops, + ), + ); + } + + void _toggleEditMode() => setState(() => _isEditMode = !_isEditMode); + + void _toggleRemainingFaces() => + setState(() => _showRemainingFaces = !_showRemainingFaces); +} + +class _FaceDataResult { + final List<_FaceInfo> defaultFaces; + final List<_FaceInfo> remainingFaces; + final NoFacesReason? errorReason; + + _FaceDataResult({ + required this.defaultFaces, + required this.remainingFaces, + this.errorReason, + }); +} + +class _FaceInfo { + final Face face; + final Uint8List faceCrop; + final String? clusterID; + final PersonEntity? person; + + _FaceInfo({ + required this.face, + required this.faceCrop, + this.clusterID, + this.person, + }); +} + +enum NoFacesReason { + fileNotUploaded, + fileNotAnalyzed, + noFacesFound, + faceThumbnailGenerationFailed, +} + +String getNoFaceReasonText(BuildContext context, NoFacesReason reason) { + switch (reason) { + case NoFacesReason.fileNotUploaded: + return S.of(context).fileNotUploadedYet; + case NoFacesReason.fileNotAnalyzed: + return S.of(context).imageNotAnalyzed; + case NoFacesReason.noFacesFound: + return S.of(context).noFacesFound; + case NoFacesReason.faceThumbnailGenerationFailed: + return "Unable to generate face thumbnails"; + } +} diff --git a/mobile/lib/ui/viewer/file_details/preview_properties_item_widget.dart b/mobile/lib/ui/viewer/file_details/preview_properties_item_widget.dart index 6e5d15d7d5..81fa413975 100644 --- a/mobile/lib/ui/viewer/file_details/preview_properties_item_widget.dart +++ b/mobile/lib/ui/viewer/file_details/preview_properties_item_widget.dart @@ -3,7 +3,7 @@ import "package:photos/generated/l10n.dart"; import "package:photos/models/ffmpeg/ffprobe_props.dart"; import 'package:photos/models/file/file.dart'; import "package:photos/models/file/file_type.dart"; -import "package:photos/services/preview_video_store.dart"; +import "package:photos/services/video_preview_service.dart"; import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/components/info_item_widget.dart"; import "package:photos/utils/standalone/data.dart"; @@ -44,7 +44,7 @@ class _PreviewPropertiesItemWidgetState final textStyle = getEnteTextTheme(context).miniMuted; final subSectionWidgets = []; - final data = await PreviewVideoStore.instance + final data = await VideoPreviewService.instance .getPlaylist(widget.file) .onError((error, stackTrace) { if (!mounted) return; diff --git a/mobile/lib/ui/viewer/file_details/upload_icon_widget.dart b/mobile/lib/ui/viewer/file_details/upload_icon_widget.dart index 7493fc0be9..262e206c72 100644 --- a/mobile/lib/ui/viewer/file_details/upload_icon_widget.dart +++ b/mobile/lib/ui/viewer/file_details/upload_icon_widget.dart @@ -65,7 +65,7 @@ class _UpdateIconWidgetState extends State { Widget build(BuildContext context) { if (SyncService.instance.isSyncInProgress()) { if (!widget.file.isUploaded) { - _logger.fine("sync in progress ${widget.file.displayName}"); + _logger.info("sync in progress ${widget.file.displayName}"); } return const SizedBox.shrink(); } diff --git a/mobile/lib/ui/viewer/gallery/component/gallery_file_widget.dart b/mobile/lib/ui/viewer/gallery/component/gallery_file_widget.dart index 178744c7d9..1462dbf8ae 100644 --- a/mobile/lib/ui/viewer/gallery/component/gallery_file_widget.dart +++ b/mobile/lib/ui/viewer/gallery/component/gallery_file_widget.dart @@ -6,7 +6,6 @@ import "package:photos/core/constants.dart"; import 'package:photos/models/file/file.dart'; import "package:photos/models/selected_files.dart"; import "package:photos/services/app_lifecycle_service.dart"; -import "package:photos/services/collections_service.dart"; import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/viewer/file/detail_page.dart"; import "package:photos/ui/viewer/file/thumbnail_widget.dart"; @@ -38,16 +37,9 @@ class GalleryFileWidget extends StatelessWidget { @override Widget build(BuildContext context) { final isFileSelected = selectedFiles?.isFileSelected(file) ?? false; - bool fileIsFromSharedPublicLink = false; - if (file.collectionID != null) { - fileIsFromSharedPublicLink = - CollectionsService.instance.isSharedPublicLink(file.collectionID!); - } + Color selectionColor = Colors.white; - if (isFileSelected && - file.isUploaded && - file.ownerID != currentUserID && - !fileIsFromSharedPublicLink) { + if (isFileSelected && file.isUploaded && file.ownerID != currentUserID) { final avatarColors = getEnteColorScheme(context).avatarColors; selectionColor = avatarColors[(file.ownerID!).remainder(avatarColors.length)]; @@ -62,7 +54,7 @@ class GalleryFileWidget extends StatelessWidget { thumbnailSize: photoGridSize < photoGridSizeDefault ? thumbnailLargeSize : thumbnailSmallSize, - shouldShowOwnerAvatar: !(isFileSelected || fileIsFromSharedPublicLink), + shouldShowOwnerAvatar: !isFileSelected, shouldShowVideoDuration: true, ); return GestureDetector( diff --git a/mobile/lib/ui/viewer/gallery/device_folder_page.dart b/mobile/lib/ui/viewer/gallery/device_folder_page.dart index 0eae4e1de1..b97e835945 100644 --- a/mobile/lib/ui/viewer/gallery/device_folder_page.dart +++ b/mobile/lib/ui/viewer/gallery/device_folder_page.dart @@ -129,7 +129,7 @@ class _BackupHeaderWidgetState extends State { trailingWidget: ToggleSwitchWidget( value: () => shouldBackup.value, onChanged: () async { - _logger.fine( + _logger.info( "Toggling device folder sync status to " "${!shouldBackup.value}", ); diff --git a/mobile/lib/ui/viewer/gallery/gallery.dart b/mobile/lib/ui/viewer/gallery/gallery.dart index 66da74f969..4cbba09f54 100644 --- a/mobile/lib/ui/viewer/gallery/gallery.dart +++ b/mobile/lib/ui/viewer/gallery/gallery.dart @@ -122,7 +122,7 @@ class GalleryState extends State { _logTag = "Gallery_${widget.tagPrefix}${kDebugMode ? "_" + widget.albumName! : ""}_x"; _logger = Logger(_logTag); - _logger.finest("init Gallery"); + _logger.info("init Gallery"); _debouncer = Debouncer( widget.reloadDebounceTime, executionInterval: widget.reloadDebounceExecutionInterval, @@ -149,11 +149,11 @@ class GalleryState extends State { _debouncer.run(() async { // In soft refresh, setState is called for entire gallery only when // number of child change - _logger.finest("Soft refresh all files on ${event.reason} "); + _logger.info("Soft refresh all files on ${event.reason} "); final result = await _loadFiles(); final bool hasTriggeredSetState = _onFilesLoaded(result.files); if (hasTriggeredSetState && kDebugMode) { - _logger.finest( + _logger.info( "Reloaded gallery on soft refresh all files on ${event.reason}", ); } @@ -179,7 +179,7 @@ class GalleryState extends State { _forceReloadEventSubscriptions.add( event.listen((event) async { _debouncer.run(() async { - _logger.finest("Force refresh all files on ${event.reason}"); + _logger.info("Force refresh all files on ${event.reason}"); _sortOrderAsc = widget.sortAsyncFn != null ? widget.sortAsyncFn!() : false; final result = await _loadFiles(); @@ -370,7 +370,7 @@ class GalleryState extends State { @override Widget build(BuildContext context) { - _logger.finest("Building Gallery ${widget.tagPrefix}"); + _logger.info("Building Gallery ${widget.tagPrefix}"); GalleryFilesState.of(context).setGalleryFiles = _allGalleryFiles; if (!_hasLoadedFiles) { return widget.loadingWidget; diff --git a/mobile/lib/ui/viewer/gallery/gallery_app_bar_widget.dart b/mobile/lib/ui/viewer/gallery/gallery_app_bar_widget.dart index 3d250ddd3d..38c02c08b9 100644 --- a/mobile/lib/ui/viewer/gallery/gallery_app_bar_widget.dart +++ b/mobile/lib/ui/viewer/gallery/gallery_app_bar_widget.dart @@ -851,10 +851,10 @@ class _GalleryAppBarWidgetState extends State { try { if (galleryType == GalleryType.sharedPublicCollection && collection!.isCollectEnabledForPublicLink()) { - final authToken = await CollectionsService.instance + final authToken = CollectionsService.instance .getSharedPublicAlbumToken(collection.id); - final albumKey = await CollectionsService.instance - .getSharedPublicAlbumKey(collection.id); + final albumKey = + CollectionsService.instance.getSharedPublicAlbumKey(collection.id); final res = await showChoiceDialog( context, diff --git a/mobile/lib/ui/viewer/gallery/hierarchical_search_gallery.dart b/mobile/lib/ui/viewer/gallery/hierarchical_search_gallery.dart index 69bcf8d03c..48621a0f73 100644 --- a/mobile/lib/ui/viewer/gallery/hierarchical_search_gallery.dart +++ b/mobile/lib/ui/viewer/gallery/hierarchical_search_gallery.dart @@ -20,7 +20,7 @@ import "package:photos/ui/viewer/gallery/state/search_filter_data_provider.dart" import "package:photos/ui/viewer/people/add_person_action_sheet.dart"; import "package:photos/ui/viewer/people/people_banner.dart"; import "package:photos/ui/viewer/people/people_page.dart"; -import "package:photos/ui/viewer/search/result/person_face_widget.dart"; +import "package:photos/ui/viewer/people/person_face_widget.dart"; import "package:photos/utils/hierarchical_search_util.dart"; import "package:photos/utils/navigation_util.dart"; @@ -171,11 +171,8 @@ class _HierarchicalSearchGalleryState extends State { ? PeopleBanner( type: PeopleBannerType.addName, faceWidget: PersonFaceWidget( - _firstUnnamedAppliedFaceFilter!.faceFile, clusterID: _firstUnnamedAppliedFaceFilter!.clusterId, - thumbnailFallback: false, - cannotTrustFile: true, ), actionIcon: Icons.add_outlined, text: S.of(context).savePerson, diff --git a/mobile/lib/ui/viewer/gallery/hooks/add_photos_sheet.dart b/mobile/lib/ui/viewer/gallery/hooks/add_photos_sheet.dart index f8f28adfd9..865c16378a 100644 --- a/mobile/lib/ui/viewer/gallery/hooks/add_photos_sheet.dart +++ b/mobile/lib/ui/viewer/gallery/hooks/add_photos_sheet.dart @@ -173,8 +173,11 @@ class AddPhotosPhotoWidget extends StatelessWidget { final List? result = await AssetPicker.pickAssets( context, pickerConfig: AssetPickerConfig( + keepScrollOffset: true, maxAssets: maxPickAssetLimit, textDelegate: assetPickerTextDelegate, + gridCount: 6, + pageSize: 120, ), ); if (result != null && result.isNotEmpty) { diff --git a/mobile/lib/ui/viewer/hierarchicial_search/applied_filters_for_appbar.dart b/mobile/lib/ui/viewer/hierarchicial_search/applied_filters_for_appbar.dart index bc41ed77af..869df13bca 100644 --- a/mobile/lib/ui/viewer/hierarchicial_search/applied_filters_for_appbar.dart +++ b/mobile/lib/ui/viewer/hierarchicial_search/applied_filters_for_appbar.dart @@ -66,7 +66,6 @@ class _AppliedFiltersForAppbarState extends State { ? FaceFilterChip( personId: filter.personId, clusterId: filter.clusterId, - faceThumbnailFile: filter.faceFile, apply: () { _searchFilterDataProvider.applyFilters([filter]); }, diff --git a/mobile/lib/ui/viewer/hierarchicial_search/chip_widgets/face_filter_chip.dart b/mobile/lib/ui/viewer/hierarchicial_search/chip_widgets/face_filter_chip.dart index 67d99be854..b7f36eaf2d 100644 --- a/mobile/lib/ui/viewer/hierarchicial_search/chip_widgets/face_filter_chip.dart +++ b/mobile/lib/ui/viewer/hierarchicial_search/chip_widgets/face_filter_chip.dart @@ -1,13 +1,11 @@ import "package:flutter/material.dart"; import "package:photos/core/constants.dart"; -import "package:photos/models/file/file.dart"; import "package:photos/theme/ente_theme.dart"; -import "package:photos/ui/viewer/search/result/person_face_widget.dart"; +import "package:photos/ui/viewer/people/person_face_widget.dart"; class FaceFilterChip extends StatefulWidget { final String? personId; final String? clusterId; - final EnteFile faceThumbnailFile; final VoidCallback apply; final VoidCallback remove; final bool isApplied; @@ -16,7 +14,6 @@ class FaceFilterChip extends StatefulWidget { const FaceFilterChip({ required this.personId, required this.clusterId, - required this.faceThumbnailFile, required this.apply, required this.remove, required this.isApplied, @@ -72,12 +69,9 @@ class _FaceFilterChipState extends State { width: kFilterChipHeight * scale, height: kFilterChipHeight * scale, child: PersonFaceWidget( - widget.faceThumbnailFile, personId: widget.personId, clusterID: widget.clusterId, - thumbnailFallback: false, useFullFile: false, - cannotTrustFile: true, ), ), ), diff --git a/mobile/lib/ui/viewer/hierarchicial_search/chip_widgets/only_them_filter_chip.dart b/mobile/lib/ui/viewer/hierarchicial_search/chip_widgets/only_them_filter_chip.dart index b3b00091d3..85c616602e 100644 --- a/mobile/lib/ui/viewer/hierarchicial_search/chip_widgets/only_them_filter_chip.dart +++ b/mobile/lib/ui/viewer/hierarchicial_search/chip_widgets/only_them_filter_chip.dart @@ -3,7 +3,7 @@ import "package:photos/core/constants.dart"; import "package:photos/generated/l10n.dart"; import "package:photos/models/search/hierarchical/face_filter.dart"; import "package:photos/theme/ente_theme.dart"; -import "package:photos/ui/viewer/search/result/person_face_widget.dart"; +import "package:photos/ui/viewer/people/person_face_widget.dart"; class OnlyThemFilterChip extends StatelessWidget { final List faceFilters; @@ -88,12 +88,9 @@ class _OnlyThemFilterThumbnail extends StatelessWidget { width: kFilterChipHeight, height: kFilterChipHeight, child: PersonFaceWidget( - faceFilters.first.faceFile, personId: faceFilters.first.personId, clusterID: faceFilters.first.clusterId, - thumbnailFallback: false, useFullFile: false, - cannotTrustFile: true, ), ), ); @@ -105,12 +102,9 @@ class _OnlyThemFilterThumbnail extends StatelessWidget { width: kFilterChipHeight / 2, height: kFilterChipHeight, child: PersonFaceWidget( - faceFilters.first.faceFile, personId: faceFilters.first.personId, clusterID: faceFilters.first.clusterId, - thumbnailFallback: false, useFullFile: false, - cannotTrustFile: true, ), ), const SizedBox(width: 1), @@ -118,12 +112,9 @@ class _OnlyThemFilterThumbnail extends StatelessWidget { width: kFilterChipHeight / 2, height: kFilterChipHeight, child: PersonFaceWidget( - faceFilters.last.faceFile, personId: faceFilters.last.personId, clusterID: faceFilters.last.clusterId, - thumbnailFallback: false, useFullFile: false, - cannotTrustFile: true, ), ), ], @@ -138,12 +129,9 @@ class _OnlyThemFilterThumbnail extends StatelessWidget { height: kFilterChipHeight, width: kFilterChipHeight / 2 - 0.5, child: PersonFaceWidget( - faceFilters[0].faceFile, personId: faceFilters[0].personId, clusterID: faceFilters[0].clusterId, - thumbnailFallback: false, useFullFile: false, - cannotTrustFile: true, ), ), const SizedBox(width: 1), @@ -158,12 +146,9 @@ class _OnlyThemFilterThumbnail extends StatelessWidget { bottomLeft: Radius.circular(1), ), child: PersonFaceWidget( - faceFilters[1].faceFile, personId: faceFilters[1].personId, clusterID: faceFilters[1].clusterId, - thumbnailFallback: false, useFullFile: false, - cannotTrustFile: true, ), ), ), @@ -176,12 +161,9 @@ class _OnlyThemFilterThumbnail extends StatelessWidget { topLeft: Radius.circular(1), ), child: PersonFaceWidget( - faceFilters[2].faceFile, personId: faceFilters[2].personId, clusterID: faceFilters[2].clusterId, - thumbnailFallback: false, useFullFile: false, - cannotTrustFile: true, ), ), ), @@ -206,12 +188,9 @@ class _OnlyThemFilterThumbnail extends StatelessWidget { bottomRight: Radius.circular(1), ), child: PersonFaceWidget( - faceFilters[0].faceFile, personId: faceFilters[0].personId, clusterID: faceFilters[0].clusterId, - thumbnailFallback: false, useFullFile: false, - cannotTrustFile: true, ), ), ), @@ -224,12 +203,9 @@ class _OnlyThemFilterThumbnail extends StatelessWidget { bottomLeft: Radius.circular(1), ), child: PersonFaceWidget( - faceFilters[1].faceFile, personId: faceFilters[1].personId, clusterID: faceFilters[1].clusterId, - thumbnailFallback: false, useFullFile: false, - cannotTrustFile: true, ), ), ), @@ -247,12 +223,9 @@ class _OnlyThemFilterThumbnail extends StatelessWidget { topRight: Radius.circular(1), ), child: PersonFaceWidget( - faceFilters[2].faceFile, personId: faceFilters[2].personId, clusterID: faceFilters[2].clusterId, - thumbnailFallback: false, useFullFile: false, - cannotTrustFile: true, ), ), ), @@ -265,12 +238,9 @@ class _OnlyThemFilterThumbnail extends StatelessWidget { topLeft: Radius.circular(1), ), child: PersonFaceWidget( - faceFilters[3].faceFile, personId: faceFilters[3].personId, clusterID: faceFilters[3].clusterId, - thumbnailFallback: false, useFullFile: false, - cannotTrustFile: true, ), ), ), diff --git a/mobile/lib/ui/viewer/hierarchicial_search/filter_options_bottom_sheet.dart b/mobile/lib/ui/viewer/hierarchicial_search/filter_options_bottom_sheet.dart index bd9c245ed9..8fae99a750 100644 --- a/mobile/lib/ui/viewer/hierarchicial_search/filter_options_bottom_sheet.dart +++ b/mobile/lib/ui/viewer/hierarchicial_search/filter_options_bottom_sheet.dart @@ -57,7 +57,6 @@ class _FilterOptionsBottomSheetState extends State { FaceFilterChip( personId: filter.personId, clusterId: filter.clusterId, - faceThumbnailFile: filter.faceFile, isInAllFiltersView: true, apply: () { widget.searchFilterDataProvider diff --git a/mobile/lib/ui/viewer/hierarchicial_search/recommended_filters_for_appbar.dart b/mobile/lib/ui/viewer/hierarchicial_search/recommended_filters_for_appbar.dart index 132f3a2b2b..2c98a5bd38 100644 --- a/mobile/lib/ui/viewer/hierarchicial_search/recommended_filters_for_appbar.dart +++ b/mobile/lib/ui/viewer/hierarchicial_search/recommended_filters_for_appbar.dart @@ -121,7 +121,6 @@ class _RecommendedFiltersForAppbarState ? FaceFilterChip( personId: filter.personId, clusterId: filter.clusterId, - faceThumbnailFile: filter.faceFile, apply: () { _searchFilterDataProvider.applyFilters([filter]); }, diff --git a/mobile/lib/ui/viewer/location/add_location_sheet.dart b/mobile/lib/ui/viewer/location/add_location_sheet.dart index ebcb53872f..e294e5ff6f 100644 --- a/mobile/lib/ui/viewer/location/add_location_sheet.dart +++ b/mobile/lib/ui/viewer/location/add_location_sheet.dart @@ -129,8 +129,7 @@ class _AddLocationSheetState extends State { children: [ Expanded( child: TextInputWidget( - hintText: S.of(context).locationName, - borderRadius: 2, + hintText: S.of(context).locationName, focusNode: _focusNode, submitNotifier: _submitNotifer, cancelNotifier: _cancelNotifier, diff --git a/mobile/lib/ui/viewer/location/edit_location_sheet.dart b/mobile/lib/ui/viewer/location/edit_location_sheet.dart index fa9e06cf3a..ef7eca1347 100644 --- a/mobile/lib/ui/viewer/location/edit_location_sheet.dart +++ b/mobile/lib/ui/viewer/location/edit_location_sheet.dart @@ -119,8 +119,7 @@ class _EditLocationSheetState extends State { children: [ Expanded( child: TextInputWidget( - hintText: S.of(context).locationName, - borderRadius: 2, + hintText: S.of(context).locationName, focusNode: _focusNode, submitNotifier: _submitNotifer, cancelNotifier: _cancelNotifier, diff --git a/mobile/lib/ui/viewer/people/cluster_breakup_page.dart b/mobile/lib/ui/viewer/people/cluster_breakup_page.dart index c1bec40466..73df061387 100644 --- a/mobile/lib/ui/viewer/people/cluster_breakup_page.dart +++ b/mobile/lib/ui/viewer/people/cluster_breakup_page.dart @@ -3,7 +3,7 @@ import "package:photos/models/file/file.dart"; import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/viewer/file/no_thumbnail_widget.dart"; import "package:photos/ui/viewer/people/cluster_page.dart"; -import "package:photos/ui/viewer/search/result/person_face_widget.dart"; +import "package:photos/ui/viewer/people/person_face_widget.dart"; class ClusterBreakupPage extends StatefulWidget { final Map> newClusterIDsToFiles; @@ -59,7 +59,6 @@ class _ClusterBreakupPageState extends State { Radius.elliptical(16, 12), ), child: PersonFaceWidget( - files.first, clusterID: clusterID, ), ) diff --git a/mobile/lib/ui/viewer/people/cluster_page.dart b/mobile/lib/ui/viewer/people/cluster_page.dart index 0a7bc4ff2b..5e8362d468 100644 --- a/mobile/lib/ui/viewer/people/cluster_page.dart +++ b/mobile/lib/ui/viewer/people/cluster_page.dart @@ -13,6 +13,7 @@ import 'package:photos/models/gallery_type.dart'; import "package:photos/models/ml/face/person.dart"; import 'package:photos/models/selected_files.dart'; import "package:photos/services/machine_learning/face_ml/feedback/cluster_feedback.dart"; +import "package:photos/services/machine_learning/ml_result.dart"; import "package:photos/ui/notification/toast.dart"; import 'package:photos/ui/viewer/actions/file_selection_overlay_bar.dart'; import 'package:photos/ui/viewer/gallery/gallery.dart'; @@ -22,7 +23,7 @@ import "package:photos/ui/viewer/people/add_person_action_sheet.dart"; import "package:photos/ui/viewer/people/cluster_app_bar.dart"; import "package:photos/ui/viewer/people/people_banner.dart"; import "package:photos/ui/viewer/people/people_page.dart"; -import "package:photos/ui/viewer/search/result/person_face_widget.dart"; +import "package:photos/ui/viewer/people/person_face_widget.dart"; import "package:photos/ui/viewer/search/result/search_result_page.dart"; import "package:photos/utils/navigation_util.dart"; @@ -76,12 +77,20 @@ class _ClusterPageState extends State { } }); _peopleChangedEvent = Bus.instance.on().listen((event) { - if (event.type == PeopleEventType.removedFilesFromCluster && - (event.source == widget.clusterID.toString())) { - for (var updatedFile in event.relevantFiles!) { - files.remove(updatedFile); + if (event.source == widget.clusterID.toString()) { + if (event.type == PeopleEventType.removedFilesFromCluster) { + for (var updatedFile in event.relevantFiles!) { + files.remove(updatedFile); + } + setState(() {}); + } + if (event.type == PeopleEventType.removedFaceFromCluster) { + for (final String removedFaceID in event.relevantFaceIDs!) { + final int fileID = getFileIdFromFaceId(removedFaceID); + files.removeWhere((file) => file.uploadedFileID == fileID); + } + setState(() {}); } - setState(() {}); } }); kDebugMode @@ -136,7 +145,6 @@ class _ClusterPageState extends State { ? PeopleBanner( type: PeopleBannerType.addName, faceWidget: PersonFaceWidget( - files.first, clusterID: widget.clusterID, ), actionIcon: Icons.add_outlined, diff --git a/mobile/lib/ui/viewer/people/file_face_widget.dart b/mobile/lib/ui/viewer/people/file_face_widget.dart new file mode 100644 index 0000000000..872630fcc0 --- /dev/null +++ b/mobile/lib/ui/viewer/people/file_face_widget.dart @@ -0,0 +1,132 @@ +import "dart:typed_data"; + +import 'package:flutter/widgets.dart'; +import "package:logging/logging.dart"; +import "package:photos/db/ml/db.dart"; +import 'package:photos/models/file/file.dart'; +import "package:photos/models/ml/face/face.dart"; +import "package:photos/theme/ente_theme.dart"; +import "package:photos/ui/common/loading_widget.dart"; +import "package:photos/ui/viewer/file/thumbnail_widget.dart"; +import "package:photos/utils/face/face_thumbnail_cache.dart"; + +final _logger = Logger("FaceWidget"); + +class FileFaceWidget extends StatefulWidget { + final EnteFile file; + + // Data to find the right face, in order of preference + final Uint8List? faceCrop; + final Face? face; + final String? clusterID; + + final bool useFullFile; + final bool thumbnailFallback; + + const FileFaceWidget( + this.file, { + this.face, + this.faceCrop, + this.clusterID, + this.useFullFile = true, + this.thumbnailFallback = false, + super.key, + }); + + @override + State createState() => _FileFaceWidgetState(); +} + +class _FileFaceWidgetState extends State { + Future? faceCropFuture; + + @override + void initState() { + super.initState(); + faceCropFuture = _getFaceCrop(); + } + + @override + void dispose() { + super.dispose(); + if (widget.faceCrop == null) { + checkStopTryingToGenerateFaceThumbnails( + widget.file.uploadedFileID!, + useFullFile: widget.useFullFile, + ); + } + } + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: faceCropFuture, + builder: (context, snapshot) { + if (snapshot.hasData) { + final ImageProvider imageProvider = MemoryImage(snapshot.data!); + return Stack( + fit: StackFit.expand, + children: [ + Image( + image: imageProvider, + fit: BoxFit.cover, + ), + ], + ); + } else { + if (snapshot.hasError) { + _logger.severe( + "Error getting cover face", + snapshot.error, + snapshot.stackTrace, + ); + } + return widget.thumbnailFallback + ? ThumbnailWidget(widget.file) + : EnteLoadingWidget( + color: getEnteColorScheme(context).fillMuted, + ); + } + }, + ); + } + + Future _getFaceCrop() async { + if (widget.faceCrop != null) { + return widget.faceCrop; + } + try { + final Face? faceToUse = widget.face ?? + await MLDataDB.instance.getCoverFaceForPerson( + recentFileID: widget.file.uploadedFileID!, + clusterID: widget.clusterID, + ); + if (faceToUse == null) { + _logger.severe( + "Cannot find face to crop, widget.face: ${widget.face}, clusterID: ${widget.clusterID}", + ); + } + final cropMap = await getCachedFaceCrops( + widget.file, + [faceToUse!], + useFullFile: widget.useFullFile, + useTempCache: true, + ); + if (cropMap != null && cropMap[faceToUse.faceID] != null) { + return cropMap[faceToUse.faceID]; + } else { + _logger.severe( + "No face crop found for face ${faceToUse.faceID} in file ${widget.file.uploadedFileID}", + ); + return null; + } + } catch (e, s) { + _logger.severe( + "Failed to get face crop for file ${widget.file.uploadedFileID}", + e, + s, + ); + return null; + } + } +} diff --git a/mobile/lib/ui/viewer/people/link_email_screen.dart b/mobile/lib/ui/viewer/people/link_email_screen.dart index 37aa85882a..f4effaa7e6 100644 --- a/mobile/lib/ui/viewer/people/link_email_screen.dart +++ b/mobile/lib/ui/viewer/people/link_email_screen.dart @@ -318,7 +318,8 @@ class _LinkEmailScreen extends State { BuildContext context, ) async { if (await checkIfEmailAlreadyAssignedToAPerson(email)) { - throw Exception("Email already linked to a person"); + await showAlreadyLinkedEmailDialog(context, email); + return false; } String? publicKey; diff --git a/mobile/lib/ui/viewer/people/people_app_bar.dart b/mobile/lib/ui/viewer/people/people_app_bar.dart index 45d1cc108d..7f733b02ad 100644 --- a/mobile/lib/ui/viewer/people/people_app_bar.dart +++ b/mobile/lib/ui/viewer/people/people_app_bar.dart @@ -17,6 +17,7 @@ import 'package:photos/services/collections_service.dart'; import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; import "package:photos/theme/ente_theme.dart"; import 'package:photos/ui/actions/collection/collection_sharing_actions.dart'; +import "package:photos/ui/viewer/gallery/hooks/pick_person_avatar.dart"; import "package:photos/ui/viewer/gallery/state/inherited_search_filter_data.dart"; import "package:photos/ui/viewer/hierarchicial_search/applied_filters_for_appbar.dart"; import "package:photos/ui/viewer/hierarchicial_search/recommended_filters_for_appbar.dart"; @@ -249,6 +250,38 @@ class _AppBarWidgetState extends State { ], ), ), + PopupMenuItem( + value: PeoplePopupAction.setCover, + child: Row( + children: [ + const Icon(Icons.image_outlined), + const Padding( + padding: EdgeInsets.all(8), + ), + Text( + S.of(context).setCover, + style: textTheme.bodyBold, + ), + ], + ), + ), + if (widget.person.data.email != null && + (widget.person.data.email == Configuration.instance.getEmail())) + PopupMenuItem( + value: PeoplePopupAction.reassignMe, + child: Row( + children: [ + const Icon(Icons.person_2_outlined), + const Padding( + padding: EdgeInsets.all(8), + ), + Text( + context.l10n.reassignMe, + style: textTheme.bodyBold, + ), + ], + ), + ), PopupMenuItem( value: PeoplePopupAction.removeLabel, child: Row( @@ -264,23 +297,6 @@ class _AppBarWidgetState extends State { ], ), ), - if (widget.person.data.email != null && - (widget.person.data.email == Configuration.instance.getEmail())) - PopupMenuItem( - value: PeoplePopupAction.reassignMe, - child: Row( - children: [ - const Icon(Icons.delete_outline), - const Padding( - padding: EdgeInsets.all(8), - ), - Text( - context.l10n.reassignMe, - style: textTheme.bodyBold, - ), - ], - ), - ), ], ); } else { @@ -394,13 +410,25 @@ class _AppBarWidgetState extends State { } Future setCoverPhoto(BuildContext context) async { - // final int? coverPhotoID = await showPickCoverPhotoSheet( - // context, - // widget.collection!, - // ); - // if (coverPhotoID != null) { - // unawaited(changeCoverPhoto(context, widget.collection!, coverPhotoID)); - // } + final result = await showPersonAvatarPhotoSheet( + context, + person, + ); + if (result != null) { + _logger.info( + 'Person avatar updated', + ); + setState(() { + person = result; + }); + Bus.instance.fire( + PeopleChangedEvent( + type: PeopleEventType.saveOrEditPerson, + source: "_PeopleAppBarState.setCoverPhoto", + person: result, + ), + ); + } } Future _reassignMe(BuildContext context) async { diff --git a/mobile/lib/ui/viewer/people/people_banner.dart b/mobile/lib/ui/viewer/people/people_banner.dart index 8380853739..5bcffdf837 100644 --- a/mobile/lib/ui/viewer/people/people_banner.dart +++ b/mobile/lib/ui/viewer/people/people_banner.dart @@ -1,7 +1,7 @@ import "package:flutter/material.dart"; import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/components/buttons/icon_button_widget.dart"; -import "package:photos/ui/viewer/search/result/person_face_widget.dart"; +import "package:photos/ui/viewer/people/person_face_widget.dart"; enum PeopleBannerType { addName, diff --git a/mobile/lib/ui/viewer/people/people_page.dart b/mobile/lib/ui/viewer/people/people_page.dart index 4878f384a9..fbb529bd5c 100644 --- a/mobile/lib/ui/viewer/people/people_page.dart +++ b/mobile/lib/ui/viewer/people/people_page.dart @@ -13,7 +13,6 @@ import 'package:photos/models/gallery_type.dart'; import "package:photos/models/ml/face/person.dart"; import "package:photos/models/search/search_result.dart"; import 'package:photos/models/selected_files.dart'; -import "package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart"; import "package:photos/services/machine_learning/face_ml/feedback/cluster_feedback.dart"; import "package:photos/services/search_service.dart"; import "package:photos/ui/components/end_to_end_banner.dart"; @@ -27,8 +26,7 @@ import "package:photos/ui/viewer/gallery/state/selection_state.dart"; import "package:photos/ui/viewer/people/link_email_screen.dart"; import "package:photos/ui/viewer/people/people_app_bar.dart"; -import "package:photos/ui/viewer/people/people_banner.dart"; -import "package:photos/ui/viewer/people/person_cluster_suggestion.dart"; +import "package:photos/ui/viewer/people/person_gallery_suggestion.dart"; import "package:photos/utils/navigation_util.dart"; class PeoplePage extends StatefulWidget { @@ -54,20 +52,14 @@ class _PeoplePageState extends State { final Logger _logger = Logger("_PeoplePageState"); final _selectedFiles = SelectedFiles(); List? files; - int? smallestClusterSize; Future> filesFuture = Future.value([]); late PersonEntity _person; - bool get showSuggestionBanner => (!userDismissedSuggestionBanner && - smallestClusterSize != null && - smallestClusterSize! >= kMinimumClusterSizeSearchResult && - files != null && - files!.isNotEmpty); - - bool userDismissedSuggestionBanner = false; + bool userDismissedPersonGallerySuggestion = false; late final StreamSubscription _filesUpdatedEvent; late final StreamSubscription _peopleChangedEvent; + late SearchFilterDataProvider? _searchFilterDataProvider; @override void initState() { @@ -75,14 +67,14 @@ class _PeoplePageState extends State { _person = widget.person; ClusterFeedbackService.resetLastViewedClusterID(); _peopleChangedEvent = Bus.instance.on().listen((event) { - setState(() { - if (event.type == PeopleEventType.saveOrEditPerson) { - if (event.person != null && - event.person!.remoteID == _person.remoteID) { + if (event.type == PeopleEventType.saveOrEditPerson) { + if (event.person != null && + event.person!.remoteID == _person.remoteID) { + setState(() { _person = event.person!; - } + }); } - }); + } }); filesFuture = loadPersonFiles(); @@ -99,6 +91,12 @@ class _PeoplePageState extends State { setState(() {}); } }); + _searchFilterDataProvider = widget.searchResult != null + ? SearchFilterDataProvider( + initialGalleryFilter: + widget.searchResult!.getHierarchicalSearchFilter(), + ) + : null; } Future> loadPersonFiles() async { @@ -110,10 +108,6 @@ class _PeoplePageState extends State { ); return []; } - smallestClusterSize = result.values.fold(result.values.first.length, - (previousValue, element) { - return element.length < previousValue ? element.length : previousValue; - }); final List resultFiles = []; for (final e in result.entries) { resultFiles.addAll(e.value); @@ -136,12 +130,7 @@ class _PeoplePageState extends State { _logger.info("Building for ${_person.data.name}"); return GalleryFilesState( child: InheritedSearchFilterDataWrapper( - searchFilterDataProvider: widget.searchResult != null - ? SearchFilterDataProvider( - initialGalleryFilter: - widget.searchResult!.getHierarchicalSearchFilter(), - ) - : null, + searchFilterDataProvider: _searchFilterDataProvider, child: Scaffold( appBar: PreferredSize( preferredSize: @@ -161,85 +150,49 @@ class _PeoplePageState extends State { ); if (snapshot.hasData) { final personFiles = snapshot.data as List; - return Column( - children: [ - Expanded( - child: SelectionState( - selectedFiles: _selectedFiles, - child: Stack( - alignment: Alignment.bottomCenter, - children: [ - inheritedSearchFilterData.isHierarchicalSearchable - ? ValueListenableBuilder( - valueListenable: inheritedSearchFilterData - .searchFilterDataProvider! - .isSearchingNotifier, - builder: ( - context, - value, - _, - ) { - return value - ? HierarchicalSearchGallery( - tagPrefix: widget.tagPrefix, - selectedFiles: _selectedFiles, - ) - : _Gallery( - tagPrefix: widget.tagPrefix, - selectedFiles: _selectedFiles, - personFiles: personFiles, - loadPersonFiles: loadPersonFiles, - personEntity: _person, - ); - }, - ) - : _Gallery( - tagPrefix: widget.tagPrefix, - selectedFiles: _selectedFiles, - personFiles: personFiles, - loadPersonFiles: loadPersonFiles, - personEntity: _person, - ), - FileSelectionOverlayBar( - PeoplePage.overlayType, - _selectedFiles, - person: _person, - ), - ], - ), - ), - ), - showSuggestionBanner - ? Dismissible( - key: const Key("suggestionBanner"), - direction: DismissDirection.horizontal, - onDismissed: (direction) { - setState(() { - userDismissedSuggestionBanner = true; - }); - }, - child: PeopleBanner( - type: PeopleBannerType.suggestion, - startIcon: Icons.face_retouching_natural, - actionIcon: Icons.search_outlined, - text: "Review suggestions", - subText: "Improve the results", - onTap: () async { - unawaited( - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => - PersonReviewClusterSuggestion( - _person, - ), - ), - ), - ); + return SelectionState( + selectedFiles: _selectedFiles, + child: Stack( + alignment: Alignment.bottomCenter, + children: [ + inheritedSearchFilterData.isHierarchicalSearchable + ? ValueListenableBuilder( + valueListenable: inheritedSearchFilterData + .searchFilterDataProvider! + .isSearchingNotifier, + builder: ( + context, + value, + _, + ) { + return value + ? HierarchicalSearchGallery( + tagPrefix: widget.tagPrefix, + selectedFiles: _selectedFiles, + ) + : _Gallery( + tagPrefix: widget.tagPrefix, + selectedFiles: _selectedFiles, + personFiles: personFiles, + loadPersonFiles: loadPersonFiles, + personEntity: _person, + ); }, + ) + : _Gallery( + tagPrefix: widget.tagPrefix, + selectedFiles: _selectedFiles, + personFiles: personFiles, + loadPersonFiles: loadPersonFiles, + personEntity: _person, ), - ) - : const SizedBox.shrink(), - ], + FileSelectionOverlayBar( + PeoplePage.overlayType, + _selectedFiles, + person: _person, + ), + ], + ), ); } else if (snapshot.hasError) { _logger @@ -259,7 +212,7 @@ class _PeoplePageState extends State { } } -class _Gallery extends StatelessWidget { +class _Gallery extends StatefulWidget { final String tagPrefix; final SelectedFiles selectedFiles; final List personFiles; @@ -274,6 +227,13 @@ class _Gallery extends StatelessWidget { required this.personEntity, }); + @override + State<_Gallery> createState() => _GalleryState(); +} + +class _GalleryState extends State<_Gallery> { + bool userDismissedPersonGallerySuggestion = false; + @override Widget build(BuildContext context) { return Gallery( @@ -283,7 +243,7 @@ class _Gallery extends StatelessWidget { limit, asc, }) async { - final result = await loadPersonFiles(); + final result = await widget.loadPersonFiles(); return Future.value( FileLoadResult( result, @@ -292,19 +252,20 @@ class _Gallery extends StatelessWidget { ); }, reloadEvent: Bus.instance.on(), - forceReloadEvents: [ - Bus.instance.on(), - ], + forceReloadEvents: [Bus.instance.on()], removalEventTypes: const { EventType.deletedFromRemote, EventType.deletedFromEverywhere, EventType.hide, }, - tagPrefix: tagPrefix + tagPrefix, - selectedFiles: selectedFiles, - initialFiles: personFiles.isNotEmpty ? [personFiles.first] : [], - header: - personEntity.data.email != null && personEntity.data.email!.isNotEmpty + tagPrefix: widget.tagPrefix + widget.tagPrefix, + selectedFiles: widget.selectedFiles, + initialFiles: + widget.personFiles.isNotEmpty ? [widget.personFiles.first] : [], + header: Column( + children: [ + widget.personEntity.data.email != null && + widget.personEntity.data.email!.isNotEmpty ? const SizedBox.shrink() : Padding( padding: const EdgeInsets.only(top: 12, bottom: 8), @@ -315,11 +276,32 @@ class _Gallery extends StatelessWidget { onTap: () async { await routeToPage( context, - LinkEmailScreen(personEntity.remoteID), + LinkEmailScreen(widget.personEntity.remoteID), ); }, ), ), + !userDismissedPersonGallerySuggestion + ? Dismissible( + key: const Key("personGallerySuggestion"), + direction: DismissDirection.horizontal, + onDismissed: (direction) { + setState(() { + userDismissedPersonGallerySuggestion = true; + }); + }, + child: PersonGallerySuggestion( + person: widget.personEntity, + onClose: () { + setState(() { + userDismissedPersonGallerySuggestion = true; + }); + }, + ), + ) + : const SizedBox.shrink(), + ], + ), ); } } diff --git a/mobile/lib/ui/viewer/people/person_cluster_suggestion.dart b/mobile/lib/ui/viewer/people/person_cluster_suggestion.dart index 54cfd893d7..44f3e89aa7 100644 --- a/mobile/lib/ui/viewer/people/person_cluster_suggestion.dart +++ b/mobile/lib/ui/viewer/people/person_cluster_suggestion.dart @@ -14,13 +14,15 @@ import "package:photos/models/file/file.dart"; import "package:photos/models/ml/face/person.dart"; import 'package:photos/services/machine_learning/face_ml/feedback/cluster_feedback.dart'; import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; +import "package:photos/services/machine_learning/ml_result.dart"; import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/components/buttons/button_widget.dart"; import "package:photos/ui/components/models/button_type.dart"; import "package:photos/ui/viewer/people/cluster_page.dart"; +import "package:photos/ui/viewer/people/file_face_widget.dart"; import "package:photos/ui/viewer/people/person_clusters_page.dart"; -import "package:photos/ui/viewer/search/result/person_face_widget.dart"; -import "package:photos/utils/face/face_box_crop.dart"; +import "package:photos/ui/viewer/people/save_or_edit_person.dart"; +import "package:photos/utils/face/face_thumbnail_cache.dart"; class SuggestionUserFeedback { final bool accepted; @@ -123,12 +125,20 @@ class _PersonClustersState extends State { _peopleChangedEvent = Bus.instance.on().listen((event) { - if (event.type == PeopleEventType.removedFilesFromCluster && - (event.source == clusterID.toString())) { - for (var updatedFile in event.relevantFiles!) { - files.remove(updatedFile); + if (event.source == clusterID.toString()) { + if (event.type == PeopleEventType.removedFilesFromCluster) { + for (var updatedFile in event.relevantFiles!) { + files.remove(updatedFile); + } + setState(() {}); + } + if (event.type == PeopleEventType.removedFaceFromCluster) { + for (final String removedFaceID in event.relevantFaceIDs!) { + final int fileID = getFileIdFromFaceId(removedFaceID); + files.removeWhere((file) => file.uploadedFileID == fileID); + } + setState(() {}); } - setState(() {}); } }); @@ -181,36 +191,61 @@ class _PersonClustersState extends State { right: 12.0, bottom: 48, ), - child: Row( - children: [ - Expanded( - child: ButtonWidget( - buttonType: ButtonType.tertiaryCritical, - icon: Icons.close, - labelText: context.l10n.no, - buttonSize: ButtonSize.large, - onTap: () async => { - await _handleUserClusterChoice( - clusterID, - false, - numberOfDifferentSuggestions, + child: Column( + children: [ + Row( + children: [ + Expanded( + child: ButtonWidget( + buttonType: ButtonType.tertiaryCritical, + icon: Icons.close, + labelText: context.l10n.no, + buttonSize: ButtonSize.large, + onTap: () async => { + await _handleUserClusterChoice( + clusterID, + false, + numberOfDifferentSuggestions, + ), + }, ), - }, - ), + ), + const SizedBox(width: 12.0), + Expanded( + child: ButtonWidget( + buttonType: ButtonType.primary, + labelText: context.l10n.yes, + buttonSize: ButtonSize.large, + onTap: () async => { + await _handleUserClusterChoice( + clusterID, + true, + numberOfDifferentSuggestions, + ), + }, + ), + ), + ], ), - const SizedBox(width: 12.0), - Expanded( - child: ButtonWidget( - buttonType: ButtonType.primary, - labelText: context.l10n.yes, - buttonSize: ButtonSize.large, - onTap: () async => { - await _handleUserClusterChoice( - clusterID, - true, - numberOfDifferentSuggestions, - ), - }, + const SizedBox(height: 4), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: canGiveFeedback + ? () => _saveAsAnotherPerson() + : null, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 12, + horizontal: 32, + ), + child: Text( + S.of(context).saveAsAnotherPerson, + style: getEnteTextTheme(context).mini.copyWith( + color: + getEnteColorScheme(context).textMuted, + decoration: TextDecoration.underline, + ), + ), ), ), ], @@ -298,6 +333,50 @@ class _PersonClustersState extends State { }); } + Future _saveAsAnotherPerson() async { + if (!canGiveFeedback || + allSuggestions.isEmpty || + currentSuggestionIndex >= allSuggestions.length) { + return; + } + + try { + final currentSuggestion = allSuggestions[currentSuggestionIndex]; + final clusterID = currentSuggestion.clusterIDToMerge; + final someFile = currentSuggestion.filesInCluster.first; + + final result = await Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => SaveOrEditPerson( + clusterID, + file: someFile, + isEditing: false, + ), + ), + ); + if (result == null || result == false) { + return; + } + if (mounted) { + setState(() => currentSuggestionIndex++); + } + final numberOfSuggestions = allSuggestions.length; + if (currentSuggestionIndex >= numberOfSuggestions) { + setState(() { + currentSuggestionIndex = 0; + futureBuilderKeySuggestions = UniqueKey(); + futureBuilderKeyFaceThumbnails = UniqueKey(); + _fetchClusterSuggestions(); + }); + } else { + futureBuilderKeyFaceThumbnails = UniqueKey(); + setState(() {}); + } + } catch (e, s) { + _logger.severe("Error saving as another person", e, s); + } + } + // Method to fetch cluster suggestions void _fetchClusterSuggestions() { debugPrint("Fetching suggestions for ${widget.person.data.name}"); @@ -408,11 +487,9 @@ class _PersonClustersState extends State { borderRadius: BorderRadius.circular(75), ), ), - child: PersonFaceWidget( + child: FileFaceWidget( files[start + index], clusterID: cluserId, - useFullFile: true, - thumbnailFallback: false, faceCrop: faceThumbnails[files[start + index].uploadedFileID!], ), diff --git a/mobile/lib/ui/viewer/people/person_clusters_page.dart b/mobile/lib/ui/viewer/people/person_clusters_page.dart index 3c083b2d4b..63b0715303 100644 --- a/mobile/lib/ui/viewer/people/person_clusters_page.dart +++ b/mobile/lib/ui/viewer/people/person_clusters_page.dart @@ -14,7 +14,7 @@ import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/common/loading_widget.dart"; import "package:photos/ui/viewer/file/no_thumbnail_widget.dart"; import "package:photos/ui/viewer/people/cluster_page.dart"; -import "package:photos/ui/viewer/search/result/person_face_widget.dart"; +import "package:photos/ui/viewer/people/person_face_widget.dart"; import "package:visibility_detector/visibility_detector.dart"; class PersonClustersPage extends StatefulWidget { @@ -81,7 +81,6 @@ class _PersonClustersPageState extends State { ), child: files.isNotEmpty ? PersonFaceWidget( - files.first, clusterID: clusterID, ) : const NoThumbnailWidget( @@ -283,7 +282,6 @@ class __ClusterWrapperForGirdState extends State<_ClusterWrapperForGird> { ), child: widget.files.isNotEmpty ? PersonFaceWidget( - widget.files.first, clusterID: widget.clusterID, ) : const NoThumbnailWidget( diff --git a/mobile/lib/ui/viewer/people/person_face_widget.dart b/mobile/lib/ui/viewer/people/person_face_widget.dart new file mode 100644 index 0000000000..8bd069f57e --- /dev/null +++ b/mobile/lib/ui/viewer/people/person_face_widget.dart @@ -0,0 +1,202 @@ +import "dart:typed_data"; + +import 'package:flutter/widgets.dart'; +import "package:logging/logging.dart"; +import "package:photos/db/files_db.dart"; +import "package:photos/db/ml/db.dart"; +import 'package:photos/models/file/file.dart'; +import "package:photos/models/ml/face/face.dart"; +import "package:photos/models/ml/face/person.dart"; +import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; +import "package:photos/services/machine_learning/ml_result.dart"; +import "package:photos/services/search_service.dart"; +import "package:photos/theme/ente_theme.dart"; +import "package:photos/ui/common/loading_widget.dart"; +import "package:photos/utils/face/face_thumbnail_cache.dart"; + +final _logger = Logger("PersonFaceWidget"); + +class PersonFaceWidget extends StatefulWidget { + final String? personId; + final String? clusterID; + final bool useFullFile; + final VoidCallback? onErrorCallback; + + // PersonFaceWidget constructor checks that both personId and clusterID are not null + // and that the file is not null + const PersonFaceWidget({ + this.personId, + this.clusterID, + this.useFullFile = true, + this.onErrorCallback, + super.key, + }) : assert( + personId != null || clusterID != null, + "PersonFaceWidget requires either personId or clusterID to be non-null", + ); + + @override + State createState() => _PersonFaceWidgetState(); +} + +class _PersonFaceWidgetState extends State { + Future? faceCropFuture; + EnteFile? fileForFaceCrop; + + bool get isPerson => widget.personId != null; + + @override + void initState() { + super.initState(); + faceCropFuture = _getFaceCrop(); + } + + @override + void dispose() { + super.dispose(); + if (fileForFaceCrop != null) { + checkStopTryingToGenerateFaceThumbnails( + fileForFaceCrop!.uploadedFileID!, + useFullFile: widget.useFullFile, + ); + } + } + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: faceCropFuture, + builder: (context, snapshot) { + if (snapshot.hasData) { + final ImageProvider imageProvider = MemoryImage(snapshot.data!); + return Stack( + fit: StackFit.expand, + children: [ + Image( + image: imageProvider, + fit: BoxFit.cover, + ), + ], + ); + } else { + if (snapshot.hasError) { + _logger.severe( + "Error getting cover face for person", + snapshot.error, + snapshot.stackTrace, + ); + } + return EnteLoadingWidget( + color: getEnteColorScheme(context).fillMuted, + ); + } + }, + ); + } + + Future _getFaceCrop() async { + try { + final String personOrClusterId = widget.personId ?? widget.clusterID!; + final tryInMemoryCachedCrop = + checkInMemoryCachedCropForPersonOrClusterID(personOrClusterId); + if (tryInMemoryCachedCrop != null) return tryInMemoryCachedCrop; + String? fixedFaceID; + PersonEntity? personEntity; + if (isPerson) { + personEntity = await PersonService.instance.getPerson(widget.personId!); + if (personEntity == null) { + _logger.severe( + "Person with ID ${widget.personId} not found, cannot get cover face.", + ); + return null; + } + fixedFaceID = personEntity.data.avatarFaceID; + } + fixedFaceID ??= + await checkUsedFaceIDForPersonOrClusterId(personOrClusterId); + final hiddenFileIDs = await SearchService.instance + .getHiddenFiles() + .then((onValue) => onValue.map((e) => e.uploadedFileID)); + EnteFile? fileForFaceCrop; + if (fixedFaceID != null) { + final fileID = getFileIdFromFaceId(fixedFaceID); + final fileInDB = await FilesDB.instance.getAnyUploadedFile(fileID); + if (fileInDB == null) { + _logger.severe( + "File with ID $fileID not found in DB, cannot get cover face.", + ); + await checkRemoveCachedFaceIDForPersonOrClusterId( + personOrClusterId, + ); + } else if (hiddenFileIDs.contains(fileInDB.uploadedFileID)) { + _logger.info( + "File with ID $fileID is hidden, skipping it for face crop.", + ); + await checkRemoveCachedFaceIDForPersonOrClusterId( + personOrClusterId, + ); + } else { + fileForFaceCrop = fileInDB; + } + } + if (fileForFaceCrop == null) { + final List allFaces = isPerson + ? await MLDataDB.instance + .getFaceIDsForPersonOrderedByScore(widget.personId!) + : await MLDataDB.instance + .getFaceIDsForClusterOrderedByScore(widget.clusterID!); + for (final faceID in allFaces) { + final fileID = getFileIdFromFaceId(faceID); + if (hiddenFileIDs.contains(fileID)) { + _logger.info( + "File with ID $fileID is hidden, skipping it for face crop.", + ); + continue; + } + fileForFaceCrop = await FilesDB.instance.getAnyUploadedFile(fileID); + if (fileForFaceCrop != null) { + _logger.info( + "Using file ID $fileID for face crop for person: ${widget.personId} or cluster: ${widget.clusterID}", + ); + fixedFaceID = faceID; + break; + } + } + if (fileForFaceCrop == null) { + _logger.warning( + "No suitable file found for face crop for person: ${widget.personId} or cluster: ${widget.clusterID}", + ); + return null; + } + } + final Face? face = await MLDataDB.instance.getCoverFaceForPerson( + recentFileID: fileForFaceCrop.uploadedFileID!, + avatarFaceId: fixedFaceID, + personID: widget.personId, + clusterID: widget.clusterID, + ); + if (face == null) { + debugPrint( + "No cover face for person: ${widget.personId} or cluster ${widget.clusterID} and fileID ${fileForFaceCrop.uploadedFileID!}", + ); + return null; + } + final cropMap = await getCachedFaceCrops( + fileForFaceCrop, + [face], + useFullFile: widget.useFullFile, + personOrClusterID: personOrClusterId, + useTempCache: false, + ); + return cropMap?[face.faceID]; + } catch (e, s) { + _logger.severe( + "Error getting cover face for person: ${widget.personId} or cluster ${widget.clusterID}", + e, + s, + ); + widget.onErrorCallback?.call(); + return null; + } + } +} diff --git a/mobile/lib/ui/viewer/people/person_gallery_suggestion.dart b/mobile/lib/ui/viewer/people/person_gallery_suggestion.dart new file mode 100644 index 0000000000..910dd70d26 --- /dev/null +++ b/mobile/lib/ui/viewer/people/person_gallery_suggestion.dart @@ -0,0 +1,670 @@ +import "dart:async"; +import "dart:typed_data"; + +import 'package:flutter/material.dart'; +import "package:logging/logging.dart"; +import "package:photos/db/ml/db.dart"; +import "package:photos/generated/l10n.dart"; +import "package:photos/models/file/file.dart"; +import "package:photos/models/ml/face/person.dart"; +import "package:photos/services/machine_learning/face_ml/feedback/cluster_feedback.dart"; +import "package:photos/theme/colors.dart"; +import "package:photos/theme/ente_theme.dart"; +import "package:photos/ui/viewer/people/cluster_page.dart"; +import "package:photos/ui/viewer/people/file_face_widget.dart"; +import "package:photos/ui/viewer/people/person_face_widget.dart"; +import "package:photos/ui/viewer/people/save_or_edit_person.dart"; +import "package:photos/utils/face/face_thumbnail_cache.dart"; + +final _logger = Logger("PersonGallerySuggestion"); + +class PersonGallerySuggestion extends StatefulWidget { + final PersonEntity? person; + final VoidCallback? onClose; + + const PersonGallerySuggestion({ + required this.person, + this.onClose, + super.key, + }); + + @override + State createState() => + _PersonGallerySuggestionState(); +} + +class _PersonGallerySuggestionState extends State + with TickerProviderStateMixin { + List allSuggestions = []; + int currentSuggestionIndex = 0; + Map faceCrops = {}; + bool isLoading = true; + bool isProcessing = false; + bool isPreparingNext = false; + bool hasCurrentSuggestion = false; + Map> precomputedFaceCrops = {}; + + PersonEntity? person; + bool get personPage => widget.person != null; + PersonEntity get relevantPerson => widget.person ?? person!; + + late AnimationController _slideController; + late AnimationController _fadeController; + late Animation _slideAnimation; + late Animation _fadeAnimation; + + @override + void initState() { + super.initState(); + person = widget.person; + _initializeAnimations(); + _loadInitialSuggestion(); + } + + void _initializeAnimations() { + _slideController = AnimationController( + duration: const Duration(milliseconds: 300), + vsync: this, + ); + _fadeController = AnimationController( + duration: const Duration(milliseconds: 200), + vsync: this, + ); + + _slideAnimation = Tween( + begin: const Offset(0, -1.0), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: _slideController, + curve: Curves.easeOutCubic, + ), + ); + + _fadeAnimation = Tween( + begin: 0.0, + end: 1.0, + ).animate( + CurvedAnimation( + parent: _fadeController, + curve: Curves.easeInOut, + ), + ); + } + + Future _loadInitialSuggestion() async { + try { + late final List suggestions; + if (personPage) { + suggestions = await ClusterFeedbackService.instance + .getSuggestionForPerson(relevantPerson); + } else { + suggestions = await ClusterFeedbackService.instance + .getAllLargePersonSuggestions(); + person = suggestions.first.person; + } + + if (suggestions.isNotEmpty && mounted) { + allSuggestions = suggestions; + currentSuggestionIndex = 0; + + final crops = await _generateFaceThumbnails( + allSuggestions[0].filesInCluster.take(personPage ? 4 : 3).toList(), + allSuggestions[0].clusterIDToMerge, + ); + + if (mounted) { + setState(() { + faceCrops = crops; + isLoading = false; + hasCurrentSuggestion = true; + }); + } + + unawaited(_fadeController.forward()); + unawaited(_slideController.forward()); + + unawaited(_precomputeNextSuggestions()); + } else { + _logger.info("No suggestions found"); + if (mounted) { + setState(() { + isLoading = false; + }); + } + } + } catch (e, s) { + _logger.severe("Error loading suggestion", e, s); + if (mounted) { + setState(() { + isLoading = false; + }); + } + } + } + + Future _precomputeNextSuggestions() async { + try { + // Precompute face crops for next two suggestions + const maxPrecompute = 2; + final endIndex = (currentSuggestionIndex + maxPrecompute) + .clamp(0, allSuggestions.length); + + for (int i = currentSuggestionIndex + 1; i < endIndex; i++) { + if (!mounted) break; + + final suggestion = allSuggestions[i]; + final crops = await _generateFaceThumbnails( + suggestion.filesInCluster.take(personPage ? 4 : 3).toList(), + suggestion.clusterIDToMerge, + ); + + if (mounted) { + precomputedFaceCrops[i] = crops; + } + } + } catch (e, s) { + _logger.severe("Error precomputing next suggestions", e, s); + } + } + + Future> _generateFaceThumbnails( + List files, + String clusterID, + ) async { + final futures = >[]; + for (final file in files) { + futures.add( + precomputeClusterFaceCrop( + file, + clusterID, + useFullFile: true, + ), + ); + } + final faceCropsList = await Future.wait(futures); + final faceCrops = {}; + for (var i = 0; i < faceCropsList.length; i++) { + faceCrops[files[i].uploadedFileID!] = faceCropsList[i]; + } + return faceCrops; + } + + void _navigateToCluster() { + if (allSuggestions.isEmpty || + currentSuggestionIndex >= allSuggestions.length) { + return; + } + + final currentSuggestion = allSuggestions[currentSuggestionIndex]; + final List sortedFiles = List.from( + currentSuggestion.filesInCluster, + ); + sortedFiles.sort( + (a, b) => b.creationTime!.compareTo(a.creationTime!), + ); + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => ClusterPage( + sortedFiles, + personID: relevantPerson, + clusterID: currentSuggestion.clusterIDToMerge, + showNamingBanner: false, + ), + ), + ); + } + + Future _handleUserChoice(bool accepted) async { + if (isProcessing || + allSuggestions.isEmpty || + currentSuggestionIndex >= allSuggestions.length) { + return; + } + + setState(() { + isProcessing = true; + }); + unawaited(_animateOut()); + + try { + final currentSuggestion = allSuggestions[currentSuggestionIndex]; + + if (accepted) { + unawaited( + ClusterFeedbackService.instance.addClusterToExistingPerson( + person: relevantPerson, + clusterID: currentSuggestion.clusterIDToMerge, + ), + ); + } else { + unawaited( + MLDataDB.instance.captureNotPersonFeedback( + personID: relevantPerson.remoteID, + clusterID: currentSuggestion.clusterIDToMerge, + ), + ); + } + // Wait for animation to complete before hiding widget + await Future.delayed(const Duration(milliseconds: 300)); + if (mounted) { + setState(() { + hasCurrentSuggestion = false; + }); + } + await _prepareNextSuggestion(); + } catch (e, s) { + _logger.severe("Error handling user choice", e, s); + if (mounted) { + setState(() { + isProcessing = false; + }); + } + } + } + + Future _saveAsAnotherPerson() async { + if (isProcessing || + allSuggestions.isEmpty || + currentSuggestionIndex >= allSuggestions.length) { + return; + } + setState(() { + isProcessing = true; + }); + unawaited(_animateOut()); + try { + final currentSuggestion = allSuggestions[currentSuggestionIndex]; + person = currentSuggestion.person; + final clusterID = currentSuggestion.clusterIDToMerge; + final someFile = currentSuggestion.filesInCluster.first; + + final result = await Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => SaveOrEditPerson( + clusterID, + file: someFile, + isEditing: false, + ), + ), + ); + if (result == null || result == false) { + // Animate back in and reset processing state + unawaited(_animateIn()); + if (mounted) { + setState(() { + isProcessing = false; + }); + } + return; + } + // Wait for animation to complete before hiding widget + await Future.delayed(const Duration(milliseconds: 300)); + if (mounted) { + setState(() { + hasCurrentSuggestion = false; + }); + } + + await _prepareNextSuggestion(); + } catch (e, s) { + _logger.severe("Error handling user choice", e, s); + if (mounted) { + setState(() { + isProcessing = false; + }); + } + } + } + + Future _prepareNextSuggestion() async { + if (!mounted) return; + + // Move to next suggestion + currentSuggestionIndex++; + + // Check if we have more suggestions + if (currentSuggestionIndex < allSuggestions.length) { + person = allSuggestions[currentSuggestionIndex].person; + try { + // Get face crops for next suggestion (from precomputed or generate new) + Map nextCrops; + if (precomputedFaceCrops.containsKey(currentSuggestionIndex)) { + nextCrops = precomputedFaceCrops[currentSuggestionIndex]!; + } else { + final nextSuggestion = allSuggestions[currentSuggestionIndex]; + nextCrops = await _generateFaceThumbnails( + nextSuggestion.filesInCluster.take(personPage ? 4 : 3).toList(), + nextSuggestion.clusterIDToMerge, + ); + } + if (mounted) { + setState(() { + faceCrops = nextCrops; + isProcessing = false; + isPreparingNext = false; + hasCurrentSuggestion = true; + }); + await _animateIn(); + unawaited(_precomputeNextSuggestions()); + } + } catch (e, s) { + _logger.severe("Error preparing next suggestion", e, s); + if (mounted) { + setState(() { + isProcessing = false; + isPreparingNext = false; + hasCurrentSuggestion = false; + }); + } + } + } else { + // No more suggestions available - stay hidden + if (mounted) { + setState(() { + isProcessing = false; + isPreparingNext = false; + hasCurrentSuggestion = false; + }); + } + } + } + + Future _animateOut() async { + await Future.wait([ + _fadeController.reverse(), + _slideController.reverse(), + ]); + } + + Future _animateIn() async { + _slideController.reset(); + _fadeController.reset(); + await Future.wait([ + _fadeController.forward(), + _slideController.forward(), + ]); + } + + @override + void dispose() { + _slideController.dispose(); + _fadeController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + if (isLoading || + allSuggestions.isEmpty || + currentSuggestionIndex >= allSuggestions.length || + !hasCurrentSuggestion) { + return const SizedBox.shrink(); + } + + final colorScheme = getEnteColorScheme(context); + final textTheme = getEnteTextTheme(context); + + return SlideTransition( + position: _slideAnimation, + child: FadeTransition( + opacity: _fadeAnimation, + child: GestureDetector( + key: ValueKey('suggestion_$currentSuggestionIndex'), + onTap: _navigateToCluster, + behavior: HitTestBehavior.opaque, + child: Stack( + children: [ + Container( + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + padding: const EdgeInsets.symmetric(vertical: 16), + decoration: BoxDecoration( + color: colorScheme.fillFaint, + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: colorScheme.strokeFainter, + width: 1, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + personPage + ? RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: textTheme.body, + children: [ + TextSpan(text: S.of(context).areThey), + TextSpan( + text: relevantPerson.data.name, + style: textTheme.bodyBold, + ), + TextSpan(text: S.of(context).questionmark), + ], + ), + ) + : Text( + S.of(context).sameperson, + style: textTheme.body, + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: _buildFaceThumbnails(), + ), + const SizedBox(height: 24), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Expanded( + child: GestureDetector( + onTap: isProcessing + ? null + : () => _handleUserChoice(false), + child: Container( + margin: const EdgeInsets.only(left: 16, right: 6), + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 12, + ), + decoration: BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: colorScheme.warning700, + width: 1, + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.close, + color: colorScheme.warning500, + size: 20, + ), + const SizedBox(width: 8), + Text( + S.of(context).no, + style: (personPage + ? textTheme.bodyBold + : textTheme.body) + .copyWith( + color: colorScheme.warning500, + ), + ), + ], + ), + ), + ), + ), + Expanded( + child: GestureDetector( + onTap: isProcessing + ? null + : () => _handleUserChoice(true), + child: Container( + margin: const EdgeInsets.only(left: 6, right: 16), + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 12, + ), + decoration: BoxDecoration( + color: colorScheme.primary500, + borderRadius: BorderRadius.circular(8), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.check, + color: textBaseDark, + size: 20, + ), + const SizedBox(width: 8), + Text( + S.of(context).yes, + style: (personPage + ? textTheme.bodyBold + : textTheme.body) + .copyWith( + color: textBaseDark, + ), + ), + ], + ), + ), + ), + ), + ], + ), + if (personPage) const SizedBox(height: 12), + if (personPage) + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: + isProcessing ? null : () => _saveAsAnotherPerson(), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 12, + horizontal: 32, + ), + child: Text( + S.of(context).saveAsAnotherPerson, + style: textTheme.mini.copyWith( + color: colorScheme.textMuted, + decoration: TextDecoration.underline, + ), + ), + ), + ), + ], + ), + ), + if (widget.onClose != null) + Positioned( + top: 4, + right: 12, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: widget.onClose, + child: Container( + padding: const EdgeInsets.all(16), + child: Icon( + Icons.close, + size: 16, + color: colorScheme.textBase, + ), + ), + ), + ), + ], + ), + ), + ), + ); + } + + List _buildFaceThumbnails() { + final currentSuggestion = allSuggestions[currentSuggestionIndex]; + final suggestPerson = currentSuggestion.person; + final files = + currentSuggestion.filesInCluster.take(personPage ? 4 : 3).toList(); + final thumbnails = []; + final textTheme = getEnteTextTheme(context); + + final start = personPage ? 0 : -1; + for (int i = start; i < files.length; i++) { + EnteFile? file; + Uint8List? faceCrop; + if (i != -1) { + file = files[i]; + faceCrop = faceCrops[file.uploadedFileID!]; + } + + if (i > start) { + thumbnails.add(const SizedBox(width: 8)); + } + + thumbnails.add( + Column( + children: [ + Container( + width: 72, + height: 72, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(32), + border: Border.all( + color: getEnteColorScheme(context).strokeFainter, + width: 1, + ), + ), + child: ClipRRect( + child: ClipPath( + clipper: ShapeBorderClipper( + shape: ContinuousRectangleBorder( + borderRadius: BorderRadius.circular(52), + ), + ), + child: (i == -1) + ? PersonFaceWidget( + personId: suggestPerson.remoteID, + key: ValueKey('person_${suggestPerson.remoteID}'), + ) + : FileFaceWidget( + key: ValueKey( + 'face_${currentSuggestionIndex}_${file!.uploadedFileID}', + ), + file, + faceCrop: faceCrop, + clusterID: currentSuggestion.clusterIDToMerge, + useFullFile: true, + thumbnailFallback: true, + ), + ), + ), + ), + if (i == -1) const SizedBox(height: 8), + if (i == -1) + SizedBox( + width: 72, + child: Center( + child: Text( + relevantPerson.data.name.trim(), + style: textTheme.bodyMuted, + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), + ), + ), + ], + ), + ); + } + + return thumbnails; + } +} diff --git a/mobile/lib/ui/viewer/people/person_row_item.dart b/mobile/lib/ui/viewer/people/person_row_item.dart index 10716f4196..0b86786621 100644 --- a/mobile/lib/ui/viewer/people/person_row_item.dart +++ b/mobile/lib/ui/viewer/people/person_row_item.dart @@ -1,41 +1,7 @@ import "package:flutter/material.dart"; import "package:photos/models/file/file.dart"; import "package:photos/models/ml/face/person.dart"; -import "package:photos/ui/viewer/search/result/person_face_widget.dart"; - -class PersonRowItem extends StatelessWidget { - final PersonEntity person; - final EnteFile personFile; - final VoidCallback onTap; - - const PersonRowItem({ - super.key, - required this.person, - required this.personFile, - required this.onTap, - }); - - @override - Widget build(BuildContext context) { - return ListTile( - dense: false, - minLeadingWidth: 0, - contentPadding: const EdgeInsets.symmetric(horizontal: 0), - leading: SizedBox( - width: 56, - height: 56, - child: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.elliptical(16, 12), - ), - child: PersonFaceWidget(personFile, personId: person.remoteID), - ), - ), - title: Text(person.data.name), - onTap: onTap, - ); - } -} +import "package:photos/ui/viewer/people/person_face_widget.dart"; class PersonGridItem extends StatelessWidget { final PersonEntity person; @@ -67,7 +33,10 @@ class PersonGridItem extends StatelessWidget { borderRadius: BorderRadius.circular(80), ), ), - child: PersonFaceWidget(personFile, personId: person.remoteID), + child: PersonFaceWidget( + personId: person.remoteID, + key: ValueKey(person.remoteID), + ), ), ), const SizedBox(height: 4), diff --git a/mobile/lib/ui/viewer/people/person_selection_action_widgets.dart b/mobile/lib/ui/viewer/people/person_selection_action_widgets.dart index b3a03451c4..e22a7696cb 100644 --- a/mobile/lib/ui/viewer/people/person_selection_action_widgets.dart +++ b/mobile/lib/ui/viewer/people/person_selection_action_widgets.dart @@ -7,7 +7,6 @@ import "package:photos/core/event_bus.dart"; import "package:photos/events/people_changed_event.dart"; import "package:photos/generated/l10n.dart"; import "package:photos/l10n/l10n.dart"; -import "package:photos/models/file/file.dart"; import "package:photos/models/ml/face/person.dart"; import "package:photos/models/typedefs.dart"; import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; @@ -17,21 +16,10 @@ import "package:photos/ui/components/buttons/button_widget.dart"; import "package:photos/ui/components/dialog_widget.dart"; import "package:photos/ui/components/models/button_type.dart"; import "package:photos/ui/notification/toast.dart"; -import "package:photos/ui/viewer/file/no_thumbnail_widget.dart"; -import "package:photos/ui/viewer/search/result/person_face_widget.dart"; +import "package:photos/ui/viewer/people/person_face_widget.dart"; import "package:photos/utils/dialog_util.dart"; import "package:photos/utils/person_contact_linking_util.dart"; -class PersonEntityWithThumbnailFile { - final PersonEntity person; - final EnteFile? thumbnailFile; - - const PersonEntityWithThumbnailFile( - this.person, - this.thumbnailFile, - ); -} - class LinkContactToPersonSelectionPage extends StatefulWidget { final String? emailToLink; const LinkContactToPersonSelectionPage({ @@ -46,25 +34,21 @@ class LinkContactToPersonSelectionPage extends StatefulWidget { class _LinkContactToPersonSelectionPageState extends State { - late Future> - _personEntitiesWithThumnailFile; + late Future> _personEntities; final _logger = Logger('LinkContactToPersonSelectionPage'); @override void initState() { super.initState(); - _personEntitiesWithThumnailFile = - PersonService.instance.getPersons().then((persons) async { - final List result = []; + _personEntities = PersonService.instance.getPersons().then((persons) async { + final List result = []; for (final person in persons) { if ((person.data.email != null && person.data.email!.isNotEmpty) || (person.data.isHidden || person.data.isIgnored)) { continue; } - final file = - await PersonService.instance.getThumbnailFileOfPerson(person); - result.add(PersonEntityWithThumbnailFile(person, file)); + result.add(person); } return result; }); @@ -85,14 +69,14 @@ class _LinkContactToPersonSelectionPageState ), centerTitle: false, ), - body: FutureBuilder>( - future: _personEntitiesWithThumnailFile, + body: FutureBuilder>( + future: _personEntities, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: EnteLoadingWidget()); } else if (snapshot.hasError) { _logger.severe( - "Failed to load _personEntitiesWithThumnailFile", + "Failed to load _personEntities", snapshot.error, snapshot.stackTrace, ); @@ -131,7 +115,7 @@ class _LinkContactToPersonSelectionPageState final updatedPerson = await linkPersonToContact( context, emailToLink: widget.emailToLink!, - personEntity: results[index].person, + personEntity: results[index], ); if (updatedPerson != null) { @@ -143,7 +127,7 @@ class _LinkContactToPersonSelectionPageState } }, itemSize: itemSize, - personEntitiesWithThumbnailFile: results[index], + personEntity: results[index], ); }, ); @@ -159,7 +143,8 @@ class _LinkContactToPersonSelectionPageState required PersonEntity personEntity, }) async { if (await checkIfEmailAlreadyAssignedToAPerson(emailToLink)) { - throw Exception("Email already linked to a person"); + await showAlreadyLinkedEmailDialog(context, emailToLink); + return null; } final personName = personEntity.data.name; @@ -221,25 +206,21 @@ class ReassignMeSelectionPage extends StatefulWidget { } class _ReassignMeSelectionPageState extends State { - late Future> - _personEntitiesWithThumnailFile; + late Future> _personEntities; final _logger = Logger('ReassignMeSelectionPage'); @override void initState() { super.initState(); - _personEntitiesWithThumnailFile = - PersonService.instance.getPersons().then((persons) async { - final List result = []; + _personEntities = PersonService.instance.getPersons().then((persons) async { + final List result = []; for (final person in persons) { if ((person.data.email != null && person.data.email!.isNotEmpty) || (person.data.isHidden || person.data.isIgnored)) { continue; } - final file = - await PersonService.instance.getThumbnailFileOfPerson(person); - result.add(PersonEntityWithThumbnailFile(person, file)); + result.add(person); } return result; }); @@ -260,8 +241,8 @@ class _ReassignMeSelectionPageState extends State { ), centerTitle: false, ), - body: FutureBuilder>( - future: _personEntitiesWithThumnailFile, + body: FutureBuilder>( + future: _personEntities, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: EnteLoadingWidget()); @@ -310,12 +291,11 @@ class _ReassignMeSelectionPageState extends State { try { await reassignMe( currentPersonID: widget.currentMeId, - newPersonID: results[index].person.remoteID, + newPersonID: results[index].remoteID, ); showToast( context, - context.l10n - .reassignedToName(results[index].person.data.name), + context.l10n.reassignedToName(results[index].data.name), ); await Future.delayed(const Duration(milliseconds: 1250)); unawaited(dialog.hide()); @@ -328,7 +308,7 @@ class _ReassignMeSelectionPageState extends State { } }, itemSize: itemSize, - personEntitiesWithThumbnailFile: results[index], + personEntity: results[index], ); }, ); @@ -374,12 +354,12 @@ class _ReassignMeSelectionPageState extends State { class _RoundedPersonFaceWidget extends StatelessWidget { final FutureVoidCallback onTap; final double itemSize; - final PersonEntityWithThumbnailFile personEntitiesWithThumbnailFile; + final PersonEntity personEntity; const _RoundedPersonFaceWidget({ required this.onTap, required this.itemSize, - required this.personEntitiesWithThumbnailFile, + required this.personEntity, }); double get borderRadius => 82 * (itemSize / 102); @@ -425,14 +405,10 @@ class _RoundedPersonFaceWidget extends StatelessWidget { ), ), ), - child: personEntitiesWithThumbnailFile.thumbnailFile == null - ? const NoThumbnailWidget(addBorder: false) - : PersonFaceWidget( - personEntitiesWithThumbnailFile.thumbnailFile!, - personId: - personEntitiesWithThumbnailFile.person.remoteID, - useFullFile: true, - ), + child: PersonFaceWidget( + personId: personEntity.remoteID, + useFullFile: true, + ), ), ), ), @@ -441,7 +417,7 @@ class _RoundedPersonFaceWidget extends StatelessWidget { Padding( padding: const EdgeInsets.only(top: 6, bottom: 0), child: Text( - personEntitiesWithThumbnailFile.person.data.name, + personEntity.data.name, maxLines: 1, textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, diff --git a/mobile/lib/ui/viewer/people/save_or_edit_person.dart b/mobile/lib/ui/viewer/people/save_or_edit_person.dart index d372b9001f..8a3f597873 100644 --- a/mobile/lib/ui/viewer/people/save_or_edit_person.dart +++ b/mobile/lib/ui/viewer/people/save_or_edit_person.dart @@ -21,7 +21,6 @@ import "package:photos/models/ml/face/person.dart"; import "package:photos/services/account/user_service.dart"; import "package:photos/services/machine_learning/face_ml/feedback/cluster_feedback.dart"; import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; -import "package:photos/services/machine_learning/ml_result.dart"; import "package:photos/services/search_service.dart"; import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/common/date_input.dart"; @@ -37,8 +36,8 @@ import "package:photos/ui/viewer/gallery/hooks/pick_person_avatar.dart"; import "package:photos/ui/viewer/people/link_email_screen.dart"; import "package:photos/ui/viewer/people/people_util.dart"; import "package:photos/ui/viewer/people/person_clusters_page.dart"; +import "package:photos/ui/viewer/people/person_face_widget.dart"; import "package:photos/ui/viewer/people/person_row_item.dart"; -import "package:photos/ui/viewer/search/result/person_face_widget.dart"; import "package:photos/utils/dialog_util.dart"; import "package:photos/utils/navigation_util.dart"; import "package:photos/utils/person_contact_linking_util.dart"; @@ -155,94 +154,72 @@ class _SaveOrEditPersonState extends State { children: [ const SizedBox(height: 48), if (person != null) - FutureBuilder<(String, EnteFile)>( - future: _getRecentFileWithClusterID(person!), - builder: (context, snapshot) { - if (snapshot.hasData) { - final String personClusterID = - snapshot.data!.$1; - final personFile = snapshot.data!.$2; - return Stack( - children: [ - SizedBox( - height: 110, - width: 110, - child: ClipPath( - clipper: ShapeBorderClipper( - shape: ContinuousRectangleBorder( - borderRadius: - BorderRadius.circular(80), - ), - ), - child: snapshot.hasData - ? PersonFaceWidget( - key: ValueKey( - person?.data.avatarFaceID ?? - "", - ), - personFile, - clusterID: personClusterID, - personId: person!.remoteID, - ) - : const NoThumbnailWidget( - addBorder: false, - ), - ), + Stack( + children: [ + SizedBox( + height: 110, + width: 110, + child: ClipPath( + clipper: ShapeBorderClipper( + shape: ContinuousRectangleBorder( + borderRadius: BorderRadius.circular(80), ), - if (person != null) - Positioned( - right: 0, - bottom: 0, - child: Container( - width: 28, - height: 28, - decoration: BoxDecoration( - borderRadius: - BorderRadius.circular(8.0), - boxShadow: Theme.of(context) - .colorScheme - .enteTheme - .shadowMenu, - color: getEnteColorScheme(context) - .backgroundElevated2, - ), - child: IconButton( - icon: const Icon(Icons.edit), - iconSize: - 16, // specify the size of the icon - onPressed: () async { - final result = - await showPersonAvatarPhotoSheet( - context, - person!, - ); - if (result != null) { - _logger.info( - 'Person avatar updated', - ); - setState(() { - person = result; - }); - Bus.instance.fire( - PeopleChangedEvent( - type: PeopleEventType - .saveOrEditPerson, - source: - "_SaveOrEditPersonState", - person: result, - ), - ); - } - }, - ), - ), - ), - ], - ); - } else { - return const SizedBox.shrink(); - } - }, + ), + child: PersonFaceWidget( + key: ValueKey( + person?.data.avatarFaceID ?? "", + ), + personId: person!.remoteID, + ), + ), + ), + if (person != null) + Positioned( + right: 0, + bottom: 0, + child: Container( + width: 28, + height: 28, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8.0), + boxShadow: Theme.of(context) + .colorScheme + .enteTheme + .shadowMenu, + color: getEnteColorScheme(context) + .backgroundElevated2, + ), + child: IconButton( + icon: const Icon(Icons.edit), + iconSize: + 16, // specify the size of the icon + onPressed: () async { + final result = + await showPersonAvatarPhotoSheet( + context, + person!, + ); + if (result != null) { + _logger.info( + 'Person avatar updated', + ); + setState(() { + person = result; + }); + Bus.instance.fire( + PeopleChangedEvent( + type: PeopleEventType + .saveOrEditPerson, + source: "_SaveOrEditPersonState", + person: result, + ), + ); + } + }, + ), + ), + ), + ], ), if (person == null) SizedBox( @@ -256,7 +233,6 @@ class _SaveOrEditPersonState extends State { ), child: widget.file != null ? PersonFaceWidget( - widget.file!, clusterID: widget.clusterID, ) : const NoThumbnailWidget( @@ -733,40 +709,6 @@ class _SaveOrEditPersonState extends State { } return personAndFileID; } - - Future<(String, EnteFile)> _getRecentFileWithClusterID( - PersonEntity person, - ) async { - final clustersToFiles = - await SearchService.instance.getClusterFilesForPersonID( - person.remoteID, - ); - int? avatarFileID; - if (person.data.hasAvatar()) { - avatarFileID = tryGetFileIdFromFaceId(person.data.avatarFaceID!); - } - EnteFile? resultFile; - // iterate over all clusters and get the first file - for (final clusterFiles in clustersToFiles.values) { - for (final file in clusterFiles) { - if (avatarFileID != null && file.uploadedFileID! == avatarFileID) { - resultFile = file; - break; - } - resultFile ??= file; - if (resultFile.creationTime! < file.creationTime!) { - resultFile = file; - } - } - } - if (resultFile == null) { - debugPrint( - "Person ${kDebugMode ? person.data.name : person.remoteID} has no files", - ); - return ("", EnteFile()); - } - return (person.remoteID, resultFile); - } } class _EmailSection extends StatefulWidget { diff --git a/mobile/lib/ui/viewer/search/result/contact_result_page.dart b/mobile/lib/ui/viewer/search/result/contact_result_page.dart index 53b675ed3e..fb487233a8 100644 --- a/mobile/lib/ui/viewer/search/result/contact_result_page.dart +++ b/mobile/lib/ui/viewer/search/result/contact_result_page.dart @@ -55,6 +55,7 @@ class _ContactResultPageState extends State { late final List collections; late final StreamSubscription _filesUpdatedEvent; late String _searchResultName; + late final SearchFilterDataProvider _searchFilterDataProvider; @override void initState() { @@ -75,6 +76,10 @@ class _ContactResultPageState extends State { setState(() {}); } }); + + _searchFilterDataProvider = SearchFilterDataProvider( + initialGalleryFilter: widget.searchResult.getHierarchicalSearchFilter(), + ); } @override @@ -145,10 +150,7 @@ class _ContactResultPageState extends State { return GalleryFilesState( child: InheritedSearchFilterDataWrapper( - searchFilterDataProvider: SearchFilterDataProvider( - initialGalleryFilter: - widget.searchResult.getHierarchicalSearchFilter(), - ), + searchFilterDataProvider: _searchFilterDataProvider, child: Scaffold( appBar: PreferredSize( preferredSize: const Size.fromHeight(90.0), diff --git a/mobile/lib/ui/viewer/search/result/magic_result_screen.dart b/mobile/lib/ui/viewer/search/result/magic_result_screen.dart index b3f1b72d44..b5c2a87543 100644 --- a/mobile/lib/ui/viewer/search/result/magic_result_screen.dart +++ b/mobile/lib/ui/viewer/search/result/magic_result_screen.dart @@ -55,6 +55,7 @@ class _MagicResultScreenState extends State { late final Logger _logger = Logger("_MagicResultScreenState"); late final Map fileIDToRelevantPos; bool _enableGrouping = false; + late final SearchFilterDataProvider _searchFilterDataProvider; @override void initState() { @@ -103,6 +104,10 @@ class _MagicResultScreenState extends State { }); } }); + + _searchFilterDataProvider = SearchFilterDataProvider( + initialGalleryFilter: widget.magicFilter, + ); } Map getFileIDToRelevantPos() { @@ -164,9 +169,7 @@ class _MagicResultScreenState extends State { ); return GalleryFilesState( child: InheritedSearchFilterDataWrapper( - searchFilterDataProvider: SearchFilterDataProvider( - initialGalleryFilter: widget.magicFilter, - ), + searchFilterDataProvider: _searchFilterDataProvider, child: Scaffold( appBar: PreferredSize( preferredSize: const Size.fromHeight(90.0), diff --git a/mobile/lib/ui/viewer/search/result/people_section_all_page.dart b/mobile/lib/ui/viewer/search/result/people_section_all_page.dart index a24e02d63b..d78eb4b9ba 100644 --- a/mobile/lib/ui/viewer/search/result/people_section_all_page.dart +++ b/mobile/lib/ui/viewer/search/result/people_section_all_page.dart @@ -1,30 +1,318 @@ import "dart:async"; import 'package:flutter/material.dart'; -import "package:flutter_animate/flutter_animate.dart"; import "package:photos/events/event.dart"; +import "package:photos/events/people_changed_event.dart"; import "package:photos/generated/l10n.dart"; +import "package:photos/models/file/file.dart"; +import "package:photos/models/ml/face/person.dart"; import "package:photos/models/search/generic_search_result.dart"; -import "package:photos/models/search/hierarchical/face_filter.dart"; +import "package:photos/models/search/recent_searches.dart"; +import "package:photos/models/search/search_constants.dart"; +import "package:photos/models/search/search_result.dart"; import "package:photos/models/search/search_types.dart"; import "package:photos/models/selected_people.dart"; +import "package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart"; +import "package:photos/services/search_service.dart"; import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/common/loading_widget.dart"; +import "package:photos/ui/components/bottom_action_bar/people_bottom_action_bar_widget.dart"; +import "package:photos/ui/viewer/file/no_thumbnail_widget.dart"; +import "package:photos/ui/viewer/file/thumbnail_widget.dart"; +import "package:photos/ui/viewer/people/add_person_action_sheet.dart"; +import "package:photos/ui/viewer/people/people_page.dart"; +import "package:photos/ui/viewer/people/person_face_widget.dart"; +import "package:photos/ui/viewer/people/person_gallery_suggestion.dart"; +import "package:photos/ui/viewer/search/result/search_result_page.dart"; import "package:photos/ui/viewer/search_tab/people_section.dart"; +import "package:photos/utils/navigation_util.dart"; -class PeopleSectionAllPage extends StatelessWidget { +class PeopleSectionAllPage extends StatefulWidget { const PeopleSectionAllPage({ super.key, }); + @override + State createState() => _PeopleSectionAllPageState(); +} + +class _PeopleSectionAllPageState extends State { + final _selectedPeople = SelectedPeople(); + @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(SectionType.face.sectionTitle(context)), - centerTitle: false, - ), - body: const PeopleSectionAllWidget(), + return ListenableBuilder( + listenable: _selectedPeople, + builder: (context, _) { + final hasSelection = _selectedPeople.personIds.isNotEmpty; + + return Scaffold( + appBar: AppBar( + title: Text(SectionType.face.sectionTitle(context)), + centerTitle: false, + ), + body: PeopleSectionAllSelectionWrapper( + selectedPeople: _selectedPeople, + ), + bottomNavigationBar: hasSelection + ? PeopleBottomActionBarWidget( + _selectedPeople, + onCancel: () { + _selectedPeople.clearAll(); + }, + ) + : null, + ); + }, + ); + } +} + +class PeopleSectionAllSelectionWrapper extends StatefulWidget { + final SelectedPeople selectedPeople; + + const PeopleSectionAllSelectionWrapper({ + super.key, + required this.selectedPeople, + }); + + @override + State createState() => + _PeopleSectionAllSelectionWrapperState(); +} + +class _PeopleSectionAllSelectionWrapperState + extends State { + @override + Widget build(BuildContext context) { + return PeopleSectionAllWidget( + selectedPeople: widget.selectedPeople, + ); + } +} + +class SelectablePersonSearchExample extends StatelessWidget { + final GenericSearchResult searchResult; + final double size; + final SelectedPeople selectedPeople; + + const SelectablePersonSearchExample({ + super.key, + required this.searchResult, + required this.selectedPeople, + this.size = 102, + }); + + void _handleTap(BuildContext context) { + if (selectedPeople.personIds.isNotEmpty) { + _toggleSelection(); + } else { + _handleNavigation(context); + } + } + + void _handleLongPress() { + _toggleSelection(); + } + + void _toggleSelection() { + final personId = searchResult.params[kPersonParamID] as String?; + final clusterId = searchResult.params[kClusterParamId] as String?; + + final idToUse = + (personId != null && personId.isNotEmpty) ? personId : clusterId; + + if (idToUse != null && idToUse.isNotEmpty) { + selectedPeople.toggleSelection(idToUse); + } + } + + void _handleNavigation(BuildContext context) { + RecentSearches().add(searchResult.name()); + if (searchResult.onResultTap != null) { + searchResult.onResultTap!(context); + } else { + routeToPage( + context, + SearchResultPage(searchResult), + ); + } + } + + @override + Widget build(BuildContext context) { + final borderRadius = 82 * (size / 102); + final bool isCluster = (searchResult.type() == ResultType.faces && + int.tryParse(searchResult.name()) != null); + + return ListenableBuilder( + listenable: selectedPeople, + builder: (context, _) { + final personId = searchResult.params[kPersonParamID] as String?; + final clusterId = searchResult.params[kClusterParamId] as String?; + final idToCheck = + (personId != null && personId.isNotEmpty) ? personId : clusterId; + final bool isSelected = idToCheck != null + ? selectedPeople.isPersonSelected(idToCheck) + : false; + + return GestureDetector( + onTap: () => _handleTap(context), + onLongPress: _handleLongPress, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Stack( + clipBehavior: Clip.none, + alignment: Alignment.center, + children: [ + ClipPath( + clipper: ShapeBorderClipper( + shape: ContinuousRectangleBorder( + borderRadius: BorderRadius.circular(borderRadius), + ), + ), + child: Container( + width: size, + height: size, + decoration: BoxDecoration( + color: getEnteColorScheme(context).strokeFaint, + ), + ), + ), + Builder( + builder: (context) { + late Widget child; + + if (searchResult.previewThumbnail() != null) { + child = searchResult.type() != ResultType.faces + ? ThumbnailWidget( + searchResult.previewThumbnail()!, + shouldShowSyncStatus: false, + ) + : FaceSearchResult(searchResult); + } else { + child = const NoThumbnailWidget( + addBorder: false, + ); + } + return SizedBox( + width: size - 2, + height: size - 2, + child: ClipPath( + clipper: ShapeBorderClipper( + shape: ContinuousRectangleBorder( + borderRadius: + searchResult.previewThumbnail() != null + ? BorderRadius.circular(borderRadius - 1) + : BorderRadius.circular(81), + ), + ), + child: ColorFiltered( + colorFilter: ColorFilter.mode( + Colors.black.withOpacity( + isSelected ? 0.4 : 0, + ), + BlendMode.darken, + ), + child: child, + ), + ), + ); + }, + ), + Positioned( + top: 5, + right: 5, + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 200), + switchInCurve: Curves.easeOut, + switchOutCurve: Curves.easeIn, + child: isSelected + ? const Icon( + Icons.check_circle_rounded, + color: Colors.white, + size: 22, + ) + : null, + ), + ), + ], + ), + isCluster + ? GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () async { + final result = await showAssignPersonAction( + context, + clusterID: searchResult.name(), + ); + if (result != null && + result is (PersonEntity, EnteFile)) { + // ignore: unawaited_futures + routeToPage( + context, + PeoplePage( + person: result.$1, + searchResult: null, + ), + ); + } else if (result != null && result is PersonEntity) { + // ignore: unawaited_futures + routeToPage( + context, + PeoplePage( + person: result, + searchResult: null, + ), + ); + } + }, + child: Padding( + padding: const EdgeInsets.only(top: 6, bottom: 0), + child: Text( + "Add name", + maxLines: 1, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + style: getEnteTextTheme(context).small, + ), + ), + ) + : Padding( + padding: const EdgeInsets.only(top: 6, bottom: 0), + child: Text( + searchResult.name(), + maxLines: 1, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + style: getEnteTextTheme(context).small, + ), + ), + ], + ), + ); + }, + ); + } +} + +class FaceSearchResult extends StatelessWidget { + final SearchResult searchResult; + + const FaceSearchResult(this.searchResult, {super.key}); + + @override + Widget build(BuildContext context) { + final params = (searchResult as GenericSearchResult).params; + return PersonFaceWidget( + personId: params[kPersonParamID], + clusterID: params[kClusterParamId], + key: params.containsKey(kPersonWidgetKey) + ? ValueKey(params[kPersonWidgetKey]) + : ValueKey(params[kPersonParamID] ?? params[kClusterParamId]), ); } } @@ -45,7 +333,15 @@ class PeopleSectionAllWidget extends StatefulWidget { class _PeopleSectionAllWidgetState extends State { late Future> sectionData; + List normalFaces = []; + List extraFaces = []; final streamSubscriptions = []; + bool _showingAllFaces = false; + bool _isLoaded = false; + bool _isInitialLoad = true; + bool userDismissedPersonGallerySuggestion = false; + + bool get _showMoreLessOption => !widget.namedOnly && extraFaces.isNotEmpty; @override void initState() { @@ -56,32 +352,55 @@ class _PeopleSectionAllWidgetState extends State { for (Stream stream in streamsToListenTo) { streamSubscriptions.add( stream.listen((event) async { - setState(() { - sectionData = getResults(); - }); + if (event is PeopleChangedEvent && + event.type == PeopleEventType.addedClusterToPerson) { + normalFaces.removeWhere( + (person) => + (person.params[kClusterParamId] as String?) == event.source, + ); + extraFaces.removeWhere( + (person) => + (person.params[kClusterParamId] as String?) == event.source, + ); + setState(() {}); + } else { + setState(() { + _isInitialLoad = false; + _isLoaded = false; + sectionData = getResults(); + }); + } }), ); } } Future> getResults() async { + final allFaces = await SearchService.instance + .getAllFace(null, minClusterSize: kMinimumClusterSizeAllFaces); + normalFaces.clear(); + extraFaces.clear(); + for (final face in allFaces) { + if (face.fileCount() >= kMinimumClusterSizeSearchResult || + face.name().isNotEmpty) { + normalFaces.add(face); + } else { + extraFaces.add(face); + } + } + if (normalFaces.isEmpty && extraFaces.isNotEmpty) { + normalFaces = extraFaces; + extraFaces = []; + } final results = - List.from(await SectionType.face.getData(context)); + _showingAllFaces ? [...normalFaces, ...extraFaces] : normalFaces; if (widget.namedOnly) { results.removeWhere( - (element) => - (element.hierarchicalSearchFilter as FaceFilter).personId == null, + (element) => element.params[kPersonParamID] == null, ); - if (widget.selectedPeople?.personIds.isEmpty ?? false) { - widget.selectedPeople!.select( - results - .take(2) - .map((e) => (e.hierarchicalSearchFilter as FaceFilter).personId!) - .toSet(), - ); - } } + _isLoaded = true; return results; } @@ -104,14 +423,15 @@ class _PeopleSectionAllWidgetState extends State { return FutureBuilder>( future: sectionData, builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { + if (!_isLoaded && + snapshot.connectionState == ConnectionState.waiting && + _isInitialLoad) { return const Center(child: EnteLoadingWidget()); } else if (snapshot.hasError) { return const Center(child: Icon(Icons.error_outline_rounded)); - } else if (!snapshot.hasData || snapshot.data!.isEmpty) { + } else if (normalFaces.isEmpty && _isLoaded) { return Center(child: Text(S.of(context).noResultsFound + '.')); } else { - final results = snapshot.data!; final screenWidth = MediaQuery.of(context).size.width; final crossAxisCount = (screenWidth / 100).floor(); @@ -120,44 +440,162 @@ class _PeopleSectionAllWidgetState extends State { ((crossAxisCount - 1) * gridPadding))) / crossAxisCount; - return GridView.builder( - padding: const EdgeInsets.fromLTRB( - horizontalEdgePadding, - 16, - horizontalEdgePadding, - 96, - ), - shrinkWrap: true, - primary: false, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - mainAxisSpacing: gridPadding, - crossAxisSpacing: gridPadding, - crossAxisCount: crossAxisCount, - childAspectRatio: itemSize / (itemSize + (24 * textScaleFactor)), - ), - itemCount: results.length, - itemBuilder: (context, index) { - return PersonSearchExample( - searchResult: results[index], - size: itemSize, - selectedPeople: widget.selectedPeople, - ) - .animate(delay: Duration(milliseconds: index * 13)) - .fadeIn( - duration: const Duration(milliseconds: 225), - curve: Curves.easeIn, - ) - .slide( - begin: const Offset(0, -0.06), - curve: Curves.easeInOut, - duration: const Duration( - milliseconds: 225, + return CustomScrollView( + slivers: [ + (!userDismissedPersonGallerySuggestion && !widget.namedOnly) + ? SliverToBoxAdapter( + child: Dismissible( + key: const Key("personGallerySuggestionAll"), + direction: DismissDirection.horizontal, + onDismissed: (direction) { + setState(() { + userDismissedPersonGallerySuggestion = true; + }); + }, + child: PersonGallerySuggestion( + person: null, + onClose: () { + setState(() { + userDismissedPersonGallerySuggestion = true; + }); + }, + ), + ), + ) + : const SliverToBoxAdapter(child: SizedBox.shrink()), + SliverPadding( + padding: const EdgeInsets.fromLTRB( + horizontalEdgePadding, + 16, + horizontalEdgePadding, + 16, + ), + sliver: SliverGrid( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + mainAxisSpacing: gridPadding, + crossAxisSpacing: gridPadding, + crossAxisCount: crossAxisCount, + childAspectRatio: + itemSize / (itemSize + (24 * textScaleFactor)), + ), + delegate: SliverChildBuilderDelegate( + childCount: normalFaces.length, + (context, index) { + return !widget.namedOnly + ? SelectablePersonSearchExample( + searchResult: normalFaces[index], + size: itemSize, + selectedPeople: widget.selectedPeople!, + ) + : PersonSearchExample( + searchResult: normalFaces[index], + size: itemSize, + selectedPeople: widget.selectedPeople!, + ); + }, + ), + ), + ), + if (_showMoreLessOption) + SliverToBoxAdapter(child: _buildShowMoreOrLessButton(context)), + const SliverToBoxAdapter( + child: SizedBox(height: 16), + ), + if (_showingAllFaces) + SliverPadding( + padding: const EdgeInsets.fromLTRB( + horizontalEdgePadding, + 16, + horizontalEdgePadding, + 16, + ), + sliver: SliverGrid( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + mainAxisSpacing: gridPadding, + crossAxisSpacing: gridPadding, + crossAxisCount: crossAxisCount, + childAspectRatio: + itemSize / (itemSize + (24 * textScaleFactor)), ), - ); - }, + delegate: SliverChildBuilderDelegate( + childCount: extraFaces.length, + (context, index) { + return !widget.namedOnly + ? SelectablePersonSearchExample( + searchResult: extraFaces[index], + size: itemSize, + selectedPeople: widget.selectedPeople!, + ) + : PersonSearchExample( + searchResult: extraFaces[index], + size: itemSize, + selectedPeople: widget.selectedPeople!, + ); + }, + ), + ), + ), + if (_showingAllFaces) + const SliverToBoxAdapter( + child: SizedBox(height: 16), + ), + ], ); } }, ); } + + Widget _buildShowMoreOrLessButton(BuildContext context) { + return Container( + padding: const EdgeInsets.fromLTRB(20, 8, 20, 24), + child: SizedBox( + width: double.infinity, + child: TextButton( + onPressed: () { + if (_showingAllFaces) { + setState(() { + _showingAllFaces = false; + }); + } else { + setState(() { + _showingAllFaces = true; + }); + } + }, + style: TextButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide( + color: Theme.of(context).colorScheme.outline.withOpacity(0.3), + width: 1, + ), + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + _showingAllFaces + ? S.of(context).showLessFaces + : S.of(context).showMoreFaces, + style: getEnteTextTheme(context).small.copyWith( + color: Theme.of(context).colorScheme.primary, + ), + ), + const SizedBox(width: 8), + Icon( + _showingAllFaces + ? Icons.keyboard_double_arrow_up_outlined + : Icons.keyboard_double_arrow_down_outlined, + size: 16, + color: Theme.of(context).colorScheme.primary, + ), + ], + ), + ), + ), + ); + } } diff --git a/mobile/lib/ui/viewer/search/result/person_face_widget.dart b/mobile/lib/ui/viewer/search/result/person_face_widget.dart deleted file mode 100644 index 62c18ec618..0000000000 --- a/mobile/lib/ui/viewer/search/result/person_face_widget.dart +++ /dev/null @@ -1,187 +0,0 @@ -import "dart:typed_data"; - -import 'package:flutter/widgets.dart'; -import "package:logging/logging.dart"; -import "package:photos/db/files_db.dart"; -import "package:photos/db/ml/db.dart"; -import 'package:photos/models/file/file.dart'; -import "package:photos/models/ml/face/face.dart"; -import "package:photos/models/ml/face/person.dart"; -import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; -import "package:photos/services/machine_learning/ml_result.dart"; -import "package:photos/services/search_service.dart"; -import "package:photos/theme/ente_theme.dart"; -import "package:photos/ui/common/loading_widget.dart"; -import "package:photos/ui/viewer/file/thumbnail_widget.dart"; -import "package:photos/utils/face/face_box_crop.dart"; - -final _logger = Logger("PersonFaceWidget"); - -class PersonFaceWidget extends StatefulWidget { - final EnteFile file; - final String? personId; - final String? clusterID; - final bool useFullFile; - final bool thumbnailFallback; - final bool cannotTrustFile; - final Uint8List? faceCrop; - final VoidCallback? onErrorCallback; - - // PersonFaceWidget constructor checks that both personId and clusterID are not null - // and that the file is not null - const PersonFaceWidget( - this.file, { - this.personId, - this.clusterID, - this.useFullFile = true, - this.thumbnailFallback = false, - this.cannotTrustFile = false, - this.faceCrop, - this.onErrorCallback, - super.key, - }) : assert( - personId != null || clusterID != null, - "PersonFaceWidget requires either personId or clusterID to be non-null", - ); - - @override - State createState() => _PersonFaceWidgetState(); -} - -class _PersonFaceWidgetState extends State { - Future? faceCropFuture; - late final mlDataDB = MLDataDB.instance; - - @override - void initState() { - super.initState(); - faceCropFuture = widget.faceCrop != null - ? Future.value(widget.faceCrop) - : _getFaceCrop(); - } - - @override - void dispose() { - super.dispose(); - checkStopTryingToGenerateFaceThumbnails( - widget.file, - useFullFile: widget.useFullFile, - ); - } - - @override - Widget build(BuildContext context) { - return FutureBuilder( - future: faceCropFuture, - builder: (context, snapshot) { - if (snapshot.hasData) { - final ImageProvider imageProvider = MemoryImage(snapshot.data!); - return Stack( - fit: StackFit.expand, - children: [ - Image( - image: imageProvider, - fit: BoxFit.cover, - ), - ], - ); - } else { - if (snapshot.hasError) { - _logger.severe( - "Error getting cover face for person: ${snapshot.error} ${snapshot.stackTrace}}", - ); - } - return widget.thumbnailFallback - ? ThumbnailWidget(widget.file) - : EnteLoadingWidget( - color: getEnteColorScheme(context).fillMuted, - ); - } - }, - ); - } - - Future _getFaceCrop() async { - try { - EnteFile? fileForFaceCrop = widget.file; - String? personAvatarFaceID; - Iterable? allFaces; - if (widget.personId != null) { - final PersonEntity? personEntity = - await PersonService.instance.getPerson(widget.personId!); - if (personEntity != null) { - personAvatarFaceID = personEntity.data.avatarFaceID; - if (personAvatarFaceID != null) { - final tryCache = - await checkGetCachedCropForFaceID(personAvatarFaceID); - if (tryCache != null) return tryCache; - } - if (personAvatarFaceID == null && widget.cannotTrustFile) { - allFaces = await mlDataDB.getFaceIDsForPerson(widget.personId!); - } - } - } else if (widget.clusterID != null && widget.cannotTrustFile) { - allFaces = await mlDataDB.getFaceIDsForCluster(widget.clusterID!); - } - if (allFaces != null) { - final allFileIDs = - allFaces.map((e) => getFileIdFromFaceId(e)).toSet(); - final hiddenFileIDs = await SearchService.instance - .getHiddenFiles() - .then((onValue) => onValue.map((e) => e.uploadedFileID)); - final acceptableFileIDs = allFileIDs.difference(hiddenFileIDs.toSet()); - final fileIDToCreationTime = - await FilesDB.instance.getFileIDToCreationTime(); - // Get the file with the most recent creation time - final recentFileID = acceptableFileIDs.reduce((a, b) { - final aTime = fileIDToCreationTime[a]; - final bTime = fileIDToCreationTime[b]; - if (aTime == null) { - return b; - } - if (bTime == null) { - return a; - } - return (aTime >= bTime) ? a : b; - }); - if (fileForFaceCrop.uploadedFileID != recentFileID) { - fileForFaceCrop = - await FilesDB.instance.getAnyUploadedFile(recentFileID); - if (fileForFaceCrop == null) return null; - } - } - - final Face? face = await mlDataDB.getCoverFaceForPerson( - recentFileID: fileForFaceCrop.uploadedFileID!, - avatarFaceId: personAvatarFaceID, - personID: widget.personId, - clusterID: widget.clusterID, - ); - if (face == null) { - debugPrint( - "No cover face for person: ${widget.personId} and cluster ${widget.clusterID} and recentFile ${widget.file.uploadedFileID}", - ); - return null; - } - if (face.fileID != fileForFaceCrop.uploadedFileID!) { - fileForFaceCrop = - await FilesDB.instance.getAnyUploadedFile(face.fileID); - if (fileForFaceCrop == null) return null; - } - final cropMap = await getCachedFaceCrops( - fileForFaceCrop, - [face], - useFullFile: widget.useFullFile, - ); - return cropMap?[face.faceID]; - } catch (e, s) { - _logger.severe( - "Error getting cover face for person: ${widget.personId} and cluster ${widget.clusterID}", - e, - s, - ); - widget.onErrorCallback?.call(); - return null; - } - } -} diff --git a/mobile/lib/ui/viewer/search/result/search_result_page.dart b/mobile/lib/ui/viewer/search/result/search_result_page.dart index 4ac02d64b0..e2ec7bf016 100644 --- a/mobile/lib/ui/viewer/search/result/search_result_page.dart +++ b/mobile/lib/ui/viewer/search/result/search_result_page.dart @@ -41,6 +41,7 @@ class _SearchResultPageState extends State { final _selectedFiles = SelectedFiles(); late final List files; late final StreamSubscription _filesUpdatedEvent; + late final SearchFilterDataProvider _searchFilterDataProvider; @override void initState() { @@ -58,6 +59,9 @@ class _SearchResultPageState extends State { setState(() {}); } }); + _searchFilterDataProvider = SearchFilterDataProvider( + initialGalleryFilter: widget.searchResult.getHierarchicalSearchFilter(), + ); } @override @@ -100,10 +104,7 @@ class _SearchResultPageState extends State { return GalleryFilesState( child: InheritedSearchFilterDataWrapper( - searchFilterDataProvider: SearchFilterDataProvider( - initialGalleryFilter: - widget.searchResult.getHierarchicalSearchFilter(), - ), + searchFilterDataProvider: _searchFilterDataProvider, child: Scaffold( appBar: PreferredSize( preferredSize: const Size.fromHeight(90.0), diff --git a/mobile/lib/ui/viewer/search/result/search_thumbnail_widget.dart b/mobile/lib/ui/viewer/search/result/search_thumbnail_widget.dart index aa0b6dc6d0..913ff1d52e 100644 --- a/mobile/lib/ui/viewer/search/result/search_thumbnail_widget.dart +++ b/mobile/lib/ui/viewer/search/result/search_thumbnail_widget.dart @@ -6,13 +6,11 @@ import "package:photos/models/search/generic_search_result.dart"; import "package:photos/models/search/search_constants.dart"; import "package:photos/models/search/search_result.dart"; import "package:photos/models/search/search_types.dart"; -import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; import "package:photos/theme/ente_theme.dart"; -import "package:photos/ui/common/loading_widget.dart"; import "package:photos/ui/sharing/user_avator_widget.dart"; import 'package:photos/ui/viewer/file/no_thumbnail_widget.dart'; import 'package:photos/ui/viewer/file/thumbnail_widget.dart'; -import 'package:photos/ui/viewer/search/result/person_face_widget.dart'; +import 'package:photos/ui/viewer/people/person_face_widget.dart'; class SearchThumbnailWidget extends StatelessWidget { final EnteFile? file; @@ -34,12 +32,11 @@ class SearchThumbnailWidget extends StatelessWidget { height: 60, width: 60, child: ClipRRect( - borderRadius: const BorderRadius.horizontal(left: Radius.circular(4)), + borderRadius: BorderRadius.circular(4), child: file != null ? (searchResult != null && searchResult!.type() == ResultType.faces) ? PersonFaceWidget( - file!, personId: (searchResult as GenericSearchResult) .params[kPersonParamID], clusterID: (searchResult as GenericSearchResult) @@ -73,7 +70,7 @@ class ContactSearchThumbnailWidget extends StatefulWidget { class _ContactSearchThumbnailWidgetState extends State { - Future? _mostRecentFileOfPerson; + bool _canUsePersonFaceWidget = true; late String? _personID; late String _email; final _logger = Logger("_ContactSearchThumbnailWidgetState"); @@ -83,16 +80,7 @@ class _ContactSearchThumbnailWidgetState super.initState(); _personID = widget.searchResult.params[kPersonParamID]; _email = widget.searchResult.params[kContactEmail]; - if (_personID != null) { - _mostRecentFileOfPerson = - PersonService.instance.getPerson(_personID!).then((person) { - if (person == null) { - return null; - } else { - return PersonService.instance.getThumbnailFileOfPerson(person); - } - }); - } + _canUsePersonFaceWidget = _personID != null; } @override @@ -102,37 +90,17 @@ class _ContactSearchThumbnailWidgetState width: 60, child: ClipRRect( borderRadius: const BorderRadius.horizontal(left: Radius.circular(4)), - child: _mostRecentFileOfPerson != null - ? FutureBuilder( - future: _mostRecentFileOfPerson, - builder: (context, snapshot) { - if (snapshot.hasData) { - return PersonFaceWidget( - snapshot.data!, - personId: _personID, - onErrorCallback: () { - if (mounted) { - setState(() { - _mostRecentFileOfPerson = null; - }); - } - }, - ); - } else if (snapshot.connectionState == ConnectionState.done && - snapshot.data == null) { - return NoFaceForContactWidget( - user: User(email: _email), - ); - } else if (snapshot.hasError) { + child: _canUsePersonFaceWidget + ? PersonFaceWidget( + personId: _personID, + onErrorCallback: () { + if (mounted) { _logger.severe( - "Error loading personID", - snapshot.error, + "Failed to load face for person with ID: $_personID", ); - return NoFaceForContactWidget( - user: User(email: _email), - ); - } else { - return const EnteLoadingWidget(); + setState(() { + _canUsePersonFaceWidget = false; + }); } }, ) diff --git a/mobile/lib/ui/viewer/search/result/searchable_item.dart b/mobile/lib/ui/viewer/search/result/searchable_item.dart index a78d1292f1..7d2a4eb1ef 100644 --- a/mobile/lib/ui/viewer/search/result/searchable_item.dart +++ b/mobile/lib/ui/viewer/search/result/searchable_item.dart @@ -64,7 +64,7 @@ class SearchableItemWidget extends StatelessWidget { decoration: BoxDecoration( border: Border.all(color: colorScheme.strokeFainter), borderRadius: const BorderRadius.all( - Radius.circular(4), + Radius.circular(6), ), ), child: Row( diff --git a/mobile/lib/ui/viewer/search/search_widget.dart b/mobile/lib/ui/viewer/search/search_widget.dart index 1461d37f99..ec297ce0a7 100644 --- a/mobile/lib/ui/viewer/search/search_widget.dart +++ b/mobile/lib/ui/viewer/search/search_widget.dart @@ -114,7 +114,7 @@ class SearchWidgetState extends State { isLoading.value = true; _debouncer.run(() async { if (mounted) { - query = textController.text; + query = textController.text.trim(); IndexOfStackNotifier().isSearchQueryEmpty = query.isEmpty; searchResultsStreamNotifier.value = _getSearchResultsStream(context, query); diff --git a/mobile/lib/ui/viewer/search_tab/albums_section.dart b/mobile/lib/ui/viewer/search_tab/albums_section.dart index 856afc8417..ffd4f7bbe7 100644 --- a/mobile/lib/ui/viewer/search_tab/albums_section.dart +++ b/mobile/lib/ui/viewer/search_tab/albums_section.dart @@ -1,7 +1,6 @@ import "dart:async"; import "package:dotted_border/dotted_border.dart"; -import "package:figma_squircle/figma_squircle.dart"; import "package:flutter/material.dart"; import "package:photos/core/constants.dart"; import "package:photos/events/event.dart"; @@ -156,9 +155,8 @@ class AlbumRecommendation extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ClipSmoothRect( - radius: - SmoothBorderRadius(cornerRadius: 2.35, cornerSmoothing: 1), + ClipRRect( + borderRadius: BorderRadius.circular(8), child: SizedBox( width: _width, height: 100, @@ -171,10 +169,12 @@ class AlbumRecommendation extends StatelessWidget { shouldShowSyncStatus: false, ), ) - : const NoThumbnailWidget(), + : const NoThumbnailWidget( + borderRadius: 8, + ), ), ), - const SizedBox(height: 2), + const SizedBox(height: 6), ConstrainedBox( constraints: const BoxConstraints(maxWidth: _width), child: Column( @@ -187,7 +187,7 @@ class AlbumRecommendation extends StatelessWidget { maxLines: 1, overflow: TextOverflow.ellipsis, ), - const SizedBox(height: 3), + const SizedBox(height: 2), FutureBuilder( future: CollectionsService.instance.getFileCount( albumSearchResult.collectionWithThumbnail.collection, @@ -198,7 +198,7 @@ class AlbumRecommendation extends StatelessWidget { snapshot.data != 0) { return Text( snapshot.data.toString(), - style: enteTextTheme.smallMuted, + style: enteTextTheme.miniMuted, ); } else { return const SizedBox.shrink(); @@ -228,20 +228,28 @@ class AlbumCTA extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - DottedBorder( - borderType: BorderType.RRect, - strokeWidth: 1.5, - borderPadding: const EdgeInsets.all(0.75), - dashPattern: const [3.75, 3.75], - radius: const Radius.circular(2.35), - padding: EdgeInsets.zero, - color: enteColorScheme.strokeFaint, - child: SizedBox( + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Container( + color: Theme.of(context).brightness == Brightness.light + ? enteColorScheme.backdropBase + : enteColorScheme.backdropFaint, height: 100, width: 100, - child: Icon( - Icons.add, + child: DottedBorder( + borderType: BorderType.RRect, + strokeWidth: 1.5, + borderPadding: const EdgeInsets.all(0.75), + dashPattern: const [3.75, 3.75], + radius: const Radius.circular(8), + padding: EdgeInsets.zero, color: enteColorScheme.strokeFaint, + child: Center( + child: Icon( + Icons.add, + color: enteColorScheme.strokeFaint, + ), + ), ), ), ), diff --git a/mobile/lib/ui/viewer/search_tab/contacts_section.dart b/mobile/lib/ui/viewer/search_tab/contacts_section.dart index bc751fbfa4..ecf5dd7375 100644 --- a/mobile/lib/ui/viewer/search_tab/contacts_section.dart +++ b/mobile/lib/ui/viewer/search_tab/contacts_section.dart @@ -7,20 +7,18 @@ import "package:photos/core/constants.dart"; import "package:photos/events/event.dart"; import "package:photos/generated/l10n.dart"; import "package:photos/models/api/collection/user.dart"; -import "package:photos/models/file/file.dart"; import "package:photos/models/search/generic_search_result.dart"; import "package:photos/models/search/recent_searches.dart"; import "package:photos/models/search/search_constants.dart"; import "package:photos/models/search/search_types.dart"; -import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; import "package:photos/theme/ente_theme.dart"; -import "package:photos/ui/common/loading_widget.dart"; import "package:photos/ui/sharing/user_avator_widget.dart"; +import "package:photos/ui/viewer/people/person_face_widget.dart"; import "package:photos/ui/viewer/search/result/contact_result_page.dart"; -import "package:photos/ui/viewer/search/result/person_face_widget.dart"; import "package:photos/ui/viewer/search/search_section_cta.dart"; import "package:photos/ui/viewer/search_tab/section_header.dart"; import "package:photos/utils/navigation_util.dart"; +import "package:photos/utils/standalone/debouncer.dart"; class ContactsSection extends StatefulWidget { final List contactSearchResults; @@ -33,6 +31,9 @@ class ContactsSection extends StatefulWidget { class _ContactsSectionState extends State { late List _contactSearchResults; final streamSubscriptions = []; + final _debouncer = Debouncer( + const Duration(milliseconds: 1500), + ); @override void initState() { @@ -43,11 +44,13 @@ class _ContactsSectionState extends State { for (Stream stream in streamsToListenTo) { streamSubscriptions.add( stream.listen((event) async { - _contactSearchResults = (await SectionType.contacts.getData( - context, - limit: kSearchSectionLimit, - )) as List; - setState(() {}); + _debouncer.run(() async { + _contactSearchResults = (await SectionType.contacts.getData( + context, + limit: kSearchSectionLimit, + )) as List; + setState(() {}); + }); }), ); } @@ -58,6 +61,7 @@ class _ContactsSectionState extends State { for (var subscriptions in streamSubscriptions) { subscriptions.cancel(); } + _debouncer.cancelDebounceTimer(); super.dispose(); } @@ -149,7 +153,7 @@ class ContactRecommendation extends StatefulWidget { } class _ContactRecommendationState extends State { - Future? _mostRecentFileOfPerson; + bool _canUsePersonFaceWidget = true; late String? _personID; final _logger = Logger("_ContactRecommendationState"); @@ -157,16 +161,7 @@ class _ContactRecommendationState extends State { void initState() { super.initState(); _personID = widget.contactSearchResult.params[kPersonParamID]; - if (_personID != null) { - _mostRecentFileOfPerson = - PersonService.instance.getPerson(_personID!).then((person) { - if (person == null) { - return null; - } else { - return PersonService.instance.getThumbnailFileOfPerson(person); - } - }); - } + _canUsePersonFaceWidget = _personID != null; } @override @@ -203,44 +198,17 @@ class _ContactRecommendationState extends State { child: SizedBox( width: 67.75, height: 67.75, - child: _mostRecentFileOfPerson != null - ? FutureBuilder( - future: _mostRecentFileOfPerson, - builder: (context, snapshot) { - if (snapshot.hasData) { - return PersonFaceWidget( - snapshot.data!, - personId: _personID, - onErrorCallback: () { - if (mounted) { - setState(() { - _mostRecentFileOfPerson = null; - }); - } - }, - ); - } else if (snapshot.connectionState == - ConnectionState.done && - snapshot.data == null) { - return FirstLetterUserAvatar( - User( - email: widget.contactSearchResult - .params[kContactEmail], - ), - ); - } else if (snapshot.hasError) { + child: _canUsePersonFaceWidget + ? PersonFaceWidget( + personId: _personID, + onErrorCallback: () { + if (mounted) { _logger.severe( - "Error loading personID", - snapshot.error, + "Failed to load face for person with ID: $_personID", ); - return FirstLetterUserAvatar( - User( - email: widget.contactSearchResult - .params[kContactEmail], - ), - ); - } else { - return const EnteLoadingWidget(); + setState(() { + _canUsePersonFaceWidget = false; + }); } }, ) diff --git a/mobile/lib/ui/viewer/search_tab/people_section.dart b/mobile/lib/ui/viewer/search_tab/people_section.dart index b90b5d1efa..5641710616 100644 --- a/mobile/lib/ui/viewer/search_tab/people_section.dart +++ b/mobile/lib/ui/viewer/search_tab/people_section.dart @@ -3,10 +3,10 @@ import "dart:async"; import "package:flutter/material.dart"; import "package:photos/core/constants.dart"; import "package:photos/events/event.dart"; +import "package:photos/generated/l10n.dart"; import "package:photos/models/file/file.dart"; import "package:photos/models/ml/face/person.dart"; import "package:photos/models/search/generic_search_result.dart"; -import "package:photos/models/search/hierarchical/face_filter.dart"; import "package:photos/models/search/recent_searches.dart"; import "package:photos/models/search/search_constants.dart"; import "package:photos/models/search/search_result.dart"; @@ -18,8 +18,8 @@ import "package:photos/ui/viewer/file/no_thumbnail_widget.dart"; import "package:photos/ui/viewer/file/thumbnail_widget.dart"; import "package:photos/ui/viewer/people/add_person_action_sheet.dart"; import "package:photos/ui/viewer/people/people_page.dart"; +import 'package:photos/ui/viewer/people/person_face_widget.dart'; import "package:photos/ui/viewer/search/result/people_section_all_page.dart"; -import 'package:photos/ui/viewer/search/result/person_face_widget.dart'; import "package:photos/ui/viewer/search/result/search_result_page.dart"; import "package:photos/ui/viewer/search/search_section_cta.dart"; import "package:photos/utils/navigation_util.dart"; @@ -52,12 +52,10 @@ class _PeopleSectionState extends State { for (Stream stream in streamsToListenTo) { streamSubscriptions.add( stream.listen((event) async { - _examples = await widget.sectionType - .getData( - context, - limit: kSearchSectionLimit, - ) - .then((value) => List.from(value)); + _examples = await widget.sectionType.getData( + context, + limit: kSearchSectionLimit, + ) as List; setState(() {}); }), ); @@ -203,9 +201,8 @@ class PersonSearchExample extends StatelessWidget { }); void toggleSelection() { - selectedPeople?.toggleSelection( - (searchResult.hierarchicalSearchFilter as FaceFilter).personId!, - ); + selectedPeople + ?.toggleSelection(searchResult.params[kPersonParamID]! as String); } @override @@ -218,9 +215,9 @@ class PersonSearchExample extends StatelessWidget { return ListenableBuilder( listenable: selectedPeople ?? ValueNotifier(false), builder: (context, _) { - final filter = (searchResult.hierarchicalSearchFilter as FaceFilter); - final id = filter.personId ?? filter.clusterId ?? ""; - final bool isSelected = selectedPeople?.isPersonSelected(id) ?? false; + final id = searchResult.params[kPersonParamID] as String?; + final bool isSelected = + id != null ? selectedPeople?.isPersonSelected(id) ?? false : false; return GestureDetector( onTap: selectedPeople != null @@ -350,7 +347,7 @@ class PersonSearchExample extends StatelessWidget { child: Padding( padding: const EdgeInsets.only(top: 6, bottom: 0), child: Text( - "Add name", + S.of(context).addName, maxLines: 1, textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, @@ -360,12 +357,15 @@ class PersonSearchExample extends StatelessWidget { ) : Padding( padding: const EdgeInsets.only(top: 6, bottom: 0), - child: Text( - searchResult.name(), - maxLines: 1, - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - style: getEnteTextTheme(context).small, + child: SizedBox( + width: size, + child: Text( + searchResult.name(), + maxLines: 1, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + style: getEnteTextTheme(context).small, + ), ), ), ], @@ -385,12 +385,11 @@ class FaceSearchResult extends StatelessWidget { Widget build(BuildContext context) { final params = (searchResult as GenericSearchResult).params; return PersonFaceWidget( - searchResult.previewThumbnail()!, personId: params[kPersonParamID], clusterID: params[kClusterParamId], key: params.containsKey(kPersonWidgetKey) ? ValueKey(params[kPersonWidgetKey]) - : null, + : ValueKey(params[kPersonParamID] ?? params[kClusterParamId]), ); } } diff --git a/mobile/lib/utils/auth_util.dart b/mobile/lib/utils/auth_util.dart index f25aff58b7..de20a9198d 100644 --- a/mobile/lib/utils/auth_util.dart +++ b/mobile/lib/utils/auth_util.dart @@ -46,6 +46,7 @@ Future requestAuthentication( signInTitle: S.of(context).androidSignInTitle, ), IOSAuthMessages( + localizedFallbackTitle: S.of(context).enterPassword, goToSettingsButton: S.of(context).goToSettings, goToSettingsDescription: S.of(context).goToSettings, lockOut: S.of(context).iOSLockOut, diff --git a/mobile/lib/utils/bg_task_utils.dart b/mobile/lib/utils/bg_task_utils.dart new file mode 100644 index 0000000000..573996625a --- /dev/null +++ b/mobile/lib/utils/bg_task_utils.dart @@ -0,0 +1,106 @@ +import "dart:io"; + +import "package:logging/logging.dart"; +import "package:permission_handler/permission_handler.dart"; +import "package:photos/db/upload_locks_db.dart"; +import "package:photos/extensions/stop_watch.dart"; +import "package:photos/main.dart"; +import "package:photos/utils/file_uploader.dart"; +import "package:shared_preferences/shared_preferences.dart"; +import "package:workmanager/workmanager.dart" as workmanager; + +@pragma('vm:entry-point') +void callbackDispatcher() { + workmanager.Workmanager().executeTask((taskName, inputData) async { + final TimeLogger tlog = TimeLogger(); + Future result = Future.error("Task didn't run"); + final prefs = await SharedPreferences.getInstance(); + + await runWithLogs( + () async { + try { + BgTaskUtils.$.info('Task started $tlog'); + await runBackgroundTask(taskName, tlog).timeout( + Platform.isIOS ? kBGTaskTimeout : const Duration(hours: 1), + onTimeout: () async { + BgTaskUtils.$.warning( + "TLE, committing seppuku for taskID: $taskName", + ); + await BgTaskUtils.releaseResourcesForKill(taskName, prefs); + }, + ); + BgTaskUtils.$.info('Task run successful $tlog'); + result = Future.value(true); + } catch (e) { + BgTaskUtils.$.warning('Task error: $e'); + await BgTaskUtils.releaseResourcesForKill(taskName, prefs); + result = Future.error(e.toString()); + } + }, + prefix: "[bg]", + ).onError((_, __) { + result = Future.error("Didn't finished correctly!"); + return; + }); + + return result; + }); +} + +class BgTaskUtils { + static final $ = Logger("BgTaskUtils"); + + static Future releaseResourcesForKill( + String taskId, + SharedPreferences prefs, + ) async { + await UploadLocksDB.instance.releaseLocksAcquiredByOwnerBefore( + ProcessType.background.toString(), + DateTime.now().microsecondsSinceEpoch, + ); + await prefs.remove(kLastBGTaskHeartBeatTime); + } + + static Future configureWorkmanager() async { + if (Platform.isIOS) { + final status = await Permission.backgroundRefresh.status; + if (status != PermissionStatus.granted) { + $.warning( + "Background refresh permission is not granted. Please grant it to start the background service.", + ); + return; + } + } + $.warning("Configuring Work Manager for background tasks"); + const iOSBackgroundAppRefresh = "io.ente.frame.iOSBackgroundAppRefresh"; + const androidPeriodicTask = "io.ente.photos.androidPeriodicTask"; + final backgroundTaskIdentifier = + Platform.isIOS ? iOSBackgroundAppRefresh : androidPeriodicTask; + try { + await workmanager.Workmanager().initialize( + callbackDispatcher, + isInDebugMode: false, + ); + await workmanager.Workmanager().registerPeriodicTask( + backgroundTaskIdentifier, + backgroundTaskIdentifier, + frequency: Platform.isIOS + ? const Duration(minutes: 30) + : const Duration(minutes: 15), + initialDelay: const Duration(minutes: 10), + constraints: workmanager.Constraints( + networkType: workmanager.NetworkType.connected, + requiresCharging: false, + requiresStorageNotLow: false, + requiresDeviceIdle: false, + ), + existingWorkPolicy: workmanager.ExistingWorkPolicy.append, + backoffPolicy: workmanager.BackoffPolicy.linear, + backoffPolicyDelay: const Duration(minutes: 15), + ); + $.info("WorkManager configured"); + } catch (e) { + $.warning("Failed to configure WorkManager: $e"); + } + } +} diff --git a/mobile/lib/utils/cache_util.dart b/mobile/lib/utils/cache_util.dart new file mode 100644 index 0000000000..a648d9df0a --- /dev/null +++ b/mobile/lib/utils/cache_util.dart @@ -0,0 +1,98 @@ +import "dart:convert" show utf8; +import "dart:developer" show log; +import "dart:io"; + +import "package:computer/computer.dart"; +import "package:logging/logging.dart"; + +final _computer = Computer.shared(); + +final _logger = Logger("CacheUtil"); + +/// Writes data to a JSON file at the specified path using the provided method, inside computer. +/// The method should convert the data to a JSON string. +/// The JSON string is then UTF-8 encoded and written to the file. +Future writeToJsonFile

( + String filePath, + P data, + String Function(P) toJsonString, +) async { + final args = { + "filePath": filePath, + "data": data, + "toJsonString": toJsonString, + }; + await _computer.compute, void>( + _writeToJsonFile

, + param: args, + taskName: "writeToJsonFile", + ); +} + +Future _writeToJsonFile

(Map args) async { + try { + final file = File(args["filePath"] as String); + if (!file.existsSync()) { + file.createSync(recursive: true); + } + final toJsonStringMethod = args["toJsonString"] as String Function(P); + final jsonString = toJsonStringMethod(args["data"] as P); + final encodedData = utf8.encode(jsonString); + await file.writeAsBytes(encodedData); + } catch (e, s) { + log("Error writing to JSON file with UTF-8 encoding, $e, \n $s"); + } +} + +/// Reads a JSON file from the specified path using the provided method, inside computer. +/// The method should decode the JSON string into an object. +/// The JSON string is expected to be UTF-8 encoded. +Future decodeJsonFile

( + String filePath, + P Function(String) jsonDecodeMethod, +) async { + final args = { + "filePath": filePath, + "jsonDecode": jsonDecodeMethod, + }; + final cache = await _computer.compute, P?>( + _decodeJsonFile

, + param: args, + taskName: "decodeJsonFile", + ); + if (cache == null) { + _logger.warning("Failed to decode JSON file at $filePath"); + } else { + _logger.info("Successfully decoded JSON file at $filePath"); + } + return cache; +} + +Future _decodeJsonFile

(Map args) async { + final file = File(args["filePath"] as String); + if (!file.existsSync()) { + log("File does not exist: ${args["filePath"]}"); + return null; + } + try { + final bytes = await file.readAsBytes(); + final jsonDecodeMethod = args["jsonDecode"] as P Function(String); + P decodedData; + try { + final jsonString = utf8.decode(bytes); + decodedData = jsonDecodeMethod(jsonString); + log("Successfully decoded JSON file as UTF-8"); + } catch (e, s) { + log("Failed to decode bytes as UTF-8, trying UTF-16 $e \n $s"); + final jsonString = + String.fromCharCodes(bytes); // Fallback to UTF-16 decoding + decodedData = jsonDecodeMethod(jsonString); + log("Successfully decoded JSON file as UTF-16"); + } + return decodedData; + } catch (e, s) { + log("Error decoding JSON file, deleting this cache $e, \n $s"); + await file.delete(); + return null; + } +} diff --git a/mobile/lib/utils/exif_util.dart b/mobile/lib/utils/exif_util.dart index 086a11e28b..f6d3363614 100644 --- a/mobile/lib/utils/exif_util.dart +++ b/mobile/lib/utils/exif_util.dart @@ -3,7 +3,7 @@ import "dart:developer"; import "dart:io"; import "package:computer/computer.dart"; -import 'package:exif/exif.dart'; +import 'package:exif_reader/exif_reader.dart'; import "package:ffmpeg_kit_flutter/ffprobe_kit.dart"; import "package:ffmpeg_kit_flutter/media_information.dart"; import "package:ffmpeg_kit_flutter/media_information_session.dart"; diff --git a/mobile/lib/utils/face/face_box_crop.dart b/mobile/lib/utils/face/face_thumbnail_cache.dart similarity index 66% rename from mobile/lib/utils/face/face_box_crop.dart rename to mobile/lib/utils/face/face_thumbnail_cache.dart index ced0c84d08..117793173f 100644 --- a/mobile/lib/utils/face/face_box_crop.dart +++ b/mobile/lib/utils/face/face_thumbnail_cache.dart @@ -20,8 +20,11 @@ import "package:photos/utils/thumbnail_util.dart"; final _logger = Logger("FaceCropUtils"); const int _retryLimit = 3; -final LRUMap _faceCropCache = LRUMap(1000); -final LRUMap _faceCropThumbnailCache = LRUMap(1000); +final LRUMap _faceCropCache = LRUMap(100); +final LRUMap _faceCropThumbnailCache = LRUMap(100); + +final LRUMap _personOrClusterIdToCachedFaceID = LRUMap(2000); + TaskQueue _queueFullFileFaceGenerations = TaskQueue( maxConcurrentTasks: 5, taskTimeout: const Duration(minutes: 1), @@ -33,37 +36,113 @@ TaskQueue _queueThumbnailFaceGenerations = TaskQueue( maxQueueSize: 100, ); -Future checkGetCachedCropForFaceID(String faceID) async { +Uint8List? checkInMemoryCachedCropForPersonOrClusterID( + String personOrClusterID, +) { + final String? faceID = + _personOrClusterIdToCachedFaceID.get(personOrClusterID); + if (faceID == null) return null; final Uint8List? cachedCover = _faceCropCache.get(faceID); return cachedCover; } -Future putCachedCropForFaceID( - String faceID, - Uint8List data, -) async { - _faceCropCache.put(faceID, data); +Uint8List? _checkInMemoryCachedCropForFaceID(String faceID) { + final Uint8List? cachedCover = _faceCropCache.get(faceID); + return cachedCover; } +Future checkUsedFaceIDForPersonOrClusterId( + String personOrClusterID, +) async { + final String? cachedFaceID = + _personOrClusterIdToCachedFaceID.get(personOrClusterID); + if (cachedFaceID != null) return cachedFaceID; + final String? faceIDFromDB = await MLDataDB.instance + .getFaceIdUsedForPersonOrCluster(personOrClusterID); + if (faceIDFromDB != null) { + _personOrClusterIdToCachedFaceID.put(personOrClusterID, faceIDFromDB); + } + return faceIDFromDB; +} + +Future putFaceIdCachedForPersonOrCluster( + String personOrClusterID, + String faceID, +) async { + await MLDataDB.instance.putFaceIdCachedForPersonOrCluster( + personOrClusterID, + faceID, + ); + _personOrClusterIdToCachedFaceID.put(personOrClusterID, faceID); +} + +Future _putCachedCropForFaceID( + String faceID, + Uint8List data, [ + String? personOrClusterID, +]) async { + _faceCropCache.put(faceID, data); + if (personOrClusterID != null) { + await putFaceIdCachedForPersonOrCluster(personOrClusterID, faceID); + } +} + +Future checkRemoveCachedFaceIDForPersonOrClusterId( + String personOrClusterID, +) async { + final String? cachedFaceID = await MLDataDB.instance + .getFaceIdUsedForPersonOrCluster(personOrClusterID); + if (cachedFaceID != null) { + _personOrClusterIdToCachedFaceID.remove(personOrClusterID); + await MLDataDB.instance + .removeFaceIdCachedForPersonOrCluster(personOrClusterID); + } +} + +/// Careful to only use [personOrClusterID] if all [faces] are from the same person or cluster. Future?> getCachedFaceCrops( EnteFile enteFile, Iterable faces, { int fetchAttempt = 1, bool useFullFile = true, + String? personOrClusterID, + required bool useTempCache, }) async { try { final faceIdToCrop = {}; final facesWithoutCrops = {}; for (final face in faces) { - final Uint8List? cachedFace = _faceCropCache.get(face.faceID); + final Uint8List? cachedFace = + _checkInMemoryCachedCropForFaceID(face.faceID); if (cachedFace != null) { faceIdToCrop[face.faceID] = cachedFace; } else { - final faceCropCacheFile = cachedFaceCropPath(face.faceID); + final faceCropCacheFile = cachedFaceCropPath(face.faceID, useTempCache); if ((await faceCropCacheFile.exists())) { - final data = await faceCropCacheFile.readAsBytes(); - _faceCropCache.put(face.faceID, data); - faceIdToCrop[face.faceID] = data; + try { + final data = await faceCropCacheFile.readAsBytes(); + if (data.isNotEmpty) { + await _putCachedCropForFaceID( + face.faceID, + data, + personOrClusterID, + ); + faceIdToCrop[face.faceID] = data; + } else { + _logger.warning( + "Cached face crop for faceID ${face.faceID} is empty, deleting file ${faceCropCacheFile.path}", + ); + await faceCropCacheFile.delete(); + facesWithoutCrops[face.faceID] = face.detection.box; + } + } catch (e, s) { + _logger.severe( + "Error reading cached face crop for faceID ${face.faceID} from file ${faceCropCacheFile.path}", + e, + s, + ); + facesWithoutCrops[face.faceID] = face.detection.box; + } } else { facesWithoutCrops[face.faceID] = face.detection.box; } @@ -102,9 +181,22 @@ Future?> getCachedFaceCrops( if (computedCrop != null) { faceIdToCrop[entry.key] = computedCrop; if (useFullFile) { - _faceCropCache.put(entry.key, computedCrop); - final faceCropCacheFile = cachedFaceCropPath(entry.key); - faceCropCacheFile.writeAsBytes(computedCrop).ignore(); + await _putCachedCropForFaceID( + entry.key, + computedCrop, + personOrClusterID, + ); + final faceCropCacheFile = cachedFaceCropPath(entry.key, useTempCache); + try { + // ignore: unawaited_futures + faceCropCacheFile.writeAsBytes(computedCrop); + } catch (e, s) { + _logger.severe( + "Error writing cached face crop for faceID ${entry.key} to file ${faceCropCacheFile.path}", + e, + s, + ); + } } else { _faceCropThumbnailCache.put(entry.key, computedCrop); } @@ -130,6 +222,7 @@ Future?> getCachedFaceCrops( faces, fetchAttempt: fetchAttempt + 1, useFullFile: useFullFile, + useTempCache: useTempCache, ); } _logger.severe( @@ -177,6 +270,7 @@ Future precomputeClusterFaceCrop( fileForFaceCrop, [face], useFullFile: useFullFile, + useTempCache: true, ); w?.logAndReset('getCachedFaceCrops'); return cropMap?[face.faceID]; @@ -191,11 +285,10 @@ Future precomputeClusterFaceCrop( } void checkStopTryingToGenerateFaceThumbnails( - EnteFile file, { + int fileID, { bool useFullFile = true, }) { - final taskId = - [file.uploadedFileID!, useFullFile ? "-full" : "-thumbnail"].join(); + final taskId = [fileID, useFullFile ? "-full" : "-thumbnail"].join(); if (useFullFile) { _queueFullFileFaceGenerations.removeTask(taskId); } else { diff --git a/mobile/lib/utils/file_download_util.dart b/mobile/lib/utils/file_download_util.dart index ed7909247a..3fea091fce 100644 --- a/mobile/lib/utils/file_download_util.dart +++ b/mobile/lib/utils/file_download_util.dart @@ -16,6 +16,8 @@ import 'package:photos/models/file/file.dart'; import "package:photos/models/file/file_type.dart"; import "package:photos/models/ignored_file.dart"; import "package:photos/module/download/file_url.dart"; +import "package:photos/module/download/task.dart"; +import "package:photos/service_locator.dart"; import "package:photos/services/collections_service.dart"; import "package:photos/services/ignored_files_service.dart"; import "package:photos/services/sync/local_sync_service.dart"; @@ -27,8 +29,7 @@ import "package:photos/utils/standalone/fake_progress.dart"; final _logger = Logger("file_download_util"); Future downloadAndDecryptPublicFile( - EnteFile file, - String authToken, { + EnteFile file, { ProgressCallback? progressCallback, }) async { final String logPrefix = 'Public File-${file.uploadedFileID}:'; @@ -40,13 +41,8 @@ Future downloadAndDecryptPublicFile( final String decryptedFilePath = "$tempDir${file.uploadedFileID}.decrypted"; try { - final authJWTToken = await CollectionsService.instance - .getSharedPublicAlbumTokenJWT(file.collectionID!); - - final headers = { - "X-Auth-Access-Token": authToken, - if (authJWTToken != null) "X-Auth-Access-Token-JWT": authJWTToken, - }; + final headers = + CollectionsService.instance.publicCollectionHeaders(file.collectionID!); final response = (await NetworkClient.instance.getDio().download( FileUrl.getUrl(file.uploadedFileID!, FileUrlType.publicDownload), encryptedFilePath, @@ -100,12 +96,8 @@ Future downloadAndDecrypt( ProgressCallback? progressCallback, }) async { if (CollectionsService.instance.isSharedPublicLink(file.collectionID!)) { - final authToken = await CollectionsService.instance - .getSharedPublicAlbumToken(file.collectionID!); - return await downloadAndDecryptPublicFile( file, - authToken!, progressCallback: progressCallback, ); } @@ -114,30 +106,48 @@ Future downloadAndDecrypt( _logger .info('$logPrefix starting download ${formatBytes(file.fileSize ?? 0)}'); final String tempDir = Configuration.instance.getTempDirectory(); - final String encryptedFilePath = "$tempDir${file.generatedID}.encrypted"; - final encryptedFile = File(encryptedFilePath); + String encryptedFilePath = "$tempDir${file.generatedID}.encrypted"; + File encryptedFile = File(encryptedFilePath); final startTime = DateTime.now().millisecondsSinceEpoch; try { - final response = await NetworkClient.instance.getDio().download( - file.downloadUrl, - encryptedFilePath, - options: Options( - headers: {"X-Auth-Token": Configuration.instance.getToken()}, - ), - onReceiveProgress: (a, b) { - if (kDebugMode && a >= 0 && b >= 0) { - // _logger.fine( - // "$logPrefix download progress: ${formatBytes(a)} / ${formatBytes(b)}", - // ); - } - progressCallback?.call(a, b); - }, - ); - if (response.statusCode != 200 || !encryptedFile.existsSync()) { - _logger.warning('$logPrefix download failed ${response.toString()}'); - return null; + if (downloadManager.enableResumableDownload(file.fileSize)) { + final DownloadResult result = await downloadManager.download( + file.uploadedFileID!, + file.displayName, + file.fileSize!, + ); + if (result.success) { + encryptedFilePath = result.task.filePath!; + encryptedFile = File(encryptedFilePath); + } else { + _logger.warning( + '$logPrefix download failed ${result.task.error} ${result.task.status}', + ); + return null; + } + } else { + // If the file is small, download it directly to the final location + final response = await NetworkClient.instance.getDio().download( + file.downloadUrl, + encryptedFilePath, + options: Options( + headers: {"X-Auth-Token": Configuration.instance.getToken()}, + ), + onReceiveProgress: (a, b) { + if (kDebugMode && a >= 0 && b >= 0) { + // _logger.info( + // "$logPrefix download progress: ${formatBytes(a)} / ${formatBytes(b)}", + // ); + } + progressCallback?.call(a, b); + }, + ); + if (response.statusCode != 200 || !encryptedFile.existsSync()) { + _logger.warning('$logPrefix download failed ${response.toString()}'); + return null; + } } final int sizeInBytes = file.fileSize ?? await encryptedFile.length(); diff --git a/mobile/lib/utils/file_uploader.dart b/mobile/lib/utils/file_uploader.dart index 14e4361798..9bb28eeee4 100644 --- a/mobile/lib/utils/file_uploader.dart +++ b/mobile/lib/utils/file_uploader.dart @@ -36,7 +36,6 @@ import "package:photos/module/upload/service/multipart.dart"; import "package:photos/service_locator.dart"; import "package:photos/services/account/user_service.dart"; import 'package:photos/services/collections_service.dart'; -import "package:photos/services/preview_video_store.dart"; import 'package:photos/services/sync/local_sync_service.dart'; import 'package:photos/services/sync/sync_service.dart'; import "package:photos/utils/exif_util.dart"; @@ -54,7 +53,7 @@ class FileUploader { static const kMaximumConcurrentVideoUploads = 2; static const kMaximumThumbnailCompressionAttempts = 2; static const kMaximumUploadAttempts = 4; - static const kMaxFileSize5Gib = 5368709120; + static const kMaxFileSize10Gib = 10737418240; static const kBlockedUploadsPollFrequency = Duration(seconds: 2); static const kFileUploadTimeout = Duration(minutes: 50); static const k20MBStorageBuffer = 20 * 1024 * 1024; @@ -99,8 +98,6 @@ class FileUploader { static FileUploader instance = FileUploader._privateConstructor(); - static final _previewVideoStore = PreviewVideoStore.instance; - Future init(SharedPreferences preferences, bool isBackground) async { _prefs = preferences; _processType = @@ -472,14 +469,6 @@ class FileUploader { } } - void _uploadPreview(EnteFile file) { - if (file.fileType == FileType.video) { - unawaited( - _previewVideoStore.chunkAndUploadVideo(null, file), - ); - } - } - Future _tryToUpload( EnteFile file, int collectionID, @@ -670,7 +659,7 @@ class FileUploader { encThumbSize = await encryptedThumbnailFile.length(); // Calculate the number of parts for the file. - final count = await _multiPartUploader.calculatePartCount(encFileSize); + final count = _multiPartUploader.calculatePartCount(encFileSize); late String fileObjectKey; late String thumbnailObjectKey; @@ -687,7 +676,7 @@ class FileUploader { await _putFile(fileUploadURL, encryptedFile, encFileSize); } else { isMultipartUpload = true; - _logger.finest( + _logger.info( "Init multipartUpload $multipartEntryExists, isUpdate $isUpdatedFile", ); if (multipartEntryExists) { @@ -814,9 +803,6 @@ class FileUploader { } await FilesDB.instance.update(remoteFile); } - if (PreviewVideoStore.instance.isVideoStreamingEnabled) { - _uploadPreview(file); - } await UploadLocksDB.instance.deleteMultipartTrack(lockKey); Bus.instance.fire( @@ -907,12 +893,15 @@ class FileUploader { files. if the link is successful, it returns true otherwise false. When false, we should go ahead and re-upload or update the file. It performs following checks: - a) Uploaded file with same localID and destination collection. Delete the - fileToUpload entry + a) Target file with same localID and destination collection exists. Delete the + fileToUpload entry. If target file is sandbox file, then we skip localID match + check. b) Uploaded file in any collection but with missing localID. Update the localID for uploadedFile and delete the fileToUpload entry c) A uploaded file exist with same localID but in a different collection. - Add a symlink in the destination collection and update the fileToUpload + Add a symlink in the destination collection and update the fileToUpload. + If target file is sandbox file, then we skip localID match + check. d) File already exists but different localID. Re-upload In case the existing files already have local identifier, which is different from the {fileToUpload}, then most probably device has @@ -931,6 +920,7 @@ class FileUploader { ); return Tuple2(false, fileToUpload); } + final bool isSandBoxFile = fileToUpload.isSharedMediaToAppSandbox; final List existingUploadedFiles = await FilesDB.instance.getUploadedFilesWithHashes( @@ -947,12 +937,13 @@ class FileUploader { final EnteFile? sameLocalSameCollection = existingUploadedFiles.firstWhereOrNull( (e) => - e.collectionID == toCollectionID && e.localID == fileToUpload.localID, + e.collectionID == toCollectionID && + (e.localID == fileToUpload.localID || isSandBoxFile), ); if (sameLocalSameCollection != null) { - _logger.fine( - "sameLocalSameCollection: \n toUpload ${fileToUpload.tag} " - "\n existing: ${sameLocalSameCollection.tag}", + _logger.info( + "sameLocalSameCollection: toUpload ${fileToUpload.tag} " + "existing: ${sameLocalSameCollection.tag} $isSandBoxFile", ); // should delete the fileToUploadEntry if (fileToUpload.generatedID != null) { @@ -976,7 +967,7 @@ class FileUploader { if (fileMissingLocal != null) { // update the local id of the existing file and delete the fileToUpload // entry - _logger.fine( + _logger.info( "fileMissingLocal: \n toUpload ${fileToUpload.tag} " "\n existing: ${fileMissingLocal.tag}", ); @@ -1005,12 +996,13 @@ class FileUploader { final EnteFile? fileExistsButDifferentCollection = existingUploadedFiles.firstWhereOrNull( (e) => - e.collectionID != toCollectionID && e.localID == fileToUpload.localID, + e.collectionID != toCollectionID && + (e.localID == fileToUpload.localID || isSandBoxFile), ); if (fileExistsButDifferentCollection != null) { - _logger.fine( - "fileExistsButDifferentCollection: \n toUpload ${fileToUpload.tag} " - "\n existing: ${fileExistsButDifferentCollection.tag}", + _logger.info( + "fileExistsButDifferentCollection: toUpload ${fileToUpload.tag} " + "existing: ${fileExistsButDifferentCollection.tag} $isSandBoxFile", ); final linkedFile = await CollectionsService.instance .linkLocalFileToExistingUploadedFileInAnotherCollection( @@ -1026,7 +1018,7 @@ class FileUploader { ) .map((e) => e.localID!) .toSet(); - _logger.fine( + _logger.info( "Found hashMatch but probably with diff localIDs " "$matchLocalIDs", ); @@ -1057,7 +1049,7 @@ class FileUploader { } if (File(encryptedFilePath).existsSync()) { if (isMultiPartUpload && !uploadCompleted) { - _logger.fine( + _logger.info( "skip delete for multipart encrypted file $encryptedFilePath", ); } else { @@ -1094,10 +1086,10 @@ class FileUploader { 'freeStorage $freeStorage'); throw StorageLimitExceededError(); } - if (fileSize > kMaxFileSize5Gib) { - _logger.warning('File size exceeds 5GiB fileSize $fileSize'); + if (fileSize > kMaxFileSize10Gib) { + _logger.warning('File size exceeds 10GiB fileSize $fileSize'); throw InvalidFileError( - 'file size above 5GiB', + 'file size above 10GiB', InvalidReason.tooLargeFile, ); } diff --git a/mobile/lib/utils/file_uploader_util.dart b/mobile/lib/utils/file_uploader_util.dart index 5ca93defe0..ba1db4da72 100644 --- a/mobile/lib/utils/file_uploader_util.dart +++ b/mobile/lib/utils/file_uploader_util.dart @@ -7,7 +7,7 @@ import 'dart:ui' as ui; import "package:archive/archive_io.dart"; import "package:computer/computer.dart"; import 'package:ente_crypto/ente_crypto.dart'; -import "package:exif/exif.dart"; +import "package:exif_reader/exif_reader.dart"; import 'package:logging/logging.dart'; import "package:motion_photos/motion_photos.dart"; import 'package:motionphoto/motionphoto.dart'; @@ -24,6 +24,7 @@ import 'package:photos/models/file/file.dart'; import 'package:photos/models/file/file_type.dart'; import "package:photos/models/location/location.dart"; import "package:photos/models/metadata/file_magic.dart"; +import "package:photos/services/sync/local_sync_service.dart"; import "package:photos/utils/exif_util.dart"; import 'package:photos/utils/file_util.dart'; import "package:uuid/uuid.dart"; @@ -109,6 +110,9 @@ Future _getMediaUploadDataFromAssetFile( throw InvalidFileError("", InvalidReason.assetDeleted); } _assertFileType(asset, file); + if (Platform.isIOS) { + trackOriginFetchForUploadOrML.put(file.localID!, true); + } sourceFile = await asset.originFile .timeout(const Duration(seconds: 15)) .catchError((e) async { @@ -148,7 +152,7 @@ Future _getMediaUploadDataFromAssetFile( // .elp -> ente live photo final uniqueId = const Uuid().v4().toString(); final livePhotoPath = tempPath + uniqueId + "_${file.generatedID}.elp"; - _logger.fine("Creating zip for live photo from " + basename(livePhotoPath)); + _logger.info("Creating zip for live photo from " + basename(livePhotoPath)); await zip( zipPath: livePhotoPath, imagePath: sourceFile.path, diff --git a/mobile/lib/utils/file_util.dart b/mobile/lib/utils/file_util.dart index 534fb29cfc..375b53a108 100644 --- a/mobile/lib/utils/file_util.dart +++ b/mobile/lib/utils/file_util.dart @@ -218,7 +218,7 @@ Future<_LivePhoto?> _downloadLivePhoto( if (decryptedFile == null) { return null; } - _logger.fine("Decoded zipped live photo from " + decryptedFile.path); + _logger.info("Decoded zipped live photo from " + decryptedFile.path); File? imageFileCache, videoFileCache; final List bytes = await decryptedFile.readAsBytes(); final Archive archive = ZipDecoder().decodeBytes(bytes); diff --git a/mobile/lib/utils/image_ml_util.dart b/mobile/lib/utils/image_ml_util.dart index bdd84d96f1..49471ea87b 100644 --- a/mobile/lib/utils/image_ml_util.dart +++ b/mobile/lib/utils/image_ml_util.dart @@ -32,12 +32,29 @@ final List> gaussianKernel = const maxKernelSize = gaussianKernelSize; const maxKernelRadius = maxKernelSize ~/ 2; -Future<(Image, Uint8List)> decodeImageFromPath(String imagePath) async { +// Face thumbnail compression constants +const int _faceThumbnailCompressionQuality = 90; +const int _faceThumbnailMinDimension = 512; + +class DecodedImage { + final Image image; + final Uint8List? rawRgbaBytes; + + const DecodedImage(this.image, [this.rawRgbaBytes]); +} + +Future decodeImageFromPath( + String imagePath, { + required bool includeRgbaBytes, +}) async { try { final imageData = await File(imagePath).readAsBytes(); final image = await decodeImageFromData(imageData); + if (!includeRgbaBytes) { + return DecodedImage(image); + } final rawRgbaBytes = await _getRawRgbaBytes(image); - return (image, rawRgbaBytes); + return DecodedImage(image, rawRgbaBytes); } catch (e, s) { final format = imagePath.split('.').last; _logger.info( @@ -50,9 +67,12 @@ Future<(Image, Uint8List)> decodeImageFromPath(String imagePath) async { format: CompressFormat.jpeg, ); final image = await decodeImageFromData(convertedData!); - final rawRgbaBytes = await _getRawRgbaBytes(image); _logger.info('Conversion successful, jpeg decoded'); - return (image, rawRgbaBytes); + if (!includeRgbaBytes) { + return DecodedImage(image); + } + final rawRgbaBytes = await _getRawRgbaBytes(image); + return DecodedImage(image, rawRgbaBytes); } catch (e) { _logger.severe( 'Error decoding image of format $format on ${Platform.isAndroid ? "Android" : "iOS"}', @@ -122,12 +142,16 @@ Future _getByteDataFromImage( /// /// Returns a [Uint8List] image, in png format. Future> generateFaceThumbnailsUsingCanvas( - Uint8List imageData, + String imagePath, List faceBoxes, ) async { int i = 0; // Index of the faceBox, initialized here for logging purposes try { - final Image img = await decodeImageFromData(imageData); + final decodedImage = await decodeImageFromPath( + imagePath, + includeRgbaBytes: false, + ); + final Image img = decodedImage.image; final futureFaceThumbnails = >[]; for (final faceBox in faceBoxes) { // Note that the faceBox values are relative to the image size, so we need to convert them to absolute values first @@ -519,6 +543,31 @@ Future _cropAndEncodeCanvas( return await _encodeImageToPng(croppedImage); } +Future> compressFaceThumbnails(Map args) async { + final listPngBytes = args['listPngBytes'] as List; + final List> compressedBytesList = []; + try { + for (final pngBytes in listPngBytes) { + final compressedBytes = FlutterImageCompress.compressWithList( + pngBytes, + quality: _faceThumbnailCompressionQuality, + format: CompressFormat.jpeg, + minWidth: _faceThumbnailMinDimension, + minHeight: _faceThumbnailMinDimension, + ); + compressedBytesList.add(compressedBytes); + } + return await Future.wait(compressedBytesList); + } catch (e, s) { + _logger.warning( + 'Failed to compress face thumbnail, using original. Size: ${listPngBytes.map((e) => e.length).toList()} bytes', + e, + s, + ); + rethrow; + } +} + RGB _getPixelBilinear( num fx, num fy, diff --git a/mobile/lib/utils/local_settings.dart b/mobile/lib/utils/local_settings.dart index da7fabb312..4133bf0087 100644 --- a/mobile/lib/utils/local_settings.dart +++ b/mobile/lib/utils/local_settings.dart @@ -28,6 +28,8 @@ class LocalSettings { static const kCuratedMemoriesEnabled = "ls.curated_memories_enabled"; static const kOnThisDayNotificationsEnabled = "ls.on_this_day_notifications_enabled"; + static const kBirthdayNotificationsEnabled = + "ls.birthday_notifications_enabled"; static const kRateUsPromptThreshold = 2; static const shouldLoopVideoKey = "video.should_loop"; static const onGuestViewKey = "on_guest_view"; @@ -129,21 +131,17 @@ class LocalSettings { return value; } - bool get userEnabledMultiplePart => - _prefs.getBool(kEnableMultiplePart) ?? false; + bool get birthdayNotificationsEnabled => + _prefs.getBool(kBirthdayNotificationsEnabled) ?? true; - Future autoEnableMultiplePart(int rolloutPercentage) async { - if (_prefs.containsKey(kEnableMultiplePart)) { - return; - } - rolloutPercentage = rolloutPercentage.clamp(0, 100); - final randomValue = DateTime.now().millisecondsSinceEpoch % 100; - await _prefs.setBool( - kEnableMultiplePart, - randomValue < rolloutPercentage, - ); + Future setBirthdayNotificationsEnabled(bool value) async { + await _prefs.setBool(kBirthdayNotificationsEnabled, value); + return value; } + bool get userEnabledMultiplePart => + _prefs.getBool(kEnableMultiplePart) ?? true; + Future setUserEnabledMultiplePart(bool value) async { await _prefs.setBool(kEnableMultiplePart, value); return value; diff --git a/mobile/lib/utils/ml_util.dart b/mobile/lib/utils/ml_util.dart index b1d18307da..7a62aab885 100644 --- a/mobile/lib/utils/ml_util.dart +++ b/mobile/lib/utils/ml_util.dart @@ -1,4 +1,4 @@ -import "dart:io" show File; +import "dart:io" show File, Platform; import "dart:math" as math show sqrt, min, max; import "package:flutter/services.dart" show PlatformException; @@ -15,13 +15,13 @@ import "package:photos/models/ml/face/dimension.dart"; import "package:photos/models/ml/face/face.dart"; import "package:photos/models/ml/ml_versions.dart"; import "package:photos/service_locator.dart"; -import "package:photos/services/filedata/filedata_service.dart"; import "package:photos/services/filedata/model/file_data.dart"; import "package:photos/services/machine_learning/face_ml/face_recognition_service.dart"; import "package:photos/services/machine_learning/ml_exceptions.dart"; import "package:photos/services/machine_learning/ml_result.dart"; import "package:photos/services/machine_learning/semantic_search/semantic_search_service.dart"; import "package:photos/services/search_service.dart"; +import "package:photos/services/sync/local_sync_service.dart"; import "package:photos/utils/file_util.dart"; import "package:photos/utils/image_ml_util.dart"; import "package:photos/utils/network_util.dart"; @@ -205,7 +205,7 @@ Stream> fetchEmbeddingsAndInstructions( pendingIndex[instruction.file.uploadedFileID!] = instruction; } _logger.info("fetching embeddings for ${ids.length} files"); - final res = await FileDataService.instance.getFilesData(ids); + final res = await fileDataService.getFilesData(ids); _logger.info("embeddingResponse ${res.debugLog()}"); final List faces = []; final List clipEmbeddings = []; @@ -349,6 +349,9 @@ Future getImagePathForML(EnteFile enteFile) async { ); } try { + if (Platform.isIOS && enteFile.localID != null) { + trackOriginFetchForUploadOrML.put(enteFile.localID!, true); + } file = await getFile(enteFile, isOrigin: true); } catch (e, s) { _logger.severe( @@ -410,7 +413,10 @@ Future analyzeImageStatic(Map args) async { final startTime = DateTime.now(); // Decode the image once to use for both face detection and alignment - final (image, rawRgbaBytes) = await decodeImageFromPath(imagePath); + final decodedImage = + await decodeImageFromPath(imagePath, includeRgbaBytes: true); + final image = decodedImage.image; + final rawRgbaBytes = decodedImage.rawRgbaBytes!; final decodedImageSize = Dimensions(height: image.height, width: image.width); final result = MLResult.fromEnteFileID(enteFileID); diff --git a/mobile/lib/utils/preload_util.dart b/mobile/lib/utils/preload_util.dart deleted file mode 100644 index 2160c87a58..0000000000 --- a/mobile/lib/utils/preload_util.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/painting.dart'; -import 'package:flutter/services.dart'; -import "package:logging/logging.dart"; - -class PreloadImage { - static final _logger = Logger((PreloadImage).toString()); - static Future loadImage(ImageProvider provider) { - final config = ImageConfiguration( - bundle: rootBundle, - devicePixelRatio: 1, - platform: defaultTargetPlatform, - ); - final Completer completer = Completer(); - final ImageStream stream = provider.resolve(config); - - late final ImageStreamListener listener; - - listener = ImageStreamListener( - (ImageInfo image, bool sync) { - _logger.info("Image ${image.debugLabel} finished loading"); - completer.complete(); - stream.removeListener(listener); - }, - onError: (dynamic exception, StackTrace? stackTrace) { - completer.complete(); - stream.removeListener(listener); - _logger.warning("Image failed to load"); - FlutterError.reportError( - FlutterErrorDetails( - context: ErrorDescription('image failed to load'), - library: 'image resource service', - exception: exception, - stack: stackTrace, - silent: true, - ), - ); - }, - ); - - stream.addListener(listener); - return completer.future; - } -} diff --git a/mobile/lib/utils/standalone/debouncer.dart b/mobile/lib/utils/standalone/debouncer.dart index fc0e6d6359..a9f9c572c8 100644 --- a/mobile/lib/utils/standalone/debouncer.dart +++ b/mobile/lib/utils/standalone/debouncer.dart @@ -16,7 +16,11 @@ class Debouncer { Timer? _debounceTimer; final bool leading; - Debouncer(this._duration, {this.executionInterval, this.leading = false}); + Debouncer( + this._duration, { + this.executionInterval, + this.leading = false, + }); final Stopwatch _stopwatch = Stopwatch(); diff --git a/mobile/lib/utils/thumbnail_util.dart b/mobile/lib/utils/thumbnail_util.dart index 169137e880..3df6122c36 100644 --- a/mobile/lib/utils/thumbnail_util.dart +++ b/mobile/lib/utils/thumbnail_util.dart @@ -163,16 +163,8 @@ Future _downloadAndDecryptThumbnail(FileDownloadItem item) async { Uint8List encryptedThumbnail; try { if (CollectionsService.instance.isSharedPublicLink(file.collectionID!)) { - final authToken = await CollectionsService.instance - .getSharedPublicAlbumToken(file.collectionID!); - final authJWTToken = await CollectionsService.instance - .getSharedPublicAlbumTokenJWT(file.collectionID!); - - final headers = { - "X-Auth-Access-Token": authToken, - if (authJWTToken != null) "X-Auth-Access-Token-JWT": authJWTToken, - }; - + final headers = CollectionsService.instance + .publicCollectionHeaders(file.collectionID!); encryptedThumbnail = (await NetworkClient.instance.getDio().get( FileUrl.getUrl( file.uploadedFileID!, @@ -250,9 +242,15 @@ File cachedThumbnailPath(EnteFile file) { ); } -File cachedFaceCropPath(String faceID) { - final thumbnailCacheDirectory = - Configuration.instance.getThumbnailCacheDirectory(); +File cachedFaceCropPath(String faceID, bool useTempCache) { + late final String thumbnailCacheDirectory; + if (useTempCache) { + thumbnailCacheDirectory = + Configuration.instance.getThumbnailCacheDirectory(); + } else { + thumbnailCacheDirectory = + Configuration.instance.getPersonFaceThumbnailCacheDirectory(); + } return File( thumbnailCacheDirectory + "/" + faceID, ); diff --git a/mobile/plugins/ente_cast/pubspec.lock b/mobile/plugins/ente_cast/pubspec.lock index 7c17037ed2..47c6c55c56 100644 --- a/mobile/plugins/ente_cast/pubspec.lock +++ b/mobile/plugins/ente_cast/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: "direct main" description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" dio: dependency: "direct main" description: @@ -215,7 +215,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: diff --git a/mobile/plugins/ente_cast_none/pubspec.lock b/mobile/plugins/ente_cast_none/pubspec.lock index aeb3c20955..9fa1deda28 100644 --- a/mobile/plugins/ente_cast_none/pubspec.lock +++ b/mobile/plugins/ente_cast_none/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" dio: dependency: transitive description: @@ -222,7 +222,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: diff --git a/mobile/plugins/ente_cast_normal/pubspec.lock b/mobile/plugins/ente_cast_normal/pubspec.lock index e1786a9a8f..05344c3dac 100644 --- a/mobile/plugins/ente_cast_normal/pubspec.lock +++ b/mobile/plugins/ente_cast_normal/pubspec.lock @@ -30,10 +30,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" dio: dependency: transitive description: @@ -263,7 +263,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: @@ -337,5 +337,5 @@ packages: source: hosted version: "1.0.4" sdks: - dart: ">=3.3.0 <4.0.0" + dart: ">=3.4.0 <4.0.0" flutter: ">=3.19.0" diff --git a/mobile/plugins/ente_crypto/lib/src/crypto.dart b/mobile/plugins/ente_crypto/lib/src/crypto.dart index 7a3ec6c3c5..52202c5ac9 100644 --- a/mobile/plugins/ente_crypto/lib/src/crypto.dart +++ b/mobile/plugins/ente_crypto/lib/src/crypto.dart @@ -51,26 +51,18 @@ Uint8List cryptoKdfDeriveFromKey( ); } -// Returns the hash for a given file, chunking it in batches of hashChunkSize +// Returns the hash for a given file Future cryptoGenericHash(Map args) async { - final sourceFile = File(args["sourceFilePath"]); - final sourceFileLength = await sourceFile.length(); - final inputFile = sourceFile.openSync(mode: FileMode.read); + final file = File(args["sourceFilePath"]); final state = Sodium.cryptoGenerichashInit(null, Sodium.cryptoGenerichashBytesMax); - var bytesRead = 0; - bool isDone = false; - while (!isDone) { - var chunkSize = hashChunkSize; - if (bytesRead + chunkSize >= sourceFileLength) { - chunkSize = sourceFileLength - bytesRead; - isDone = true; + await for (final chunk in file.openRead()) { + if (chunk is Uint8List) { + Sodium.cryptoGenerichashUpdate(state, chunk); + } else { + Sodium.cryptoGenerichashUpdate(state, Uint8List.fromList(chunk)); } - final buffer = await inputFile.read(chunkSize); - bytesRead += chunkSize; - Sodium.cryptoGenerichashUpdate(state, buffer); } - await inputFile.close(); return Sodium.cryptoGenerichashFinal(state, Sodium.cryptoGenerichashBytesMax); } diff --git a/mobile/plugins/ente_crypto/pubspec.lock b/mobile/plugins/ente_crypto/pubspec.lock index 0807ae8a31..7574c76da8 100644 --- a/mobile/plugins/ente_crypto/pubspec.lock +++ b/mobile/plugins/ente_crypto/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: "direct main" description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" computer: dependency: "direct main" description: @@ -91,7 +91,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" vector_math: dependency: transitive description: diff --git a/mobile/plugins/ente_feature_flag/lib/src/service.dart b/mobile/plugins/ente_feature_flag/lib/src/service.dart index 376f6b6e48..39bd5cb929 100644 --- a/mobile/plugins/ente_feature_flag/lib/src/service.dart +++ b/mobile/plugins/ente_feature_flag/lib/src/service.dart @@ -60,6 +60,10 @@ class FlagService { String get castUrl => flags.castUrl; + bool hasSyncedAccountFlags() { + return _prefs.containsKey("remote_flags"); + } + Future setMapEnabled(bool isEnabled) async { await _updateKeyValue("mapEnabled", isEnabled.toString()); _updateFlags(flags.copyWith(mapEnabled: isEnabled)); diff --git a/mobile/plugins/ente_feature_flag/pubspec.lock b/mobile/plugins/ente_feature_flag/pubspec.lock index e58ff1231c..608654b2e8 100644 --- a/mobile/plugins/ente_feature_flag/pubspec.lock +++ b/mobile/plugins/ente_feature_flag/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: "direct main" description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" dio: dependency: "direct main" description: @@ -215,7 +215,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: diff --git a/mobile/plugins/onnx_dart/pubspec.lock b/mobile/plugins/onnx_dart/pubspec.lock index 72000bb8f1..ec8eccea6e 100644 --- a/mobile/plugins/onnx_dart/pubspec.lock +++ b/mobile/plugins/onnx_dart/pubspec.lock @@ -37,10 +37,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" fake_async: dependency: transitive description: @@ -71,18 +71,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.7" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.8" leak_tracker_testing: dependency: transitive description: @@ -143,7 +143,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: @@ -156,10 +156,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.0" stream_channel: dependency: transitive description: @@ -172,10 +172,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" term_glyph: dependency: transitive description: @@ -188,10 +188,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.3" vector_math: dependency: transitive description: @@ -204,10 +204,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "14.3.0" sdks: dart: ">=3.4.3 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/mobile/pubspec.lock b/mobile/pubspec.lock index 62a3685340..2c4c95d52d 100644 --- a/mobile/pubspec.lock +++ b/mobile/pubspec.lock @@ -119,21 +119,13 @@ packages: source: hosted version: "1.5.8" async: - dependency: transitive + dependency: "direct main" description: name: async sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted version: "2.11.0" - background_fetch: - dependency: "direct main" - description: - name: background_fetch - sha256: e9f26ae54d88310b7ac2a68f2f9fcee0081a4d5f11100f233a70702021e7ac4f - url: "https://pub.dev" - source: hosted - version: "1.3.7" battery_info: dependency: "direct main" description: @@ -159,6 +151,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + brotli: + dependency: transitive + description: + name: brotli + sha256: "7f891558ed779aab2bed874f0a36b8123f9ff3f19cf6efbee89e18ed294945ae" + url: "https://pub.dev" + source: hosted + version: "0.6.0" build: dependency: transitive description: @@ -566,14 +566,15 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" - exif: + exif_reader: dependency: "direct main" description: - name: exif - sha256: a7980fdb3b7ffcd0b035e5b8a5e1eef7cadfe90ea6a4e85ebb62f87b96c7a172 - url: "https://pub.dev" - source: hosted - version: "3.3.0" + path: "." + ref: "476f701c084861a8e9de5f4f4e5e067fc85fda96" + resolved-ref: "476f701c084861a8e9de5f4f4e5e067fc85fda96" + url: "https://github.com/mgenware/exif_reader.git" + source: git + version: "3.16.1" expandable: dependency: "direct main" description: @@ -1371,6 +1372,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + iso_base_media: + dependency: transitive + description: + name: iso_base_media + sha256: "0f5594feef1fba98179a2df95d1afbdda952de0c7a2e35e6815093f7c00aaf06" + url: "https://pub.dev" + source: hosted + version: "4.5.2" jni: dependency: transitive description: @@ -1752,10 +1761,10 @@ packages: dependency: "direct main" description: name: native_video_player - sha256: "64ac4086c50f13306c7ebca70372b2c2c67c063caae25f0c486dbec16d666e9a" + sha256: "83c6672848c7d563734d2415e189713285020174eebd967cbbf22c6941c5833c" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "4.0.0" nested: dependency: transitive description: @@ -2091,10 +2100,10 @@ packages: dependency: "direct overridden" description: name: protobuf - sha256: fbb0c37d435641d0b84813c1dad41e6fa61ddc880a320bce16b3063ecec35aa6 + sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "3.1.0" provider: dependency: transitive description: @@ -2127,6 +2136,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.2" + random_access_source: + dependency: transitive + description: + name: random_access_source + sha256: dc86934da2cc4777334f43916234410f232032738c519c0c3452147c5d4fec89 + url: "https://pub.dev" + source: hosted + version: "2.1.0" receive_sharing_intent: dependency: "direct main" description: @@ -2549,6 +2566,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.4" + thermal: + dependency: "direct main" + description: + name: thermal + sha256: c6275ebc609e75f1bbbfc354d56d6c559a0c6045a06a8e8c3939c03306a07e18 + url: "https://pub.dev" + source: hosted + version: "1.1.11" timezone: dependency: "direct main" description: @@ -2796,10 +2821,10 @@ packages: dependency: "direct main" description: name: visibility_detector - sha256: "15c54a459ec2c17b4705450483f3d5a2858e733aee893dcee9d75fd04814940d" + sha256: dd5cc11e13494f432d15939c3aa8ae76844c42b723398643ce9addb88a5ed420 url: "https://pub.dev" source: hosted - version: "0.3.3" + version: "0.4.0+2" vm_service: dependency: transitive description: @@ -2884,10 +2909,18 @@ packages: dependency: "direct main" description: name: wechat_assets_picker - sha256: "9934724a45fdb2b12e332d8190c58713e6675c37c630d53608e0f50167215c9f" + sha256: cafe3d32564ed3cacf9822f251941f7b44fe9885c17c8de4fca7e939a459e1ef url: "https://pub.dev" source: hosted - version: "8.9.0-dev.1" + version: "9.5.1" + wechat_picker_library: + dependency: transitive + description: + name: wechat_picker_library + sha256: a42e09cb85b15fc9410f6a69671371cc60aa99c4a1f7967f6593a7f665f6f47a + url: "https://pub.dev" + source: hosted + version: "1.0.5" widgets_to_image: dependency: "direct main" description: @@ -2920,6 +2953,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + workmanager: + dependency: "direct main" + description: + name: workmanager + sha256: f3c3ce6d79cce53eee4a29dd2e8328c25db5ba5d9062fcc5e8f3c71e0af9b7e4 + url: "https://pub.dev" + source: hosted + version: "0.6.0" xdg_directories: dependency: transitive description: diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index 9474370c5c..962333e51a 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -12,7 +12,7 @@ description: ente photos application # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.1.0+1053 +version: 1.1.53+1083 publish_to: none environment: @@ -24,7 +24,7 @@ dependencies: animated_list_plus: ^0.5.2 app_links: ^6.4.0 archive: ^3.6.1 - background_fetch: ^1.3.7 + async: ^2.11.0 battery_info: # replace with battery_plus git: url: https://github.com/ente-io/battery_info @@ -61,7 +61,10 @@ dependencies: path: plugins/ente_feature_flag equatable: ^2.0.5 event_bus: ^2.0.0 - exif: ^3.0.0 + exif_reader: + git: + url: https://github.com/mgenware/exif_reader.git + ref: 476f701c084861a8e9de5f4f4e5e067fc85fda96 expandable: ^5.0.1 expansion_tile_card: ^3.0.0 extended_image: ^8.1.1 @@ -139,7 +142,7 @@ dependencies: ref: 3b862fe nanoid: ^1.0.0 native_dio_adapter: ^1.4.0 - native_video_player: ^3.0.0-dev.4 + native_video_player: ^4.0.0 onnx_dart: path: plugins/onnx_dart onnxruntime: @@ -188,6 +191,7 @@ dependencies: syncfusion_flutter_sliders: ^25.2.5 synchronized: ^3.3.0+3 system_info_plus: ^0.0.6 + thermal: ^1.1.11 timezone: ^0.10.0 tuple: ^2.0.0 ua_client_hints: ^1.4.0 @@ -202,10 +206,11 @@ dependencies: ref: android_video_roation_fix path: packages/video_player/video_player/ video_thumbnail: - visibility_detector: ^0.3.3 + visibility_detector: ^0.4.0+2 wakelock_plus: ^1.1.1 - wechat_assets_picker: ^8.6.3 + wechat_assets_picker: ^9.5.1 widgets_to_image: ^0.0.2 + workmanager: ^0.6.0 xml: ^6.3.0 dependency_overrides: diff --git a/server/cmd/museum/main.go b/server/cmd/museum/main.go index 24b0950176..742d098397 100644 --- a/server/cmd/museum/main.go +++ b/server/cmd/museum/main.go @@ -5,7 +5,6 @@ import ( "database/sql" b64 "encoding/base64" "fmt" - "github.com/ente-io/museum/pkg/controller/collections" "net/http" "os" "os/signal" @@ -15,6 +14,8 @@ import ( "syscall" "time" + "github.com/ente-io/museum/pkg/controller/collections" + "github.com/ente-io/museum/ente/base" "github.com/ente-io/museum/pkg/controller/emergency" "github.com/ente-io/museum/pkg/controller/file_copy" @@ -922,8 +923,8 @@ func setupAndStartCrons(userAuthRepo *repo.UserAuthRepository, publicCollectionR }) schedule(c, "@every 24h", func() { - _ = userAuthRepo.RemoveDeletedTokens(timeUtil.MicrosecondBeforeDays(30)) - _ = castDb.DeleteOldSessions(context.Background(), timeUtil.MicrosecondBeforeDays(7)) + _ = userAuthRepo.RemoveDeletedTokens(timeUtil.MicrosecondsBeforeDays(30)) + _ = castDb.DeleteOldSessions(context.Background(), timeUtil.MicrosecondsBeforeDays(7)) _ = publicCollectionRepo.CleanupAccessHistory(context.Background()) }) @@ -990,6 +991,10 @@ func setupAndStartCrons(userAuthRepo *repo.UserAuthRepository, publicCollectionR emailNotificationCtrl.SendStorageLimitExceededMails() }) + scheduleAndRun(c, "@every 24h", func() { + emailNotificationCtrl.SayHelloToCustomers() + }) + schedule(c, "@every 1m", func() { pushController.SendPushes() }) diff --git a/server/docs/quickstart.md b/server/docs/quickstart.md index 9e9760c8f3..3f29357711 100644 --- a/server/docs/quickstart.md +++ b/server/docs/quickstart.md @@ -16,8 +16,15 @@ sh -c "$(curl -fsSL https://raw.githubusercontent.com/ente-io/ente/main/server/q > > If you don't want to run via curl, you can alternatively download > [quickstart.sh](https://github.com/ente-io/ente/blob/main/server/quickstart.sh), -> `chmod +x` it and then run it with `./quickstart.sh`. +> make it executable and run the script. +> +> ``` shell +> curl -o quickstart.sh https://raw.githubusercontent.com/ente-io/ente/main/server/quickstart.sh +> chmod +x quickstart.sh +> ./quickstart.sh + +If prompted to start the cluster, enter `y` if you wish to start the Docker compose cluster. After the Docker compose cluster starts, you can open the Ente web app at http://localhost:3000. diff --git a/server/ente/billing.go b/server/ente/billing.go index 9909b9f052..5e212c5cb8 100644 --- a/server/ente/billing.go +++ b/server/ente/billing.go @@ -30,7 +30,7 @@ const ( Period3Years = "3" Period5Years = "5" - + Period10Years = "10" // FamilyPlanProductID is the product ID of family (internal employees & their friends & family) plan @@ -127,6 +127,7 @@ type Subscription struct { // LinkedPurchaseToken on PlayStore , OriginalTransactionID on AppStore and SubscriptionID on Stripe OriginalTransactionID string `json:"originalTransactionID"` ExpiryTime int64 `json:"expiryTime"` + UpgradedAt int64 `json:"upgradedAt,omitempty"` PaymentProvider PaymentProvider `json:"paymentProvider"` Attributes SubscriptionAttributes `json:"attributes"` Price string `json:"price"` diff --git a/server/mail-templates/customer_hello.html b/server/mail-templates/customer_hello.html new file mode 100644 index 0000000000..cd09a80df4 --- /dev/null +++ b/server/mail-templates/customer_hello.html @@ -0,0 +1,149 @@ + + + + + + + +

 
+
+

Hi there,

+ +

Vishnu here, CEO of Ente.

+ +

Thank you for checking out Ente Photos, and upgrading to a paid plan.

+ +

This is my personal email address. If you need help with anything or + have feedback to share, please write back - we want this to be a great + experience for you!

+ +

Best, +
+ Vishnu +
+ Founder & CEO at Ente +

+
+
+ + + diff --git a/server/mail-templates/mobile_app_first_upload.html b/server/mail-templates/mobile_app_first_upload.html index 5d05827495..6947b5225b 100644 --- a/server/mail-templates/mobile_app_first_upload.html +++ b/server/mail-templates/mobile_app_first_upload.html @@ -113,15 +113,15 @@

Congratulations on preserving your first memory!

- Did you know that we will be keeping 3 copies of your data, at 3 - different locations so they are as safe as they can be? One of these - copies will in fact be preserved in an underground fallout shelter! + Did you know that if you upgrade to a paid plan, we will keep 3 copies + of your data, at 3 locations? One of these is in an underground fallout + shelter!

- While we work our magic, you could turn on - Machine Learning to - see the magic you can do with your photos. + Even on the free plan, you can turn on + machine learning for + a private magic show.

diff --git a/server/mail-templates/ott.html b/server/mail-templates/ott.html index 73750e9f79..0c671a53c0 100644 --- a/server/mail-templates/ott.html +++ b/server/mail-templates/ott.html @@ -96,12 +96,12 @@ a:hover {

 
-

Please use this code to verify your email address

+

Enter this code to complete verification:

{{.VerificationCode}}

-

If you need help, just hit the reply button!

+

Need help? Contact us at support@ente.io.