浏览代码

Merge branch 'main' into f-droid

vishnukvmd 1 年之前
父节点
当前提交
a8e9934a8a
共有 100 个文件被更改,包括 939 次插入220 次删除
  1. 2 0
      .github/workflows/server-publish.yml
  2. 1 1
      .github/workflows/web-crowdin.yml
  3. 1 1
      .github/workflows/web-deploy-accounts.yml
  4. 1 1
      .github/workflows/web-deploy-auth.yml
  5. 1 1
      .github/workflows/web-deploy-cast.yml
  6. 2 2
      .github/workflows/web-deploy-payments.yml
  7. 1 1
      .github/workflows/web-deploy-photos.yml
  8. 48 0
      .github/workflows/web-deploy-staff.yml
  9. 2 2
      .github/workflows/web-nightly.yml
  10. 1 1
      .github/workflows/web-preview.yml
  11. 4 1
      CONTRIBUTING.md
  12. 40 0
      auth/android/app/src/main/play/listings/en-US/full_description.txt
  13. 二进制
      auth/android/app/src/main/play/listings/en-US/graphics/icon/icon.png
  14. 二进制
      auth/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/1.png
  15. 二进制
      auth/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/2.png
  16. 二进制
      auth/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/3.png
  17. 二进制
      auth/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/4.png
  18. 二进制
      auth/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/5.png
  19. 1 0
      auth/android/app/src/main/play/listings/en-US/short_description.txt
  20. 1 0
      auth/android/app/src/main/play/listings/en-US/title.txt
  21. 1 13
      auth/ios/Podfile.lock
  22. 16 6
      auth/lib/ui/home_page.dart
  23. 23 29
      auth/lib/ui/two_factor_authentication_page.dart
  24. 0 4
      auth/linux/flutter/generated_plugin_registrant.cc
  25. 0 1
      auth/linux/flutter/generated_plugins.cmake
  26. 0 2
      auth/macos/Flutter/GeneratedPluginRegistrant.swift
  27. 2 18
      auth/pubspec.lock
  28. 2 2
      auth/pubspec.yaml
  29. 0 3
      auth/windows/flutter/generated_plugin_registrant.cc
  30. 0 1
      auth/windows/flutter/generated_plugins.cmake
  31. 4 77
      docs/docs/.vitepress/sidebar.ts
  32. 10 8
      docs/docs/photos/faq/export.md
  33. 15 6
      docs/docs/photos/faq/general.md
  34. 3 1
      docs/docs/photos/faq/subscription.md
  35. 11 9
      docs/docs/photos/migration/export/index.md
  36. 22 8
      docs/docs/self-hosting/guides/admin.md
  37. 2 2
      docs/docs/self-hosting/index.md
  38. 13 0
      docs/docs/self-hosting/troubleshooting/uploads.md
  39. 54 0
      infra/services/listmonk/README.md
  40. 14 0
      infra/services/listmonk/initialize-db.sh
  41. 26 0
      infra/services/listmonk/listmonk.nginx.conf
  42. 19 0
      infra/services/listmonk/listmonk.service
  43. 9 0
      infra/services/nginx/README.md
  44. 3 2
      infra/services/status/uptime-kuma.nginx.conf
  45. 36 0
      mobile/android/app/src/main/play/listings/de/full_description.txt
  46. 1 0
      mobile/android/app/src/main/play/listings/de/short_description.txt
  47. 1 0
      mobile/android/app/src/main/play/listings/de/title.txt
  48. 36 0
      mobile/android/app/src/main/play/listings/en-US/full_description.txt
  49. 二进制
      mobile/android/app/src/main/play/listings/en-US/graphics/icon/icon.png
  50. 二进制
      mobile/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/1.png
  51. 二进制
      mobile/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/2.png
  52. 二进制
      mobile/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/3.png
  53. 二进制
      mobile/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/4.png
  54. 二进制
      mobile/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/5.png
  55. 二进制
      mobile/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/6.png
  56. 二进制
      mobile/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/7.png
  57. 1 0
      mobile/android/app/src/main/play/listings/en-US/short_description.txt
  58. 1 0
      mobile/android/app/src/main/play/listings/en-US/title.txt
  59. 36 0
      mobile/android/app/src/main/play/listings/es/full_description.txt
  60. 1 0
      mobile/android/app/src/main/play/listings/es/short_description.txt
  61. 1 0
      mobile/android/app/src/main/play/listings/es/title.txt
  62. 36 0
      mobile/android/app/src/main/play/listings/fr/full_description.txt
  63. 1 0
      mobile/android/app/src/main/play/listings/fr/short_description.txt
  64. 1 0
      mobile/android/app/src/main/play/listings/fr/title.txt
  65. 36 0
      mobile/android/app/src/main/play/listings/he/full_description.txt
  66. 1 0
      mobile/android/app/src/main/play/listings/he/short_description.txt
  67. 1 0
      mobile/android/app/src/main/play/listings/he/title.txt
  68. 36 0
      mobile/android/app/src/main/play/listings/it/full_description.txt
  69. 1 0
      mobile/android/app/src/main/play/listings/it/short_description.txt
  70. 1 0
      mobile/android/app/src/main/play/listings/it/title.txt
  71. 36 0
      mobile/android/app/src/main/play/listings/nl/full_description.txt
  72. 1 0
      mobile/android/app/src/main/play/listings/nl/short_description.txt
  73. 1 0
      mobile/android/app/src/main/play/listings/nl/title.txt
  74. 1 0
      mobile/android/app/src/main/play/listings/pl/short_description.txt
  75. 1 0
      mobile/android/app/src/main/play/listings/pl/title.txt
  76. 36 0
      mobile/android/app/src/main/play/listings/pt/full_description.txt
  77. 1 0
      mobile/android/app/src/main/play/listings/pt/short_description.txt
  78. 1 0
      mobile/android/app/src/main/play/listings/pt/title.txt
  79. 36 0
      mobile/android/app/src/main/play/listings/ru/full_description.txt
  80. 1 0
      mobile/android/app/src/main/play/listings/ru/short_description.txt
  81. 1 0
      mobile/android/app/src/main/play/listings/ru/title.txt
  82. 36 0
      mobile/android/app/src/main/play/listings/zh/full_description.txt
  83. 1 0
      mobile/android/app/src/main/play/listings/zh/short_description.txt
  84. 1 0
      mobile/android/app/src/main/play/listings/zh/title.txt
  85. 130 0
      mobile/integration_test/app_init_test.dart
  86. 7 1
      mobile/ios/Podfile.lock
  87. 8 1
      mobile/lib/core/configuration.dart
  88. 2 4
      mobile/lib/core/network/ente_interceptor.dart
  89. 17 11
      mobile/lib/core/network/network.dart
  90. 3 0
      mobile/lib/events/endpoint_updated_event.dart
  91. 2 0
      mobile/lib/generated/intl/messages_cs.dart
  92. 2 0
      mobile/lib/generated/intl/messages_de.dart
  93. 17 0
      mobile/lib/generated/intl/messages_en.dart
  94. 2 0
      mobile/lib/generated/intl/messages_es.dart
  95. 2 0
      mobile/lib/generated/intl/messages_fr.dart
  96. 2 0
      mobile/lib/generated/intl/messages_it.dart
  97. 2 0
      mobile/lib/generated/intl/messages_ko.dart
  98. 2 0
      mobile/lib/generated/intl/messages_nl.dart
  99. 2 0
      mobile/lib/generated/intl/messages_no.dart
  100. 2 0
      mobile/lib/generated/intl/messages_pl.dart

+ 2 - 0
.github/workflows/server-publish.yml

@@ -32,6 +32,8 @@ jobs:
                   image: server
                   registry: ghcr.io
                   enableBuildKit: true
+                  multiPlatform: true
+                  platform: linux/amd64,linux/arm64,linux/arm/v7
                   buildArgs: GIT_COMMIT=${{ inputs.commit }}
                   tags: ${{ inputs.commit }}, latest
                   username: ${{ github.actor }}

+ 1 - 1
.github/workflows/web-crowdin.yml

@@ -5,7 +5,7 @@ on:
         branches: [main]
         paths:
             # Run workflow when web's en-US/translation.json is changed
-            - "web/apps/photos/public/locales/en-US/translation.json"
+            - "web/packages/next/locales/en-US/translation.json"
             # Or the workflow itself is changed
             - ".github/workflows/web-crowdin.yml"
     schedule:

+ 1 - 1
.github/workflows/web-deploy-accounts.yml

@@ -24,7 +24,7 @@ jobs:
               with:
                   node-version: 20
                   cache: "yarn"
-                  cache-dependency-path: "docs/yarn.lock"
+                  cache-dependency-path: "web/yarn.lock"
 
             - name: Install dependencies
               run: yarn install

+ 1 - 1
.github/workflows/web-deploy-auth.yml

@@ -24,7 +24,7 @@ jobs:
               with:
                   node-version: 20
                   cache: "yarn"
-                  cache-dependency-path: "docs/yarn.lock"
+                  cache-dependency-path: "web/yarn.lock"
 
             - name: Install dependencies
               run: yarn install

+ 1 - 1
.github/workflows/web-deploy-cast.yml

@@ -24,7 +24,7 @@ jobs:
               with:
                   node-version: 20
                   cache: "yarn"
-                  cache-dependency-path: "docs/yarn.lock"
+                  cache-dependency-path: "web/yarn.lock"
 
             - name: Install dependencies
               run: yarn install

+ 2 - 2
.github/workflows/web-deploy-payments.yml

@@ -24,7 +24,7 @@ jobs:
               with:
                   node-version: 20
                   cache: "yarn"
-                  cache-dependency-path: "docs/yarn.lock"
+                  cache-dependency-path: "web/yarn.lock"
 
             - name: Install dependencies
               run: yarn install
@@ -39,5 +39,5 @@ jobs:
                   apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
                   projectName: ente
                   branch: deploy/payments
-                  directory: web/apps/payments/out
+                  directory: web/apps/payments/dist
                   wranglerVersion: "3"

+ 1 - 1
.github/workflows/web-deploy-photos.yml

@@ -24,7 +24,7 @@ jobs:
               with:
                   node-version: 20
                   cache: "yarn"
-                  cache-dependency-path: "docs/yarn.lock"
+                  cache-dependency-path: "web/yarn.lock"
 
             - name: Install dependencies
               run: yarn install

+ 48 - 0
.github/workflows/web-deploy-staff.yml

@@ -0,0 +1,48 @@
+name: "Deploy (staff)"
+
+on:
+    # Run on every push to main that changes web/apps/staff/
+    push:
+        branches: [main]
+        paths:
+            - "web/apps/staff/**"
+            - ".github/workflows/web-deploy-staff.yml"
+    # Also allow manually running the workflow
+    workflow_dispatch:
+
+jobs:
+    deploy:
+        runs-on: ubuntu-latest
+
+        defaults:
+            run:
+                working-directory: web
+
+        steps:
+            - name: Checkout code
+              uses: actions/checkout@v4
+              with:
+                  submodules: recursive
+
+            - name: Setup node and enable yarn caching
+              uses: actions/setup-node@v4
+              with:
+                  node-version: 20
+                  cache: "yarn"
+                  cache-dependency-path: "web/yarn.lock"
+
+            - name: Install dependencies
+              run: yarn install
+
+            - name: Build staff
+              run: yarn build:staff
+
+            - name: Publish staff
+              uses: cloudflare/pages-action@1
+              with:
+                  accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
+                  apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
+                  projectName: ente
+                  branch: deploy/staff
+                  directory: web/apps/staff/dist
+                  wranglerVersion: "3"

+ 2 - 2
.github/workflows/web-nightly.yml

@@ -34,7 +34,7 @@ jobs:
               with:
                   node-version: 20
                   cache: "yarn"
-                  cache-dependency-path: "docs/yarn.lock"
+                  cache-dependency-path: "web/yarn.lock"
 
             - name: Install dependencies
               run: yarn install
@@ -88,7 +88,7 @@ jobs:
                   apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
                   projectName: ente
                   branch: n-payments
-                  directory: web/apps/payments/out
+                  directory: web/apps/payments/dist
                   wranglerVersion: "3"
 
             - name: Build photos

+ 1 - 1
.github/workflows/web-preview.yml

@@ -34,7 +34,7 @@ jobs:
               with:
                   node-version: 20
                   cache: "yarn"
-                  cache-dependency-path: "docs/yarn.lock"
+                  cache-dependency-path: "web/yarn.lock"
 
             - name: Install dependencies
               run: yarn install

+ 4 - 1
CONTRIBUTING.md

@@ -59,7 +59,10 @@ See [docs/](docs/README.md) for how to edit these documents.
 
 ## Code contributions
 
-If you'd like to contribute code, it is best to start small.
+Code is a small aspect of community, and the ways mentioned above are more
+important in helping us. But if you'd _really_ like to contribute code, it is
+best to start small. Consider some well-scoped changes, say like adding more
+[custom icons to auth](auth/docs/adding-icons.md).
 
 Each of the individual product/platform specific directories in this repository
 have instructions on setting up a dev environment and making changes. The issues

+ 40 - 0
auth/android/app/src/main/play/listings/en-US/full_description.txt

@@ -0,0 +1,40 @@
+Ente Auth helps you generate and store 2 step verification (2FA)
+tokens on your mobile devices.
+
+
+FEATURES
+
+- Secure Backups
+Auth provides end-to-end encrypted cloud backups so that you don't have to worry
+about losing your tokens. We use the same protocols ente Photos uses to encrypt
+and preserve your data.
+
+- Multi Device Synchronization
+Auth will automatically sync the 2FA tokens you add to your account, across all
+your devices. Every new device you sign into will have access to these tokens.
+
+- Web access
+You can access your 2FA code from any web browser by visiting https://auth.ente.io .
+
+- Offline Mode
+Auth generates 2FA tokens offline, so your network connectivity will not get in
+the way of your workflow.
+
+- Import and Export Tokens
+You can add tokens to Auth by one of the following methods: 
+1. Scanning a QR code
+2. Manually entering (copy-pasting) a 2FA secret
+3. Bulk importing from a file that contains a list of codes in the following format:
+
+otpauth://totp/provider.com:you@email.com?secret=YOUR_SECRET
+
+The codes maybe separated by new lines or commas.
+
+You can also export the codes you have added to Auth, to an **unencrypted** text
+file, that adheres to the above format.
+
+
+SUPPORT
+
+If you need help, please reach out to support@ente.io, and a human will get in touch with you.
+If you have feature requests, please create an issue @ https://github.com/ente-io/ente

二进制
auth/android/app/src/main/play/listings/en-US/graphics/icon/icon.png


二进制
auth/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/1.png


二进制
auth/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/2.png


二进制
auth/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/3.png


二进制
auth/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/4.png


二进制
auth/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/5.png


+ 1 - 0
auth/android/app/src/main/play/listings/en-US/short_description.txt

@@ -0,0 +1 @@
+Auth is a FOSS authenticator app that provides end-to-end encrypted backups for your 2FA secrets.

+ 1 - 0
auth/android/app/src/main/play/listings/en-US/title.txt

@@ -0,0 +1 @@
+Ente Auth

+ 1 - 13
auth/ios/Podfile.lock

@@ -67,8 +67,6 @@ PODS:
     - Toast
   - local_auth_darwin (0.0.1):
     - Flutter
-  - local_auth_ios (0.0.1):
-    - Flutter
   - move_to_background (0.0.1):
     - Flutter
   - MTBBarcodeScanner (5.0.11)
@@ -99,8 +97,6 @@ PODS:
   - shared_preferences_foundation (0.0.1):
     - Flutter
     - FlutterMacOS
-  - smart_auth (0.0.1):
-    - Flutter
   - sodium_libs (2.2.1):
     - Flutter
   - sqflite (0.0.3):
@@ -142,7 +138,6 @@ DEPENDENCIES:
   - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
   - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
   - local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`)
-  - local_auth_ios (from `.symlinks/plugins/local_auth_ios/ios`)
   - move_to_background (from `.symlinks/plugins/move_to_background/ios`)
   - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
   - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
@@ -151,7 +146,6 @@ DEPENDENCIES:
   - sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`)
   - share_plus (from `.symlinks/plugins/share_plus/ios`)
   - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
-  - smart_auth (from `.symlinks/plugins/smart_auth/ios`)
   - sodium_libs (from `.symlinks/plugins/sodium_libs/ios`)
   - sqflite (from `.symlinks/plugins/sqflite/darwin`)
   - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`)
@@ -202,8 +196,6 @@ EXTERNAL SOURCES:
     :path: ".symlinks/plugins/fluttertoast/ios"
   local_auth_darwin:
     :path: ".symlinks/plugins/local_auth_darwin/darwin"
-  local_auth_ios:
-    :path: ".symlinks/plugins/local_auth_ios/ios"
   move_to_background:
     :path: ".symlinks/plugins/move_to_background/ios"
   package_info_plus:
@@ -220,8 +212,6 @@ EXTERNAL SOURCES:
     :path: ".symlinks/plugins/share_plus/ios"
   shared_preferences_foundation:
     :path: ".symlinks/plugins/shared_preferences_foundation/darwin"
-  smart_auth:
-    :path: ".symlinks/plugins/smart_auth/ios"
   sodium_libs:
     :path: ".symlinks/plugins/sodium_libs/ios"
   sqflite:
@@ -245,11 +235,10 @@ SPEC CHECKSUMS:
   flutter_inappwebview_ios: 97215cf7d4677db55df76782dbd2930c5e1c1ea0
   flutter_local_authentication: 1172a4dd88f6306dadce067454e2c4caf07977bb
   flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086
-  flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
+  flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778
   flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
   fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265
   local_auth_darwin: c7e464000a6a89e952235699e32b329457608d98
-  local_auth_ios: 5046a18c018dd973247a0564496c8898dbb5adf9
   move_to_background: 39a5b79b26d577b0372cbe8a8c55e7aa9fcd3a2d
   MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
   OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
@@ -264,7 +253,6 @@ SPEC CHECKSUMS:
   SentryPrivate: d651efb234cf385ec9a1cdd3eff94b5e78a0e0fe
   share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5
   shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
-  smart_auth: 4bedbc118723912d0e45a07e8ab34039c19e04f2
   sodium_libs: 1faae17af662384acbd13e41867a0008cd2e2318
   sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
   sqlite3: 73b7fc691fdc43277614250e04d183740cb15078

+ 16 - 6
auth/lib/ui/home_page.dart

@@ -93,12 +93,22 @@ class _HomePageState extends State<HomePage> {
   void _applyFilteringAndRefresh() {
     if (_searchText.isNotEmpty && _showSearchBox) {
       final String val = _searchText.toLowerCase();
-      _filteredCodes = _codes
-          .where(
-            (element) => (element.account.toLowerCase().contains(val) ||
-                element.issuer.toLowerCase().contains(val)),
-          )
-          .toList();
+      // Prioritize issuer match above account for better UX while searching
+      // for a specific TOTP for email providers. Searching for "emailProvider" like (gmail, proton) should
+      // show the email provider first instead of other accounts where protonmail
+      // is the account name.
+      final List<Code> issuerMatch = [];
+      final List<Code> accountMatch = [];
+
+      for (final Code code in _codes) {
+        if (code.issuer.toLowerCase().contains(val)) {
+          issuerMatch.add(code);
+        } else if (code.account.toLowerCase().contains(val)) {
+          accountMatch.add(code);
+        }
+      }
+      _filteredCodes = issuerMatch;
+      _filteredCodes.addAll(accountMatch);
     } else {
       _filteredCodes = _codes;
     }

+ 23 - 29
auth/lib/ui/two_factor_authentication_page.dart

@@ -4,8 +4,7 @@ import 'package:ente_auth/services/user_service.dart';
 import 'package:ente_auth/ui/lifecycle_event_handler.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
-
-import 'package:pinput/pinput.dart';
+import 'package:pinput/pin_put/pin_put.dart';
 
 class TwoFactorAuthenticationPage extends StatefulWidget {
   final String sessionID;
@@ -20,6 +19,10 @@ class TwoFactorAuthenticationPage extends StatefulWidget {
 class _TwoFactorAuthenticationPageState
     extends State<TwoFactorAuthenticationPage> {
   final _pinController = TextEditingController();
+  final _pinPutDecoration = BoxDecoration(
+    border: Border.all(color: const Color.fromRGBO(45, 194, 98, 1.0)),
+    borderRadius: BorderRadius.circular(15.0),
+  );
   String _code = "";
   late LifecycleEventHandler _lifecycleEventHandler;
 
@@ -60,16 +63,6 @@ class _TwoFactorAuthenticationPageState
 
   Widget _getBody() {
     final l10n = context.l10n;
-    final pinPutDecoration = BoxDecoration(
-      border: Border.all(
-        color: Theme.of(context)
-            .inputDecorationTheme
-            .focusedBorder!
-            .borderSide
-            .color,
-      ),
-      borderRadius: BorderRadius.circular(15.0),
-    );
     return Column(
       crossAxisAlignment: CrossAxisAlignment.stretch,
       mainAxisAlignment: MainAxisAlignment.center,
@@ -86,31 +79,32 @@ class _TwoFactorAuthenticationPageState
         const Padding(padding: EdgeInsets.all(32)),
         Padding(
           padding: const EdgeInsets.fromLTRB(40, 0, 40, 0),
-          child: Pinput(
-            onSubmitted: (String code) {
+          child: PinPut(
+            fieldsCount: 6,
+            onSubmit: (String code) {
               _verifyTwoFactorCode(code);
             },
-            length: 6,
-            defaultPinTheme: const PinTheme(),
-            submittedPinTheme: PinTheme(
-              decoration: pinPutDecoration.copyWith(
-                borderRadius: BorderRadius.circular(20.0),
-              ),
-            ),
-            focusedPinTheme: PinTheme(
-              decoration: pinPutDecoration,
-            ),
-            followingPinTheme: PinTheme(
-              decoration: pinPutDecoration.copyWith(
-                borderRadius: BorderRadius.circular(5.0),
-              ),
-            ),
             onChanged: (String pin) {
               setState(() {
                 _code = pin;
               });
             },
             controller: _pinController,
+            submittedFieldDecoration: _pinPutDecoration.copyWith(
+              borderRadius: BorderRadius.circular(20.0),
+            ),
+            selectedFieldDecoration: _pinPutDecoration,
+            followingFieldDecoration: _pinPutDecoration.copyWith(
+              borderRadius: BorderRadius.circular(5.0),
+              border: Border.all(
+                color: const Color.fromRGBO(45, 194, 98, 0.5),
+              ),
+            ),
+            inputDecoration: const InputDecoration(
+              focusedBorder: InputBorder.none,
+              border: InputBorder.none,
+              counterText: '',
+            ),
             autofocus: true,
           ),
         ),

+ 0 - 4
auth/linux/flutter/generated_plugin_registrant.cc

@@ -13,7 +13,6 @@
 #include <gtk/gtk_plugin.h>
 #include <screen_retriever/screen_retriever_plugin.h>
 #include <sentry_flutter/sentry_flutter_plugin.h>
-#include <smart_auth/smart_auth_plugin.h>
 #include <sodium_libs/sodium_libs_plugin.h>
 #include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
 #include <tray_manager/tray_manager_plugin.h>
@@ -42,9 +41,6 @@ void fl_register_plugins(FlPluginRegistry* registry) {
   g_autoptr(FlPluginRegistrar) sentry_flutter_registrar =
       fl_plugin_registry_get_registrar_for_plugin(registry, "SentryFlutterPlugin");
   sentry_flutter_plugin_register_with_registrar(sentry_flutter_registrar);
-  g_autoptr(FlPluginRegistrar) smart_auth_registrar =
-      fl_plugin_registry_get_registrar_for_plugin(registry, "SmartAuthPlugin");
-  smart_auth_plugin_register_with_registrar(smart_auth_registrar);
   g_autoptr(FlPluginRegistrar) sodium_libs_registrar =
       fl_plugin_registry_get_registrar_for_plugin(registry, "SodiumLibsPlugin");
   sodium_libs_plugin_register_with_registrar(sodium_libs_registrar);

+ 0 - 1
auth/linux/flutter/generated_plugins.cmake

@@ -10,7 +10,6 @@ list(APPEND FLUTTER_PLUGIN_LIST
   gtk
   screen_retriever
   sentry_flutter
-  smart_auth
   sodium_libs
   sqlite3_flutter_libs
   tray_manager

+ 0 - 2
auth/macos/Flutter/GeneratedPluginRegistrant.swift

@@ -20,7 +20,6 @@ import screen_retriever
 import sentry_flutter
 import share_plus
 import shared_preferences_foundation
-import smart_auth
 import sodium_libs
 import sqflite
 import sqlite3_flutter_libs
@@ -44,7 +43,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
   SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin"))
   SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
   SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
-  SmartAuthPlugin.register(with: registry.registrar(forPlugin: "SmartAuthPlugin"))
   SodiumLibsPlugin.register(with: registry.registrar(forPlugin: "SodiumLibsPlugin"))
   SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
   Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))

+ 2 - 18
auth/pubspec.lock

@@ -1109,10 +1109,10 @@ packages:
     dependency: "direct main"
     description:
       name: pinput
-      sha256: a92b55ecf9c25d1b9e100af45905385d5bc34fc9b6b04177a9e82cb88fe4d805
+      sha256: "27eb69042f75755bdb6544f6e79a50a6ed09d6e97e2d75c8421744df1e392949"
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.1"
+    version: "1.2.2"
   platform:
     dependency: transitive
     description:
@@ -1334,14 +1334,6 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.99"
-  smart_auth:
-    dependency: transitive
-    description:
-      name: smart_auth
-      sha256: a25229b38c02f733d0a4e98d941b42bed91a976cb589e934895e60ccfa674cf6
-      url: "https://pub.dev"
-    source: hosted
-    version: "1.1.1"
   sodium:
     dependency: transitive
     description:
@@ -1551,14 +1543,6 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.2.2"
-  universal_platform:
-    dependency: transitive
-    description:
-      name: universal_platform
-      sha256: d315be0f6641898b280ffa34e2ddb14f3d12b1a37882557869646e0cc363d0cc
-      url: "https://pub.dev"
-    source: hosted
-    version: "1.0.0+1"
   url_launcher:
     dependency: "direct main"
     description:

+ 2 - 2
auth/pubspec.yaml

@@ -1,6 +1,6 @@
 name: ente_auth
 description: ente two-factor authenticator
-version: 2.0.50+250
+version: 2.0.51+251
 publish_to: none
 
 environment:
@@ -75,7 +75,7 @@ dependencies:
   password_strength: ^0.2.0
   path: ^1.8.3
   path_provider: ^2.0.11
-  pinput: ^3.0.1
+  pinput: ^1.2.2
   pointycastle: ^3.7.3
   privacy_screen: ^0.0.6
   protobuf: ^3.0.0

+ 0 - 3
auth/windows/flutter/generated_plugin_registrant.cc

@@ -16,7 +16,6 @@
 #include <screen_retriever/screen_retriever_plugin.h>
 #include <sentry_flutter/sentry_flutter_plugin.h>
 #include <share_plus/share_plus_windows_plugin_c_api.h>
-#include <smart_auth/smart_auth_plugin.h>
 #include <sodium_libs/sodium_libs_plugin_c_api.h>
 #include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
 #include <tray_manager/tray_manager_plugin.h>
@@ -44,8 +43,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
       registry->GetRegistrarForPlugin("SentryFlutterPlugin"));
   SharePlusWindowsPluginCApiRegisterWithRegistrar(
       registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
-  SmartAuthPluginRegisterWithRegistrar(
-      registry->GetRegistrarForPlugin("SmartAuthPlugin"));
   SodiumLibsPluginCApiRegisterWithRegistrar(
       registry->GetRegistrarForPlugin("SodiumLibsPluginCApi"));
   Sqlite3FlutterLibsPluginRegisterWithRegistrar(

+ 0 - 1
auth/windows/flutter/generated_plugins.cmake

@@ -13,7 +13,6 @@ list(APPEND FLUTTER_PLUGIN_LIST
   screen_retriever
   sentry_flutter
   share_plus
-  smart_auth
   sodium_libs
   sqlite3_flutter_libs
   tray_manager

+ 4 - 77
docs/docs/.vitepress/sidebar.ts

@@ -202,6 +202,10 @@ export const sidebar = [
             {
                 text: "Troubleshooting",
                 items: [
+                    {
+                        text: "Uploads",
+                        link: "/self-hosting/troubleshooting/uploads",
+                    },
                     {
                         text: "Yarn",
                         link: "/self-hosting/troubleshooting/yarn",
@@ -219,80 +223,3 @@ export const sidebar = [
         link: "/about/contribute",
     },
 ];
-
-function sidebarOld() {
-    return [
-        {
-            text: "Welcome",
-            items: [
-                {
-                    text: "Features",
-                    collapsed: true,
-                    items: [
-                        {
-                            text: "Family Plan",
-                            link: "/photos/features/family-plan",
-                        },
-                        { text: "Albums", link: "/photos/features/albums" },
-                        { text: "Archive", link: "/photos/features/archive" },
-                        { text: "Hidden", link: "/photos/features/hidden" },
-                        { text: "Map", link: "/photos/features/map" },
-                        {
-                            text: "Location Tags",
-                            link: "/photos/features/location",
-                        },
-                        {
-                            text: "Collect Photos",
-                            link: "/photos/features/collect",
-                        },
-                        {
-                            text: "Public links",
-                            link: "/photos/features/public-links",
-                        },
-                        {
-                            text: "Quick link",
-                            link: "/photos/features/quick-link",
-                        },
-                        {
-                            text: "Watch folder",
-                            link: "/photos/features/watch-folders",
-                        },
-                        { text: "Trash", link: "/photos/features/trash" },
-                        {
-                            text: "Uncategorized",
-                            link: "/photos/features/uncategorized",
-                        },
-                        {
-                            text: "Referral Plan",
-                            link: "/photos/features/referral",
-                        },
-                        {
-                            text: "Live & Motion Photos",
-                            link: "/photos/features/live-photos",
-                        },
-                        { text: "Cast", link: "/photos/features/cast" },
-                    ],
-                },
-                {
-                    text: "Troubleshoot",
-                    collapsed: true,
-                    link: "/photos/troubleshooting/files-not-uploading",
-                    items: [
-                        {
-                            text: "Files not uploading",
-                            link: "/photos/troubleshooting/files-not-uploading",
-                        },
-                        {
-                            text: "Failed to play video",
-                            link: "/photos/troubleshooting/video-not-playing",
-                        },
-                        {
-                            text: "Report bug",
-                            link: "/photos/troubleshooting/report-bug",
-                        },
-                    ],
-                },
-            ],
-        },
-    ];
-}

+ 10 - 8
docs/docs/photos/faq/export.md

@@ -12,15 +12,17 @@ in a local drive or NAS of your choice. This way, you can use Ente in your day
 to day use, but will have an additional guarantee that a copy of your original
 photos and videos are always available in normal directories and files.
 
-* 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
-  are incremental, and will also gracefully handle interruptions.
+-   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 are
+    incremental, and will also gracefully handle interruptions.
 
-* Similarly, you can use Ente's [desktop app](https://ente.io/download/desktop)
-  to export your data to a folder of your choice. The desktop app also supports
-  "continuous" exports, where it will automatically export new items in the
-  background without you needing to run any other cron jobs. See
-  [migration/export](/photos/migration/export/) for more details.
+-   Similarly, you can use Ente's
+    [desktop app](https://ente.io/download/desktop) to export your data to a
+    folder of your choice. The desktop app also supports "continuous" exports,
+    where it will automatically export new items in the background without you
+    needing to run any other cron jobs. See
+    [migration/export](/photos/migration/export/) for more details.
 
 ## Does the exported data from Ente photos preserve the same folder and album structure as in the app?
 

+ 15 - 6
docs/docs/photos/faq/general.md

@@ -77,26 +77,35 @@ It's like cafe 😊. kaf-_ay_. en-_tay_.
 
 ## Does Ente apply compression to uploaded photos?
 
-Ente does not apply compression to uploaded photos. The file size of your photos in Ente will be similar to the original file sizes you have.
+Ente does not apply compression to uploaded photos. The file size of your photos
+in Ente will be similar to the original file sizes you have.
 
 ## Can I add photos from a shared album to albums that I created in Ente?
 
-Currently, Ente does not support adding photos from a shared album to your personal albums. If you want to include photos from a shared album in your own albums, you will need to ask the owner of the photos to add them to your album. 
+Currently, Ente does not support adding photos from a shared album to your
+personal albums. If you want to include photos from a shared album in your own
+albums, you will need to ask the owner of the photos to add them to your album.
 
 ## How do I ensure that the Ente desktop app stays up to date on my system?
 
-Ente desktop includes an auto-update feature, ensuring that whenever updates are deployed, the app will automatically download and install them. You don't need to manually update the software.
+Ente desktop includes an auto-update feature, ensuring that whenever updates are
+deployed, the app will automatically download and install them. You don't need
+to manually update the software.
 
 ## Can I sync a folder containing multiple subfolders, each representing an album?
 
-Yes, when you drag and drop the folder onto the desktop app, the app will detect the multiple folders and prompt you to choose whether you want to create a single album or separate albums for each folder.
+Yes, when you drag and drop the folder onto the desktop app, the app will detect
+the multiple folders and prompt you to choose whether you want to create a
+single album or separate albums for each folder.
 
 ## What is the difference between **Magic** and **Content** search results on the desktop?
 
-**Magic** is where you can search for long queries. Like, "baby in red dress", or "dog playing at the beach".
+**Magic** is where you can search for long queries. Like, "baby in red dress",
+or "dog playing at the beach".
 
 **Content** is where you can search for single-words. Like, "car" or "pizza".
 
 ## 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."
+Check the sections within the upload progress bar for "Failed Uploads," "Ignored
+Uploads," and "Unsuccessful Uploads."

+ 3 - 1
docs/docs/photos/faq/subscription.md

@@ -159,4 +159,6 @@ We do offer a generous free trial for you to experience the product.
 
 ## Will I need to pay for Ente Auth after my Ente Photos free plan expires?
 
-No, you will not need to pay for Ente Auth after your Ente Photos free plan expires. Ente Auth is completely free to use, and the expiration of your Ente Photos free plan will not impact your ability to access or use Ente Auth.
+No, you will not need to pay for Ente Auth after your Ente Photos free plan
+expires. Ente Auth is completely free to use, and the expiration of your Ente
+Photos free plan will not impact your ability to access or use Ente Auth.

+ 11 - 9
docs/docs/photos/migration/export/index.md

@@ -13,7 +13,7 @@ videos you have uploaded to Ente.
 
     ![Ente - Sign in to export data](sign-in.png)
 
-2. Open the side bar, and select the option to **export data**.
+2. Open the side bar, and select the option to **Export Data**.
 
     ![Ente - Export data](export-1.png)
 
@@ -33,7 +33,7 @@ videos you have uploaded to Ente.
 
 </div>
 
-5. Wait for the export to get completed.
+5. Wait for the export to complete.
 
 <div align="center">
 
@@ -42,7 +42,7 @@ videos you have uploaded to Ente.
 </div>
 
 6. In case your download gets interrupted, Ente will resume from where it left
-   off. Simply select **export data** again and click on **Resync**.
+   off. Simply select **Export Data** again and click on **Resync**.
 
 <div align="center">
 
@@ -50,18 +50,20 @@ videos you have uploaded to Ente.
 
 </div>
 
-7. **Sync continuously** : You can utilize Continuous Sync to eliminate manual
-   exports each time new photos are added to Ente. This feature automatically
-   detects new files and runs exports accordingly, It also ensures that exported
-   data reflects the latest album states with new files, moves, and deletions.
+### Sync continuously
 
-    ![Ente - Continuous sync](continuous-sync.webp)
+You can switch on the toggle to **Sync continuously** to eliminate manual
+exports each time new photos are added to Ente. This feature automatically
+detects new files and runs exports accordingly. It also ensures that exported
+data reflects the latest album states with new files, moves, and deletions.
 
+![Ente - Continuous sync](continuous-sync.webp)
 
+---
 
 If you run into any issues during your data export, please reach out to
 [support@ente.io](mailto:support@ente.io) and we will be happy to help you!
 
 Note that we also provide a [CLI
 tool](https://github.com/ente-io/ente/tree/main/cli#export) to export your data.
-Some more details are in this [FAQ entry](/photos/faq/export).
+Please find more details [here](/photos/faq/export).

+ 22 - 8
docs/docs/self-hosting/guides/admin.md

@@ -24,18 +24,32 @@ and subsequently increase the
 [storage and account validity](https://github.com/ente-io/ente/blob/main/cli/docs/generated/ente_admin_update-subscription.md)
 using the CLI.
 
-For the admin actions, you can create `server/museum.yaml`, and whitelist add
-the admin userID `internal.admins`. See
-[local.yaml](https://github.com/ente-io/ente/blob/main/server/configurations/local.yaml#L211C1-L232C1)
+For security purposes, we need to whitelist the user IDs that can perform admin
+actions on the server. To do this,
+
+-   Create a `museum.yaml` in the directory where you're starting museum from.
+    For example, if you're running using `docker compose up`, then this file
+    should be in the same directory as `compose.yaml` (generally,
+    `server/museum.yaml`).
+
+    > Docker might've created an empty `museum.yaml` _directory_ on your machine
+    > previously. If so, delete that empty directory and create a new file named
+    > `museum.yaml`.
+
+-   In this `museum.yaml` we can add overrides over the default configuration.
+
+For whitelisting the admin userIDs we need to define an `internal.admins`. See
+the "internal" section in
+[local.yaml](https://github.com/ente-io/ente/blob/main/server/configurations/local.yaml)
 in the server source code for details about how to define this.
 
+Here is an example. Suppose we wanted to whitelist a user with ID
+`1580559962386440`, we can create the following `museum.yaml`
+
 ```yaml
-....
 internal:
-  admins:
-    # - 1580559962386440
-
-....
+    admins:
+        - 1580559962386440
 ```
 
 You can use

+ 2 - 2
docs/docs/self-hosting/index.md

@@ -26,8 +26,8 @@ docker compose up --build
 
 > [!TIP]
 >
-> You can also use a pre-built Docker image from `ghcr.io/ente-io/server` ([More
-> info](https://github.com/ente-io/ente/blob/main/server/docs/docker.md))
+> You can also use a pre-built Docker image from `ghcr.io/ente-io/server`
+> ([More info](https://github.com/ente-io/ente/blob/main/server/docs/docker.md))
 
 Then in a separate terminal, you can run (e.g) the web client
 

+ 13 - 0
docs/docs/self-hosting/troubleshooting/uploads.md

@@ -0,0 +1,13 @@
+---
+title: Uploads failing
+description: Fixing upload errors when trying to self host Ente
+---
+
+# Uploads failing
+
+If uploads to your self-hosted server are failing, make sure that
+`credentials.yaml` has `yourserverip:3200` for all three minio locations.
+
+By default it is `localhost:3200`, and it needs to be changed to an IP that is
+accessible from both where you are running the Ente clients (e.g. the mobile
+app) and also from within the Docker compose cluster.

+ 54 - 0
infra/services/listmonk/README.md

@@ -0,0 +1,54 @@
+# Listmonk
+
+We use [Listmonk](https://listmonk.app/) to manage our mailing lists.
+
+- Museum lets Listmonk know about new users and account deletion (this allows
+  Listmonk to create corresponding accounts).
+
+- Subsequently, Listmonk handles user subscription / unsubscription etc
+  (Listmonk stores its data in an external Postgres).
+
+## Installing
+
+Install [nginx](../nginx/README.md).
+
+Add Listmonk's configuration.
+
+```sh
+sudo mkdir -p /root/listmonk
+sudo tee /root/listmonk/config.toml
+```
+
+Add the service definition and nginx configuration.
+
+```sh
+scp services/listmonk/listmonk.* <instance>:
+
+sudo mv listmonk.service /etc/systemd/system/
+sudo mv listmonk.nginx.conf /root/nginx/conf.d
+```
+
+> The very first time we ran Listmonk, at this point we also needed to get it to
+> install the tables it needs in the Postgres DB. For this, we used the
+> `initialize-db.sh` script.
+>
+> ```sh
+> scp services/listmonk/initialize-db.sh <instance>:
+>
+> sudo sh initialize-db.sh
+> rm initialize-db.sh
+> ```
+
+Tell systemd to pick up new service definitions, enable the unit (so that it
+automatically starts on boot), and start it this time around.
+
+```sh
+sudo systemctl daemon-reload
+sudo systemctl enable --now listmonk
+```
+
+Tell nginx to pick up the new configuration.
+
+```sh
+sudo systemctl reload nginx
+```

+ 14 - 0
infra/services/listmonk/initialize-db.sh

@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# This script needs to be manually run the once (and only once) before starting
+# Listmonk for the first time. It uses the provided credentials to initialize
+# its database.
+
+set -o errexit
+set -o xtrace
+
+docker pull listmonk/listmonk
+
+docker run -it --rm --name listmonk \
+    -v /root/listmonk/config.toml:/listmonk/config.toml:ro \
+    listmonk/listmonk ./listmonk --install

+ 26 - 0
infra/services/listmonk/listmonk.nginx.conf

@@ -0,0 +1,26 @@
+# This file gets loaded in a top level http block by the default nginx.conf
+# See infra/services/nginx/README.md for more details.
+
+server {
+    listen 443 ssl;
+    listen [::]:443 ssl;
+    http2 on;
+    ssl_certificate         /etc/ssl/certs/cert.pem;
+    ssl_certificate_key     /etc/ssl/private/key.pem;
+
+    server_name lists.ente.io;
+
+    location / {
+        proxy_pass http://host.docker.internal:9000;
+        proxy_set_header Host $host;
+        proxy_set_header X-Real-IP $remote_addr;
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header X-Forwarded-Proto $scheme;
+
+        # Use HTTP/1.1 when talking to upstream
+        # Also, while not necessary (AFAIK), also allow websockets.
+        proxy_http_version 1.1;
+        proxy_set_header   Upgrade $http_upgrade;
+        proxy_set_header   Connection "upgrade";
+    }
+}

+ 19 - 0
infra/services/listmonk/listmonk.service

@@ -0,0 +1,19 @@
+[Unit]
+Documentation=https://listmonk.app/docs/installation/
+Requires=docker.service
+After=docker.service
+
+[Install]
+WantedBy=multi-user.target
+
+[Service]
+ExecStartPre=docker pull listmonk/listmonk
+ExecStartPre=-docker stop listmonk
+ExecStartPre=-docker rm listmonk
+ExecStartPre=-docker run --rm --name listmonk \
+    -v /root/listmonk/config.toml:/listmonk/config.toml:ro \
+    listmonk/listmonk ./listmonk --upgrade --yes
+ExecStart=docker run --name listmonk \
+    -p 9000:9000 \
+    -v /root/listmonk/config.toml:/listmonk/config.toml:ro \
+    listmonk/listmonk

+ 9 - 0
infra/services/nginx/README.md

@@ -62,3 +62,12 @@ We can see this in the default configuration of nginx:
 This is a [handy tool](https://nginx-playground.wizardzines.com) to check the
 syntax of the configuration files. Alternatively, you can run `docker exec nginx
 nginx -t` on the instance to ask nginx to check the configuration.
+
+## Updating configuration
+
+Nginx configuration files can be changed without needing to restart anything.
+
+1. Update the configuration file at `/root/nginx/conf.d/museum.conf`
+2. Verify that there are no errors in the configuration by using `sudo docker
+   exec nginx nginx -t`.
+3. Ask nginx to reload the configuration `sudo systemctl reload nginx`.

+ 3 - 2
infra/services/status/uptime-kuma.nginx.conf

@@ -2,8 +2,9 @@
 # See infra/services/nginx/README.md for more details.
 
 server {
-    listen 443 ssl http2;
-    listen [::]:443 ssl http2;
+    listen 443 ssl;
+    listen [::]:443 ssl;
+    http2 on;
     ssl_certificate         /etc/ssl/certs/cert.pem;
     ssl_certificate_key     /etc/ssl/private/key.pem;
 

+ 36 - 0
mobile/android/app/src/main/play/listings/de/full_description.txt

@@ -0,0 +1,36 @@
+ente ist eine einfache App, um Ihre Fotos und Videos automatisch zu sichern und zu organisieren.
+
+Wenn Sie auf der Suche nach einer datenschutzfreundlichen Alternative zu Google Fotos sind, sind Sie an der richtigen Stelle. Mit Ente werden Ihre Fotos Ende-zu-Ende-verschlüsselt gespeichert (e2ee). Dies bedeutet, dass nur Sie sie sehen können.
+
+Ihre Fotos werden verschlüsselt (e2ee) zwischen allen Geräten synchronisiert.
+
+ente ermöglicht es, deine Alben simpel & schnell mit deinen Geliebten zu teilen. Sie können öffentlich einsehbare Links teilen, sodass andere sogar ohne einen Account oder eine App Ihr Album sehen und darin zusammenarbeiten können, indem sie Fotos hinzufügen.
+
+Ihre verschlüsselten Daten werden an 3 verschiedenen Orten gespeichert, unter anderem in einem Schutzbunker in Paris. Wir nehmen die Erhaltung der Nachwelt ernst und machen es Ihnen leicht, dafür zu sorgen, dass Ihre Erinnerungen Sie überdauern.
+
+Wir sind hier, um die sicherste Foto-App aller Zeiten zu entwickeln, begleite uns auf unserem Weg!
+
+FEATURES
+- Sicherungen in Originalqualität, weil jeder Pixel zählt
+- Familien-Abos, damit Sie den Speicherplatz mit Ihrer Familie teilen können
+- Kollaborative Alben, sodass Sie nach einer Reise Fotos sammeln können
+- Geteilte Ordner für den Fall, dass Ihr Partner Ihre "Kamera" Klicks genießen soll
+- Album-Links, die mit einem Passwort geschützt werden können
+- Möglichkeit, Speicherplatz freizugeben, indem bereits gesicherte Daten auf dem Gerät entfernt werden
+- Menschlicher Support, denn Sie sind es wert
+- Beschreibungen, damit Sie Ihre Erinnerungen beschriften und leicht wiederfinden können
+- Foto-Editor, um Ihren Fotos den Feinschliff zu verpassen
+- Favorisieren, verstecken und erleben Sie Ihre Erinnerungen, denn sie sind kostbar
+- Ein-Klick-Import von Google, Apple, Ihrer Festplatte und mehr
+- Dunkles Theme, weil Ihre Fotos darin gut aussehen
+- 2FA, 3FA, biometrische Authentifizierung
+- und noch VIELES mehr!
+
+BERECHTIGUNGEN
+Diese können unter folgendem Link überprüft werden: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
+
+PREIS
+Wir bieten keine lebenslang kostenlosen Abonnements an, da es für uns wichtig ist, einen nachhaltigen Service anzubieten. Wir bieten jedoch bezahlbare Abonemments an, welche auch mit der Familie geteilt werden können. Mehr Informationen sind auf ente.io zu finden.
+
+SUPPORT
+Wir sind stolz darauf, einen persönlichen Support anzubieten. Falls Sie ein Abonnement besitzen, können Sie sich mit Ihrem Anliegen via E-Mail an team@ente.io wenden und erhalten eine Antwort innerhalb von 24 Stunden.

+ 1 - 0
mobile/android/app/src/main/play/listings/de/short_description.txt

@@ -0,0 +1 @@
+ente ist eine Ende-zu-Ende-verschlüsselte Fotospeicher-App

+ 1 - 0
mobile/android/app/src/main/play/listings/de/title.txt

@@ -0,0 +1 @@
+ente - verschlüsselter Fotospeicher

+ 36 - 0
mobile/android/app/src/main/play/listings/en-US/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.

二进制
mobile/android/app/src/main/play/listings/en-US/graphics/icon/icon.png


二进制
mobile/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/1.png


二进制
mobile/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/2.png


二进制
mobile/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/3.png


二进制
mobile/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/4.png


二进制
mobile/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/5.png


二进制
mobile/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/6.png


二进制
mobile/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/7.png


+ 1 - 0
mobile/android/app/src/main/play/listings/en-US/short_description.txt

@@ -0,0 +1 @@
+Ente Photos is an open source photos app, that provides end-to-end encrypted backups for your photos and videos.

+ 1 - 0
mobile/android/app/src/main/play/listings/en-US/title.txt

@@ -0,0 +1 @@
+Ente Photos - Open source, end-to-end encrypted alternative to Google Photos

+ 36 - 0
mobile/android/app/src/main/play/listings/es/full_description.txt

@@ -0,0 +1,36 @@
+ente es una aplicación simple para hacer copias de seguridad y compartir tus fotos y videos.
+
+Si has estado buscando una alternativa a Google Photos que sea amigable con la privacidad, has llegado al lugar correcto. Con Ente, se almacenan cifradas de extremo a extremo (e2ee). Esto significa que solo tú puedes verlas.
+
+Tenemos aplicaciones en Android, iOS, web y escritorio, y tus fotos se sincronizarán perfectamente entre todos tus dispositivos encriptadas de extremo a extremo (e2ee).
+
+ente también hace fácil compartir tus álbumes con tus seres queridos, incluso si no están en ente. Puedes compartir enlaces visibles públicamente, donde pueden ver tu álbum y colaborar añadiendo fotos a él, incluso sin una cuenta o aplicación.
+
+Sus datos cifrados se replican en 3 ubicaciones diferentes, incluyendo un bunker en París. Nos tomamos la posteridad en serio y facilitamos que sus recuerdos sobrevivan a usted.
+
+Estamos aquí para hacer la aplicación de fotos más segura jamás creada, ¡únete a nuestro viaje!
+
+CARACTERÍSTICAS
+- Copias de seguridad con la calidad original, porque cada pixel es importante
+- Planes familiares, para que puedas compartir el almacenamiento con tu familia
+- Álbumes colaborativos, para que puedas juntar fotos después de un viaje
+- Carpetas compartidas, por si quieres que tu pareja disfrute de tus fotos
+- Enlaces al álbum, que se pueden proteger con una contraseña
+- Capacidad para liberar espacio, eliminando archivos de los que ya tienes una copia de seguridad
+- Apoyo humano, porque tú lo vales
+- Descripciones, para que puedas encontrar tus recuerdos fácilmente
+- Editor de imagen, para añadir retoques finales
+- Marca como favoritos, oculta y revive tus recuerdos, porque son preciosos
+- Importa en un click desde Google, Apple, tu disco duro y más
+- Tema oscuro, porque tus fotos quedan bien con él
+- 2FA, 3FA, autenticación biométrica
+- ¡Y mucho más!
+
+PERMISOS
+ente solicita ciertos permisos para servir al propósito de un proveedor de almacenamiento de fotos, que puede ser revisado aquí: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
+
+PRECIOS
+No ofrecemos planes gratis para siempre, porque es importante para nosotros seguir siendo sostenibles y resistir a la prueba del tiempo. En su lugar, ofrecemos planes asequibles que puedes compartir libremente con tu familia. Puedes encontrar más información en ente.io.
+
+SOPORTE
+Estamos orgullosos de ofrecer apoyo humano. Si eres un cliente de pago, puedes contactar con team@ente.io y esperar una respuesta de nuestro equipo en 24 horas.

+ 1 - 0
mobile/android/app/src/main/play/listings/es/short_description.txt

@@ -0,0 +1 @@
+ente es una aplicación de almacenamiento de fotos cifrado de extremo a extremo

+ 1 - 0
mobile/android/app/src/main/play/listings/es/title.txt

@@ -0,0 +1 @@
+ente - almacenamiento de fotos encriptado

+ 36 - 0
mobile/android/app/src/main/play/listings/fr/full_description.txt

@@ -0,0 +1,36 @@
+entre est une application simple qui permet de sauvegarder et partager vos photos et vidéos.
+
+Si vous êtes à la recherche d'une alternative à Google Photos respectueuse de la vie privée, vous êtes au bon endroit. Avec ente, ils sont stockés chiffrés de bout-en-bout (e2ee). Cela signifie que vous-seul pouvez les voir.
+
+Nous avons des applications sur Android, iOS, Web et Ordinateur, et vos photos seront synchronisées de manière transparente entre tous vos appareils chiffrée de bout en bout (e2ee).
+
+ente vous permet également de partager vos albums avec vos proches, même s'ils ne sont pas sur ente. Vous pouvez partager des liens visibles publiquement, où ils peuvent voir votre album et collaborer en y ajoutant des photos, même sans compte ou application.
+
+Vos données chiffrées sont répliqué à 3 endroits différents, dont un abri antiatomique à Paris. Nous prenons la postérité au sérieux et facilitons la conservation de vos souvenirs.
+
+Nous sommes là pour faire l'application photo la plus sûre de tous les temps, rejoignez-nous !
+
+CARACTÉRISTIQUES
+- Sauvegardes de qualité originales, car chaque pixel est important
+- Abonnement familiaux, pour que vous puissiez partager l'espace de stockage avec votre famille
+- Albums collaboratifs, pour que vous puissiez regrouper des photos après un voyage
+- Dossiers partagés, si vous voulez que votre partenaire profite de vos clichés
+- Liens ves les albums qui peuvent être protégés par un mot de passe
+- Possibilité de libérer de l'espace en supprimant les fichiers qui ont été sauvegardés en toute sécurité
+- Support humain, car vous en valez la peine
+- Descriptions, afin que vous puissiez légender vos souvenirs et les retrouver facilement
+- Éditeur d'images, pour ajouter des touches de finition
+- Favoriser, cacher et revivre vos souvenirs, car ils sont précieux
+- Importation en un clic depuis Google, Apple, votre disque dur et plus encore
+- Thème sombre, parce que vos photos y sont jolies
+- 2FA, 3FA, authentification biométrique
+- et beaucoup de choses encore !
+
+PERMISSIONS
+ente sollicite diverses autorisations dans le but de fonctionner en tant que service de stockage de photos, et ces autorisations sont détaillées ici : https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
+
+PRIX
+Nous ne proposons pas d'abonnement gratuits pour toujours, car il est important pour nous de rester durables et de résister à l'épreuve du temps. Au lieu de cela, nous vous proposons des abonnements abordables que vous pouvez partager librement avec votre famille. Vous pouvez trouver plus d'informations sur ente.io.
+
+ASSISTANCE
+Nous sommes fiers d'offrir un support humain. Si vous êtes un abonné, vous pouvez contacter team@ente.io et vous recevrez une réponse de notre équipe dans les 24 heures.

+ 1 - 0
mobile/android/app/src/main/play/listings/fr/short_description.txt

@@ -0,0 +1 @@
+ente est une application de stockage de photos chiffrées de bout en bout

+ 1 - 0
mobile/android/app/src/main/play/listings/fr/title.txt

@@ -0,0 +1 @@
+ente - stockage de photos chiffré

+ 36 - 0
mobile/android/app/src/main/play/listings/he/full_description.txt

@@ -0,0 +1,36 @@
+האפליקציה Ente היא אפליקציה פשוטה לגיבוי ושיתוף של התמונות והסרטונים שלך.
+
+אם חיפשת אלטרנטיבה ידידותית לפרטיות לGoogle Photos, הגעת למקום הנכון. עם Ente, התמונות והסרטונים מאוחסנים בצורה מאובטחת באמצעות הצפנה קצה-אל-קצה (e2ee). זה אומר שרק אתה יכול לצפות בהם.
+
+יש לנו אפלקציות קוד פתוח זמינות לAndroid, iOS, רשת ולמחשב, וכל התמונות שלך ייסתנכרנו באופן חלק בין כולם באופן מאובטח על ידי הצפנה קצה-אל-קצה (e2ee).
+
+ente גם מקל על שיתוף האלבומים שלך עם קרובך, גם אם הם אינם ב-ente. תוכל לשתף קישורים שניתן לצפות בהם בצורה פומבית, שבאמצעותם יתאפשר להם לצפות באלבום שלך ולשתף פעולה על ידי הוספת תמונות אליו, גם בלי חשבון או האפליקציה.
+
+הנתונים המוצפנים שלך מאוחסנים ב3 מקומות שונים, כולל מקלט גרעיני בפריז. אנחנו מתייחסים ברצינות לעתידות ומקלים עליך לוודא שזכרונותיך ישרדו אחרייך.
+
+הגענו לכאן כדי ליצור את היישומון לתמונות המאובטח ביותר אי פעם, הצטרפו אלינו למסע!
+
+מאפיינים
+- גיבויים באיכות המקורית, כי כל פיקסל חשוב
+- תוכניות משפחתיות, כך שתוכלו לשתף אחסון עם המשפחה שלכם
+- אלבומים משותפים, כך שתוכל לאגד יחד תמונות אחרי טיול
+- תיקיות משותפות, במקרה ותרצה שהבן זוג שלך יהנה מהקליקים של ה"מצלמה" שלך
+- קישורי אלבום, המאובטחים בעזרת סיסמא
+- יכולת לשחרר מקום, על ידי הסרת קבצים שכבר גובו באופן מאובטח
+- תמיכה אנושית, כי אתה שווה את זה
+- תיאורים, כך שתוכל לתאר את הזכרונות שלך ולמצוא אותם בקלות
+- עורך תמונות, להוסיף למראה הסופי
+- סמן כמועדפים, הסתר ולחזור על זכרונות שלך, כי הם יקרים ללבך
+- ייבוא בלחיצה אחת מ-Google, Apple, הכונן הקשיח שלך ועוד
+- ערכת נושא כהה, כי התמונות שלך נראות יפות בה
+- 2FA, 3FA, אימות ביומטרי
+- ועוד הרבה יותר!
+
+הרשאות
+ente מבקש הרשאות מסוימות כדי לספק שירותי אחסון תמונות, וניתן לסקור אותן כאן: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
+
+מחיר
+אנחנו לא מציעים תוכניות בחינם לתמיד, משום שזה חשוב לנו להיות עמידים ולעמוד במבחן הזמן. במקום זאת אנחנו מציעים תוכניות במחיר סביר כדי שתוכל לשתף באופן חופשי עם המשפחה שלך. ניתן למצוא עוד מידע ב-ente.io.
+
+תמיכה
+אנחנו גאים להציע תמיכה אנושית. אם אתה לקום משלם, אתה יכול לפנות אלינו בכתובת team@ente.io ולצפות לתשובה תוך 24 שעות.

+ 1 - 0
mobile/android/app/src/main/play/listings/he/short_description.txt

@@ -0,0 +1 @@
+ente הוא אפליקציה לאחסון תמונות המשתמשת בהצפנה קצה-אל-קצה

+ 1 - 0
mobile/android/app/src/main/play/listings/he/title.txt

@@ -0,0 +1 @@
+ente - אחסון תמונות באופן מוצפן

+ 36 - 0
mobile/android/app/src/main/play/listings/it/full_description.txt

@@ -0,0 +1,36 @@
+ente è una semplice app per il backup e la condivisione di foto e video.
+
+Se siete alla ricerca di un'alternativa rispettosa della privacy a Google Photos, siete nel posto giusto. Con ente, sono memorizzati con crittografia end-to-end (e2ee). Questo significa che solo tu puoi vederli.
+
+Abbiamo applicazioni open-source su Android, iOS, web e desktop, e le tue foto saranno sincronizzate tra tutti i dispositivi utilizzando la crittografia end-to-end (e2ee).
+
+ente rende anche semplice condividere i tuoi album con i tuoi cari, anche se non sono utenti ente. Puoi condividere link visualizzabili pubblicamente, dove possono visualizzare il tuo album e collaborare aggiungendo le foto, anche senza un account o un'app installata.
+
+I tuoi dati crittografati vengono replicati in 3 luoghi diversi, tra cui un rifugio antiatomico a Parigi. I tuoi ricordi continueranno a vivere anche quando non ci sarai più.
+
+Siamo qui per creare l'app per la gestione di foto e video più sicura di sempre, unisciti al nostro viaggio!
+
+CARATTERISTICHE
+- Backup di qualità originale, perché ogni pixel è importante
+- Piani famiglia, in modo da poter condividere lo spazio disponibile con la tua famiglia
+- Album collaborativi, per poter mettere insieme le foto dopo un viaggio
+- Cartelle condivise, nel caso in cui desideri condividere le tue foto subito con il tuo o la tua partner
+- Collegamenti di album, che possono essere anche protetti con una password
+- Possibilità di liberare spazio, rimuovendo i file che sono stati salvati in modo sicuro
+- Supporto umano, perché ne vale la pena
+- Descrizioni, in modo da poter descrivere i tuoi ricordi e trovarli facilmente
+- Editor di immagini, per ritocchi finali
+- Preferiti, nascondi e rivivi i tuoi ricordi, perché sono preziosi
+- Importa da Google, Apple o dal tuo hard disk con un semplice clic
+- Tema scuro, per valorizzare le tue foto
+- 2FA, 3FA, Autenticazione biometrica
+- e molto altro ancora!
+
+PERMESSI
+ente richiede alcune autorizzazioni per servire lo scopo di un provider di storage fotografico, che può essere esaminato qui: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
+
+PREZZO
+Non offriamo piani gratuiti per sempre, perché per noi è importante rimanere sostenibili e resistere alla prova del tempo. Offriamo invece piani accessibili che si possono condividere liberamente con la propria famiglia. Puoi trovare maggiori informazioni su ente.io.
+
+SUPPORTO
+Siamo orgogliosi di offrire supporto umano. Se sei un nostro cliente a pagamento, puoi contattare team@ente.io e aspettarti una risposta dal nostro team entro 24 ore.

+ 1 - 0
mobile/android/app/src/main/play/listings/it/short_description.txt

@@ -0,0 +1 @@
+ente è un'applicazione di archiviazione foto e video crittografata end-to-end

+ 1 - 0
mobile/android/app/src/main/play/listings/it/title.txt

@@ -0,0 +1 @@
+ente - archivio fotografico crittografato

+ 36 - 0
mobile/android/app/src/main/play/listings/nl/full_description.txt

@@ -0,0 +1,36 @@
+ente is een eenvoudige app om jouw foto's en video's automatisch te back-uppen en delen.
+
+Als je op zoek bent naar een privacy-vriendelijk alternatief voor Google Photos, dan ben je hier op de juiste plaats. Bij ente worden ze end-to-end encrypted (e2ee). Dit betekent dat alleen jij ze kunt bekijken.
+
+We hebben open-source apps op Android, iOS, web en Desktop, en je foto's zullen naadloos synchroniseren tussen al je apparaten op een end-to-end versleutelde (e2ee) manier.
+
+ente maakt het ook simpeler om album te delen met je dierbaren, zelfs als die ente niet gebruiken. Je kunt openbaar zichtbare links delen, waar anderen jouw album kunnen bekijken en er foto's aan toe kunnen voegen, zelfs zonder account of app.
+
+Jouw versleutelde gegevens worden drievoudig opgeslagen op meerdere locaties, waaronder een kernbunker in Parijs. Wij nemen opslag voor de lange termijn serieus, en zorgen ervoor dat je herinneringen minstens je hele leven bewaard worden.
+
+Ons doel is om de veiligste foto app ooit te maken, sluit je bij ons aan!
+
+FUNCTIES
+- Backups van originele kwaliteit, omdat elke pixel belangrijk is
+- Familieplannen, zodat je de opslag kunt delen met je familie
+- Gezamenlijke albums, zodat je foto's kunt samenvoegen na een reis
+- Gedeelde mappen, voor het geval je jouw partner wilt laten meegenieten van jouw "Camera" klikjes
+- Album links, die met een wachtwoord beschermd kunnen worden
+- Mogelijkheid om ruimte vrij te maken op je apparaat, door bestanden die veilig zijn geback-upt te verwijderen
+- Menselijke klantenservice, omdat je het waard bent
+- Beschrijvingen, zodat je je herinneringen kunt bijhouden en ze gemakkelijk kunt vinden
+- Fotobewerker om de laatste finishing touches toe te voegen
+- Favorieten, verbergen en herleven van je herinneringen, want ze zijn kostbaar
+- Met één klik importeren vanuit Google, Apple, je harde schijf en meer
+- Donker thema, omdat je foto's er goed in uit zien
+- 2FA, 3FA, biometrische authenticatie
+- en nog veel meer!
+
+TOESTEMMINGEN
+ente heeft bepaalde machtigingen nodig om uw foto's op te slaan, die hier bekeken kunnen worden: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
+
+PRIJZEN
+We bieden geen oneindig gratis plannen aan, omdat het voor ons belangrijk is dat we duurzaam blijven en de tand des tijds weerstaan. In plaats daarvan bieden we betaalbare plannen aan die je vrij kunt delen met je familie. Je kunt meer informatie vinden op ente.io.
+
+KLANTENSERVICE
+Wij zijn trots op het bieden van menselijke klantenservice. Als je een betaalde klant bent, kun je contact opnemen met team@ente.io en binnen 24 uur een antwoord van ons verwachten.

+ 1 - 0
mobile/android/app/src/main/play/listings/nl/short_description.txt

@@ -0,0 +1 @@
+ente is een end-to-end versteutelde app voor foto opslag

+ 1 - 0
mobile/android/app/src/main/play/listings/nl/title.txt

@@ -0,0 +1 @@
+ente - versleutelde foto opslag

+ 1 - 0
mobile/android/app/src/main/play/listings/pl/short_description.txt

@@ -0,0 +1 @@
+ente to w pełni szyfrowana aplikacja do przechowywania zdjęć

+ 1 - 0
mobile/android/app/src/main/play/listings/pl/title.txt

@@ -0,0 +1 @@
+ente - szyfrowane przechowywanie zdjęć

+ 36 - 0
mobile/android/app/src/main/play/listings/pt/full_description.txt

@@ -0,0 +1,36 @@
+ente é um aplicativo simples para fazer backup e compartilhar suas fotos e vídeos.
+
+Se você está procurando uma alternativa ao Google Fotos com foco em privacidade, você veio ao lugar certo. Com ente, eles são armazenados com criptografia de ponta a ponta (e2ee). Isso significa que só você pode vê-los.
+
+Temos aplicativos de código aberto em todas as plataformas, Android, iOS, web e desktop, e suas fotos irão sincronizar perfeitamente entre todas elas de forma criptografada (e2ee).
+
+ente também torna simples compartilhar seus álbuns com seus entes queridos, mesmo que eles não estejam no ente. Você pode compartilhar links para visualização pública, onde eles podem visualizar seu álbum e colaborar adicionando fotos a ele, mesmo sem uma conta ou app.
+
+Seus dados criptografados são replicados em 3 locais diferentes, incluindo um abrigo avançado em Paris. Levamos a sério a nossa postura e fazemos com que seja fácil garantir que suas memórias vivam.
+
+Estamos aqui para se tornar o app de fotos mais seguro de todos, venha entrar em nossa jornada!
+
+RECURSOS
+- Cópia de qualidade original, porque cada pixel é importante
+- Planos de família, para que você possa compartilhar o armazenamento com sua família
+- Álbuns colaborativos, para que você possa agrupar fotos após uma corrida
+- Pastas compartilhadas, caso você queira que seu parceiro aproveite seus cliques da "Câmera"
+- Links de álbuns, que podem ser protegidos com uma senha e definidos para expirar
+- Capacidade de liberar espaço, removendo arquivos que foram salvos com segurança
+- Suporte humano, porque você vale a pena
+- Descrições, para que você possa captar suas memórias e encontrá-las facilmente
+- Editor de imagens, para adicionar toques finais
+- Favoritar, esconder e reviver suas memórias, pois elas são preciosas
+- Importar com um clique do Google, Apple, seu disco rígido e muito mais
+- Tema escuro, porque suas fotos parecem bem nele
+- 2FA, 3FA, Autenticação biométrica
+- e MUITO MAIS!
+
+PERMISSÕES
+ente solicita certas permissões para servir o propósito de um provedor de armazenamento de fotos, que pode ser revisado 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 que permaneçamos sustentáveis e resistamos à prova do tempo. Em vez disso, oferecemos planos acessíveis que você pode compartilhar livremente com sua família. Você pode encontrar mais informações em ente.io.
+
+SUPORTE
+Temos orgulho em oferecer apoio humano. Se você é nosso cliente pago, você pode entrar em contato com o team@ente.io e esperar uma resposta da nossa equipe dentro de 24 horas.

+ 1 - 0
mobile/android/app/src/main/play/listings/pt/short_description.txt

@@ -0,0 +1 @@
+ente é um aplicativo de armazenamento de fotos criptografado de ponta a ponta

+ 1 - 0
mobile/android/app/src/main/play/listings/pt/title.txt

@@ -0,0 +1 @@
+ente - armazenamento criptografado de fotos

+ 36 - 0
mobile/android/app/src/main/play/listings/ru/full_description.txt

@@ -0,0 +1,36 @@
+ente - это простое приложение для резервного копирования и отправки ваших фотографий и видео.
+
+Если вы ищете подходящую для вас альтернативу Гугл Фото, то вы попали в нужное место. В Ente, они хранятся в сквозном шифровании (e2ee). Это означает то, что только вы можете их просматривать.
+
+У нас есть приложения с открытым исходным кодом на всех платформах, и ваши фотографии будут беспрепятственно синхронизироваться со всеми вашими устройствами с помощью сквозного шифрования (e2ee).
+
+ente также делает так, что делится альбомами со своими близкими становиться невероятно легко, даже если они не зарегистрированы в ente. Вы можете поделиться ссылками публичного доступа, где они могут просматривать ваш альбом и совместно с вами добавлять фотографии в него даже без учетной записи или приложения.
+
+Ваши зашифрованные данные воспроизводятся в 3‑х разных местах, включая скрытое убежище в Париже. Мы серьезно относимся к потомству и легко сделаем так, что ваши воспоминания переживут и вас.
+
+Мы здесь, чтобы сделать самое безопасное приложение для хранения фотографий, присоединяйтесь к нашему путешествию!
+
+ОСОБЕННОСТИ
+- Оригинальное качество резервных копий, потому что важен каждый пиксел
+- Семейные планы, чтобы вы могли делиться хранилищем с вашей семьей
+- Групповые альбомы, что бы вы могли объединить фотографии после поездки
+- Общие папки, если вы хотите, чтобы ваш партнер наслаждался кликами вашей "Камеры"
+- Ссылки для альбома, которые могут быть защищены паролем
+- Возможность освободить место путем удаления файлов, которые были безопасно сохранены
+- Поддержка с живыми людьми, потому что вы заслуживаете лучшего
+- Описания, так что вы можете добавить надпись на свои воспоминания и легко найти их
+- Редактор изображений, для добавления финальных штрихов
+- Избранное, скрывать и доверять вашим воспоминаниям, потому что они драгоценны
+- Импорт в один клик из Google, Apple, вашего жесткого диска и многого другого
+- Темная тема, потому что в ней хорошо выглядят ваши фотографии
+- 2ФА, 3ФА, биометрическая аутентификация
+- и ещё МНОГОЕ другое!
+
+РАЗРЕШЕНИЯ
+ente просит разрешения на использование хранилища фотографий, которые можно рассмотреть здесь: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
+
+ЦЕНА
+Мы не предлагаем бесконечные бесплатные планы, потому что для нас важно оставаться устойчивыми и выдерживать испытание временем. Вместо этого мы предлагаем доступные по цене планы, которыми вы можете свободно делиться с вашей семьей. Дополнительную информацию можно найти на сайте ente.io.
+
+ПОДДЕРЖКА
+Мы гордимся тем, что предлагаем поддержку с живыми людьми. Если вы являетесь нашим платным клиентом, вы можете связаться по электронному адресу team@ente.io и получить ответ от нашей команды в течение 24 часов.

+ 1 - 0
mobile/android/app/src/main/play/listings/ru/short_description.txt

@@ -0,0 +1 @@
+ente - это приложение для хранения фотографий с помощью сквозного шифрования

+ 1 - 0
mobile/android/app/src/main/play/listings/ru/title.txt

@@ -0,0 +1 @@
+ente - хранилище фотографий со сквозным шифрованием

+ 36 - 0
mobile/android/app/src/main/play/listings/zh/full_description.txt

@@ -0,0 +1,36 @@
+ente 是一个简单的应用程序来备份和分享您的照片和视频。
+
+如果你一直在寻找一个隐私友好的Google Photos替代品,那么你就来对地方了。 使用 Ente,它们以端到端加密 (e2ee) 的方式存储。 这意味着只有您可以查看它们。 使用 Ente,它们以端到端加密 (e2ee) 的方式存储。 这意味着只有您可以查看它们。
+
+我们在Android、iOS、web 和桌面上有开源应用, 和您的照片将以端到端加密方式 (e2ee) 无缝同步。
+
+ente也使分享相册给自己的爱人、亲人变得轻而易举,即使他们可能并不使用ente。 您可以分享可公开查看的链接,使他们可以查看您的相册,并通过添加照片来协作而不需要注册账户或下载app。 您可以共享公开可见的链接,他们可以在其中查看您的相册并通过向其中添加照片进行协作,即使没有账户或应用程序也是如此。
+
+您的加密数据已复制到三个不同的地点,包括巴黎的一个安全屋。 我们认真对待子孙后代,并确保您的回忆比您长寿。 我们认真对待子孙后代,并确保您的回忆比您长寿。
+
+我们来这里是为了打造有史以来最安全的照片应用,来和我们一起前行!
+
+特点
+- 原始质量备份,因为每个像素都是重要的
+- 家庭计划,您可以与家人共享存储
+- 协作相册,您可以在旅行后将照片汇集在一起。
+- 共享文件夹,如果您想让您的伙伴享受您的每一次快门
+- 可以用密码保护相册链接
+- 能够通过移除已经安全备份的文件释放空间
+- 实人支持与协助,因为你值得这一切。
+- 添加描述,这样您可以描述您的回忆并在未来轻松地找到它们
+- 图像编辑器,完成收尾工作
+- 收藏、隐藏和恢复您的回忆,因为它们是宝贵的
+- 一键从谷歌、苹果、您的硬盘或更多的介质导入
+- 黑暗主题,因为您的照片在其中看着不错
+- 2FA,3FA,生物识别认证
+- 还有更多特色待你发现!
+
+权限
+ente需要特定权限以执行作为图像存储提供商的职责,相关内容可以在此链接查阅:https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
+
+价格
+我们不会提供永久免费计划,因为我们必须保持可持续性,经受住时间的考验。 相反,我们向您提供了价格实惠、可自由分享的订阅计划。 您可以在 ente.io 找到更多信息。 相反,我们向您提供了价格实惠、可自由分享的订阅计划。 您可以在 ente.io 找到更多信息。 相反,我们向您提供了价格实惠、可自由分享的订阅计划。 您可以在 ente.io 找到更多信息。
+
+支持
+我们对提供真人支持感到自豪。 我们对提供真人支持感到自豪。 如果您是我们的付费客户,您可以联系 team@ente.io 并在24小时内收到来自我们团队的回复。

+ 1 - 0
mobile/android/app/src/main/play/listings/zh/short_description.txt

@@ -0,0 +1 @@
+ente 是一个端到端加密的照片存储应用

+ 1 - 0
mobile/android/app/src/main/play/listings/zh/title.txt

@@ -0,0 +1 @@
+ente - 加密照片存储

+ 130 - 0
mobile/integration_test/app_init_test.dart

@@ -0,0 +1,130 @@
+import "dart:async";
+
+import "package:flutter/material.dart";
+import "package:flutter_test/flutter_test.dart";
+import "package:integration_test/integration_test.dart";
+import "package:logging/logging.dart";
+import "package:photos/main.dart" as app;
+
+void main() {
+  group("App init test", () {
+    final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
+    binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
+    testWidgets("App init test", semanticsEnabled: false, (tester) async {
+      // https://github.com/flutter/flutter/issues/89749#issuecomment-1029965407
+      tester.testTextInput.register();
+
+      await runZonedGuarded(
+        () async {
+          bool skipLogin = false;
+
+          ///Ignore exceptions thrown by the app for the test to pass
+          WidgetsFlutterBinding.ensureInitialized();
+          FlutterError.onError = (FlutterErrorDetails errorDetails) {
+            FlutterError.dumpErrorToConsole(errorDetails);
+          };
+
+          await binding.traceAction(
+            () async {
+              app.main();
+
+              await tester.pumpAndSettle(const Duration(seconds: 1));
+
+              await dismissUpdateAppDialog(tester);
+
+              final signInButton = find.byKey(const ValueKey("signInButton"));
+              skipLogin = !tester.any(signInButton);
+
+              if (!skipLogin) {
+                await tester.tap(signInButton);
+                await tester.pumpAndSettle();
+                final emailInputField = find.byType(TextFormField);
+                final logInButton = find.byKey(const ValueKey("logInButton"));
+                //Fill email id here
+                await tester.enterText(emailInputField, "*enter email here*");
+                await tester.pumpAndSettle(const Duration(seconds: 1));
+                await tester.tap(logInButton);
+                await tester.pumpAndSettle(const Duration(seconds: 3));
+                final passwordInputField =
+                    find.byKey(const ValueKey("passwordInputField"));
+                final verifyPasswordButton =
+                    find.byKey(const ValueKey("verifyPasswordButton"));
+                //Fill password here
+                await tester.enterText(
+                  passwordInputField,
+                  "*enter password here*",
+                );
+                await tester.pumpAndSettle(const Duration(seconds: 1));
+                await tester.tap(verifyPasswordButton);
+                await tester.pumpAndSettle();
+
+                await tester.pumpAndSettle(const Duration(seconds: 1));
+                await dismissUpdateAppDialog(tester);
+
+                //Grant permission to access photos. Must manually click the system dialog.
+                final grantPermissionButton =
+                    find.byKey(const ValueKey("grantPermissionButton"));
+                await tester.tap(grantPermissionButton);
+                await tester.pumpAndSettle(const Duration(seconds: 1));
+                await tester.pumpAndSettle(const Duration(seconds: 3));
+
+                //Automatically skips backup
+                final skipBackupButton =
+                    find.byKey(const ValueKey("skipBackupButton"));
+                await tester.tap(skipBackupButton);
+                await tester.pumpAndSettle(const Duration(seconds: 2));
+              }
+            },
+            reportKey: "app_init_summary",
+          );
+        },
+        (error, stack) {
+          Logger("app_init_test").info(error, stack);
+        },
+      );
+    });
+  });
+}
+
+Future<void> dismissUpdateAppDialog(WidgetTester tester) async {
+  await tester.tapAt(const Offset(0, 0));
+  await tester.pumpAndSettle();
+}
+
+
+///Use this widget as floating action buttom in HomeWidget so that frames
+///are built and rendered continuously so that timeline trace has continuous 
+///data. Change the duraiton in `_startTimer()` to control the duraiton of 
+///test on app init.
+
+// class TempWidget extends StatefulWidget {
+//   const TempWidget({super.key});
+
+//   @override
+//   TempWidgetState createState() => TempWidgetState();
+// }
+
+// class TempWidgetState extends State<TempWidget> {
+//   bool _isLoading = true;
+
+//   @override
+//   void initState() {
+//     super.initState();
+//     _startTimer();
+//   }
+
+//   void _startTimer() {
+//     Future.delayed(const Duration(seconds: 20), () {
+//       setState(() {
+//         _isLoading = false;
+//       });
+//     });
+//   }
+
+//   @override
+//   Widget build(BuildContext context) {
+//     return _isLoading
+//         ? const CircularProgressIndicator()
+//         : const SizedBox.shrink();
+//   }
+// }

+ 7 - 1
mobile/ios/Podfile.lock

@@ -152,6 +152,8 @@ PODS:
   - path_provider_foundation (0.0.1):
     - Flutter
     - FlutterMacOS
+  - permission_handler_apple (9.1.1):
+    - Flutter
   - photo_manager (2.0.0):
     - Flutter
     - FlutterMacOS
@@ -247,6 +249,7 @@ DEPENDENCIES:
   - open_mail_app (from `.symlinks/plugins/open_mail_app/ios`)
   - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
   - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
+  - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
   - photo_manager (from `.symlinks/plugins/photo_manager/ios`)
   - receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
   - screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`)
@@ -353,6 +356,8 @@ EXTERNAL SOURCES:
     :path: ".symlinks/plugins/package_info_plus/ios"
   path_provider_foundation:
     :path: ".symlinks/plugins/path_provider_foundation/darwin"
+  permission_handler_apple:
+    :path: ".symlinks/plugins/permission_handler_apple/ios"
   photo_manager:
     :path: ".symlinks/plugins/photo_manager/ios"
   receive_sharing_intent:
@@ -429,6 +434,7 @@ SPEC CHECKSUMS:
   OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
   package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
   path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
+  permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
   photo_manager: 4f6810b7dfc4feb03b461ac1a70dacf91fba7604
   PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4
   ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
@@ -454,4 +460,4 @@ SPEC CHECKSUMS:
 
 PODFILE CHECKSUM: c1a8f198a245ed1f10e40b617efdb129b021b225
 
-COCOAPODS: 1.14.3
+COCOAPODS: 1.15.2

+ 8 - 1
mobile/lib/core/configuration.dart

@@ -16,6 +16,7 @@ import 'package:photos/db/files_db.dart';
 import 'package:photos/db/memories_db.dart';
 import 'package:photos/db/trash_db.dart';
 import 'package:photos/db/upload_locks_db.dart';
+import "package:photos/events/endpoint_updated_event.dart";
 import 'package:photos/events/signed_in_event.dart';
 import 'package:photos/events/user_logged_out_event.dart';
 import 'package:photos/models/key_attributes.dart';
@@ -69,6 +70,7 @@ class Configuration {
   static const hasSelectedAllFoldersForBackupKey =
       "has_selected_all_folders_for_backup";
   static const anonymousUserIDKey = "anonymous_user_id";
+  static const endPointKey = "endpoint";
 
   final kTempFolderDeletionTimeBuffer = const Duration(hours: 6).inMicroseconds;
 
@@ -390,7 +392,12 @@ class Configuration {
   }
 
   String getHttpEndpoint() {
-    return endpoint;
+    return _preferences.getString(endPointKey) ?? endpoint;
+  }
+
+  Future<void> setHttpEndpoint(String endpoint) async {
+    await _preferences.setString(endPointKey, endpoint);
+    Bus.instance.fire(EndpointUpdatedEvent());
   }
 
   String? getToken() {

+ 2 - 4
mobile/lib/core/network/ente_interceptor.dart

@@ -1,14 +1,12 @@
 import 'package:dio/dio.dart';
 import 'package:flutter/foundation.dart';
 import 'package:photos/core/configuration.dart';
-import 'package:shared_preferences/shared_preferences.dart';
 import 'package:uuid/uuid.dart';
 
 class EnteRequestInterceptor extends Interceptor {
-  final SharedPreferences _preferences;
   final String enteEndpoint;
 
-  EnteRequestInterceptor(this._preferences, this.enteEndpoint);
+  EnteRequestInterceptor(this.enteEndpoint);
 
   @override
   void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
@@ -20,7 +18,7 @@ class EnteRequestInterceptor extends Interceptor {
     }
     // ignore: prefer_const_constructors
     options.headers.putIfAbsent("x-request-id", () => Uuid().v4().toString());
-    final String? tokenValue = _preferences.getString(Configuration.tokenKey);
+    final String? tokenValue = Configuration.instance.getToken();
     if (tokenValue != null) {
       options.headers.putIfAbsent("X-Auth-Token", () => tokenValue);
     }

+ 17 - 11
mobile/lib/core/network/network.dart

@@ -3,26 +3,21 @@ import 'dart:io';
 import 'package:dio/dio.dart';
 import 'package:fk_user_agent/fk_user_agent.dart';
 import 'package:package_info_plus/package_info_plus.dart';
-import 'package:photos/core/constants.dart';
+import "package:photos/core/configuration.dart";
+import "package:photos/core/event_bus.dart";
 import 'package:photos/core/network/ente_interceptor.dart';
-import 'package:shared_preferences/shared_preferences.dart';
+import "package:photos/events/endpoint_updated_event.dart";
 
 int kConnectTimeout = 15000;
 
 class NetworkClient {
-  // apiEndpoint points to the Ente server's API endpoint
-  static const apiEndpoint = String.fromEnvironment(
-    "endpoint",
-    defaultValue: kDefaultProductionEndpoint,
-  );
-
   late Dio _dio;
   late Dio _enteDio;
 
   Future<void> init() async {
     await FkUserAgent.init();
     final packageInfo = await PackageInfo.fromPlatform();
-    final preferences = await SharedPreferences.getInstance();
+    final endpoint = Configuration.instance.getHttpEndpoint();
     _dio = Dio(
       BaseOptions(
         connectTimeout: kConnectTimeout,
@@ -35,7 +30,7 @@ class NetworkClient {
     );
     _enteDio = Dio(
       BaseOptions(
-        baseUrl: apiEndpoint,
+        baseUrl: endpoint,
         connectTimeout: kConnectTimeout,
         headers: {
           HttpHeaders.userAgentHeader: FkUserAgent.userAgent,
@@ -44,7 +39,18 @@ class NetworkClient {
         },
       ),
     );
-    _enteDio.interceptors.add(EnteRequestInterceptor(preferences, apiEndpoint));
+    _setupInterceptors(endpoint);
+
+    Bus.instance.on<EndpointUpdatedEvent>().listen((event) {
+      final endpoint = Configuration.instance.getHttpEndpoint();
+      _enteDio.options.baseUrl = endpoint;
+      _setupInterceptors(endpoint);
+    });
+  }
+
+  void _setupInterceptors(String endpoint) {
+    _enteDio.interceptors.clear();
+    _enteDio.interceptors.add(EnteRequestInterceptor(endpoint));
   }
 
   NetworkClient._privateConstructor();

+ 3 - 0
mobile/lib/events/endpoint_updated_event.dart

@@ -0,0 +1,3 @@
+import "package:photos/events/event.dart";
+
+class EndpointUpdatedEvent extends Event {}

+ 2 - 0
mobile/lib/generated/intl/messages_cs.dart

@@ -35,6 +35,8 @@ class MessageLookup extends MessageLookupByLibrary {
         "changeLocationOfSelectedItems": MessageLookupByLibrary.simpleMessage(
             "Change location of selected items?"),
         "contacts": MessageLookupByLibrary.simpleMessage("Contacts"),
+        "createCollaborativeLink":
+            MessageLookupByLibrary.simpleMessage("Create collaborative link"),
         "deleteConfirmDialogBody": MessageLookupByLibrary.simpleMessage(
             "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted."),
         "descriptions": MessageLookupByLibrary.simpleMessage("Descriptions"),

+ 2 - 0
mobile/lib/generated/intl/messages_de.dart

@@ -503,6 +503,8 @@ class MessageLookup extends MessageLookupByLibrary {
             MessageLookupByLibrary.simpleMessage("Konto erstellen"),
         "createAlbumActionHint": MessageLookupByLibrary.simpleMessage(
             "Drücke lange um Fotos auszuwählen und klicke + um ein Album zu erstellen"),
+        "createCollaborativeLink":
+            MessageLookupByLibrary.simpleMessage("Create collaborative link"),
         "createCollage":
             MessageLookupByLibrary.simpleMessage("Collage erstellen"),
         "createNewAccount":

+ 17 - 0
mobile/lib/generated/intl/messages_en.dart

@@ -62,6 +62,8 @@ class MessageLookup extends MessageLookupByLibrary {
   static String m13(provider) =>
       "Please contact us at support@ente.io to manage your ${provider} subscription.";
 
+  static String m69(endpoint) => "Connected to ${endpoint}";
+
   static String m14(count) =>
       "${Intl.plural(count, one: 'Delete ${count} item', other: 'Delete ${count} items')}";
 
@@ -488,6 +490,8 @@ class MessageLookup extends MessageLookupByLibrary {
         "createAccount": MessageLookupByLibrary.simpleMessage("Create account"),
         "createAlbumActionHint": MessageLookupByLibrary.simpleMessage(
             "Long press to select photos and click + to create an album"),
+        "createCollaborativeLink":
+            MessageLookupByLibrary.simpleMessage("Create collaborative link"),
         "createCollage": MessageLookupByLibrary.simpleMessage("Create collage"),
         "createNewAccount":
             MessageLookupByLibrary.simpleMessage("Create new account"),
@@ -502,6 +506,7 @@ class MessageLookup extends MessageLookupByLibrary {
         "currentUsageIs":
             MessageLookupByLibrary.simpleMessage("Current usage is "),
         "custom": MessageLookupByLibrary.simpleMessage("Custom"),
+        "customEndpoint": m69,
         "darkTheme": MessageLookupByLibrary.simpleMessage("Dark"),
         "dayToday": MessageLookupByLibrary.simpleMessage("Today"),
         "dayYesterday": MessageLookupByLibrary.simpleMessage("Yesterday"),
@@ -562,6 +567,10 @@ class MessageLookup extends MessageLookupByLibrary {
         "details": MessageLookupByLibrary.simpleMessage("Details"),
         "devAccountChanged": MessageLookupByLibrary.simpleMessage(
             "The developer account we use to publish ente on App Store has changed. Because of this, you will need to login again.\n\nOur apologies for the inconvenience, but this was unavoidable."),
+        "developerSettings":
+            MessageLookupByLibrary.simpleMessage("Developer settings"),
+        "developerSettingsWarning": MessageLookupByLibrary.simpleMessage(
+            "Are you sure that you want to modify Developer settings?"),
         "deviceCodeHint":
             MessageLookupByLibrary.simpleMessage("Enter the code"),
         "deviceFilesAutoUploading": MessageLookupByLibrary.simpleMessage(
@@ -627,6 +636,8 @@ class MessageLookup extends MessageLookupByLibrary {
         "encryption": MessageLookupByLibrary.simpleMessage("Encryption"),
         "encryptionKeys":
             MessageLookupByLibrary.simpleMessage("Encryption keys"),
+        "endpointUpdatedMessage": MessageLookupByLibrary.simpleMessage(
+            "Endpoint updated successfully"),
         "endtoendEncryptedByDefault": MessageLookupByLibrary.simpleMessage(
             "End-to-end encrypted by default"),
         "enteCanEncryptAndPreserveFilesOnlyIfYouGrant":
@@ -781,6 +792,10 @@ class MessageLookup extends MessageLookupByLibrary {
             MessageLookupByLibrary.simpleMessage("Install manually"),
         "invalidEmailAddress":
             MessageLookupByLibrary.simpleMessage("Invalid email address"),
+        "invalidEndpoint":
+            MessageLookupByLibrary.simpleMessage("Invalid endpoint"),
+        "invalidEndpointMessage": MessageLookupByLibrary.simpleMessage(
+            "Sorry, the endpoint you entered is invalid. Please enter a valid endpoint and try again."),
         "invalidKey": MessageLookupByLibrary.simpleMessage("Invalid key"),
         "invalidRecoveryKey": MessageLookupByLibrary.simpleMessage(
             "The recovery key you entered is not valid. Please make sure it contains 24 words, and check the spelling of each.\n\nIf you entered an older recovery code, make sure it is 64 characters long, and check each of them."),
@@ -1220,6 +1235,8 @@ class MessageLookup extends MessageLookupByLibrary {
         "sendEmail": MessageLookupByLibrary.simpleMessage("Send email"),
         "sendInvite": MessageLookupByLibrary.simpleMessage("Send invite"),
         "sendLink": MessageLookupByLibrary.simpleMessage("Send link"),
+        "serverEndpoint":
+            MessageLookupByLibrary.simpleMessage("Server endpoint"),
         "sessionExpired":
             MessageLookupByLibrary.simpleMessage("Session expired"),
         "setAPassword": MessageLookupByLibrary.simpleMessage("Set a password"),

+ 2 - 0
mobile/lib/generated/intl/messages_es.dart

@@ -426,6 +426,8 @@ class MessageLookup extends MessageLookupByLibrary {
         "createAccount": MessageLookupByLibrary.simpleMessage("Crear cuenta"),
         "createAlbumActionHint": MessageLookupByLibrary.simpleMessage(
             "Mantenga presionado para seleccionar fotos y haga clic en + para crear un álbum"),
+        "createCollaborativeLink":
+            MessageLookupByLibrary.simpleMessage("Create collaborative link"),
         "createNewAccount":
             MessageLookupByLibrary.simpleMessage("Crear nueva cuenta"),
         "createOrSelectAlbum":

+ 2 - 0
mobile/lib/generated/intl/messages_fr.dart

@@ -494,6 +494,8 @@ class MessageLookup extends MessageLookupByLibrary {
             MessageLookupByLibrary.simpleMessage("Créer un compte"),
         "createAlbumActionHint": MessageLookupByLibrary.simpleMessage(
             "Appuyez longuement pour sélectionner des photos et cliquez sur + pour créer un album"),
+        "createCollaborativeLink":
+            MessageLookupByLibrary.simpleMessage("Create collaborative link"),
         "createCollage":
             MessageLookupByLibrary.simpleMessage("Créez un collage"),
         "createNewAccount":

+ 2 - 0
mobile/lib/generated/intl/messages_it.dart

@@ -478,6 +478,8 @@ class MessageLookup extends MessageLookupByLibrary {
         "createAccount": MessageLookupByLibrary.simpleMessage("Crea account"),
         "createAlbumActionHint": MessageLookupByLibrary.simpleMessage(
             "Premi a lungo per selezionare le foto e fai clic su + per creare un album"),
+        "createCollaborativeLink":
+            MessageLookupByLibrary.simpleMessage("Create collaborative link"),
         "createCollage":
             MessageLookupByLibrary.simpleMessage("Crea un collage"),
         "createNewAccount":

+ 2 - 0
mobile/lib/generated/intl/messages_ko.dart

@@ -35,6 +35,8 @@ class MessageLookup extends MessageLookupByLibrary {
         "changeLocationOfSelectedItems": MessageLookupByLibrary.simpleMessage(
             "Change location of selected items?"),
         "contacts": MessageLookupByLibrary.simpleMessage("Contacts"),
+        "createCollaborativeLink":
+            MessageLookupByLibrary.simpleMessage("Create collaborative link"),
         "deleteConfirmDialogBody": MessageLookupByLibrary.simpleMessage(
             "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted."),
         "descriptions": MessageLookupByLibrary.simpleMessage("Descriptions"),

+ 2 - 0
mobile/lib/generated/intl/messages_nl.dart

@@ -500,6 +500,8 @@ class MessageLookup extends MessageLookupByLibrary {
             MessageLookupByLibrary.simpleMessage("Account aanmaken"),
         "createAlbumActionHint": MessageLookupByLibrary.simpleMessage(
             "Lang indrukken om foto\'s te selecteren en klik + om een album te maken"),
+        "createCollaborativeLink":
+            MessageLookupByLibrary.simpleMessage("Create collaborative link"),
         "createCollage": MessageLookupByLibrary.simpleMessage("Creëer collage"),
         "createNewAccount":
             MessageLookupByLibrary.simpleMessage("Nieuw account aanmaken"),

+ 2 - 0
mobile/lib/generated/intl/messages_no.dart

@@ -44,6 +44,8 @@ class MessageLookup extends MessageLookupByLibrary {
         "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage(
             "Ja, jeg ønsker å slette denne kontoen og all dataen dens permanent."),
         "contacts": MessageLookupByLibrary.simpleMessage("Contacts"),
+        "createCollaborativeLink":
+            MessageLookupByLibrary.simpleMessage("Create collaborative link"),
         "deleteAccount": MessageLookupByLibrary.simpleMessage("Slett konto"),
         "deleteAccountFeedbackPrompt": MessageLookupByLibrary.simpleMessage(
             "Vi er lei oss for at du forlater oss. Gi oss gjerne en tilbakemelding så vi kan forbedre oss."),

+ 2 - 0
mobile/lib/generated/intl/messages_pl.dart

@@ -63,6 +63,8 @@ class MessageLookup extends MessageLookupByLibrary {
         "contacts": MessageLookupByLibrary.simpleMessage("Contacts"),
         "continueLabel": MessageLookupByLibrary.simpleMessage("Kontynuuj"),
         "createAccount": MessageLookupByLibrary.simpleMessage("Stwórz konto"),
+        "createCollaborativeLink":
+            MessageLookupByLibrary.simpleMessage("Create collaborative link"),
         "createNewAccount":
             MessageLookupByLibrary.simpleMessage("Stwórz nowe konto"),
         "decrypting":

部分文件因为文件数量过多而无法显示