diff --git a/.github/workflows/auth-internal-release.yml b/.github/workflows/auth-internal-release.yml
index 0a3d192856..4aec41202f 100644
--- a/.github/workflows/auth-internal-release.yml
+++ b/.github/workflows/auth-internal-release.yml
@@ -40,7 +40,7 @@ jobs:
- name: Build PlayStore AAB
run: |
- flutter build appbundle --release --flavor playstore --dart-define=app.flavor=playstore
+ flutter build appbundle --dart-define=cronetHttpNoPlay=true --release --flavor playstore
env:
SIGNING_KEY_PATH: "/home/runner/work/_temp/keystore/ente_auth_key.jks"
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
@@ -54,3 +54,12 @@ jobs:
packageName: io.ente.auth
releaseFiles: auth/build/app/outputs/bundle/playstoreRelease/app-playstore-release.aab
track: internal
+
+ - name: Notify Discord
+ uses: sarisia/actions-status-discord@v1
+ with:
+ webhook: ${{ secrets.DISCORD_INTERNAL_RELEASE_WEBHOOK }}
+ nodetail: true
+ title: "🏆 Internal release available for Auth"
+ description: "[Download](https://play.google.com/store/apps/details?id=io.ente.auth)"
+ color: 0x800080
diff --git a/.github/workflows/auth-release.yml b/.github/workflows/auth-release.yml
index f1f8eff830..aa2bdc27d1 100644
--- a/.github/workflows/auth-release.yml
+++ b/.github/workflows/auth-release.yml
@@ -68,7 +68,7 @@ jobs:
- name: Build independent APK
run: |
- flutter build apk --release --flavor independent --dart-define=app.flavor=independent
+ flutter build apk --dart-define=cronetHttpNoPlay=true --release --flavor independent
mv build/app/outputs/flutter-apk/app-independent-release.apk artifacts/ente-${{ github.ref_name }}.apk
env:
SIGNING_KEY_PATH: "/home/runner/work/_temp/keystore/ente_auth_key.jks"
diff --git a/.github/workflows/mobile-internal-release.yml b/.github/workflows/mobile-internal-release.yml
index 6752fb1308..cbba50064f 100644
--- a/.github/workflows/mobile-internal-release.yml
+++ b/.github/workflows/mobile-internal-release.yml
@@ -40,7 +40,7 @@ jobs:
- name: Build PlayStore AAB
run: |
- flutter build appbundle --release --flavor playstore
+ flutter build appbundle --dart-define=cronetHttpNoPlay=true --release --flavor playstore
env:
SIGNING_KEY_PATH: "/home/runner/work/_temp/keystore/ente_photos_key.jks"
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS_PHOTOS }}
@@ -54,3 +54,12 @@ jobs:
packageName: io.ente.photos
releaseFiles: mobile/build/app/outputs/bundle/playstoreRelease/app-playstore-release.aab
track: internal
+
+ - name: Notify Discord
+ uses: sarisia/actions-status-discord@v1
+ with:
+ webhook: ${{ secrets.DISCORD_INTERNAL_RELEASE_WEBHOOK }}
+ nodetail: true
+ title: "🏆 Internal release available for Photos"
+ description: "[Download](https://play.google.com/store/apps/details?id=io.ente.photos)"
+ color: 0x00ff00
diff --git a/.github/workflows/mobile-release.yml b/.github/workflows/mobile-release.yml
index ecf2c6d769..8997f0afbc 100644
--- a/.github/workflows/mobile-release.yml
+++ b/.github/workflows/mobile-release.yml
@@ -45,7 +45,7 @@ jobs:
- name: Build independent APK
run: |
- flutter build apk --release --flavor independent
+ flutter build apk --dart-define=cronetHttpNoPlay=true --release --flavor independent
mv build/app/outputs/flutter-apk/app-independent-release.apk build/app/outputs/flutter-apk/ente-${{ github.ref_name }}.apk
env:
SIGNING_KEY_PATH: "/home/runner/work/_temp/keystore/ente_photos_key.jks"
diff --git a/.github/workflows/server-publish.yml b/.github/workflows/server-publish.yml
index a1d259480f..a677fd9eac 100644
--- a/.github/workflows/server-publish.yml
+++ b/.github/workflows/server-publish.yml
@@ -1,27 +1,24 @@
name: "Publish ghcr (server)"
on:
- # Run manually, providing it the commit.
- #
- # To obtain the commit from the currently deployed museum, do:
- # curl -s https://api.ente.io/ping | jq -r '.id'
- #
- # See server/docs/publish.md for more details.
+ # Run automatically on 15th of every month, at 05:00 UTC.
+ schedule:
+ - cron: '0 5 15 * *'
+ # Run manually if needed to publish out of schedule.
workflow_dispatch:
- inputs:
- commit:
- description: "Commit to publish the image from"
- type: string
- required: true
jobs:
publish:
runs-on: ubuntu-latest
steps:
+ - name: Determine commit from prod museum
+ run: |
+ echo "museum_commit=$(curl -s https://api.ente.io/ping | jq -r .id)" >> $GITHUB_ENV
+
- name: Checkout code
uses: actions/checkout@v4
with:
- ref: ${{ inputs.commit }}
+ ref: ${{ env.museum_commit }}
- name: Build and push
uses: mr-smithers-excellent/docker-build-push@v6
@@ -34,8 +31,8 @@ jobs:
enableBuildKit: true
multiPlatform: true
platform: linux/amd64,linux/arm64
- buildArgs: GIT_COMMIT=${{ inputs.commit }}
- tags: ${{ inputs.commit }}, latest
+ buildArgs: GIT_COMMIT=${{ env.museum_commit }}
+ tags: ${{ env.museum_commit }}, latest
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
diff --git a/auth/assets/custom-icons/_data/custom-icons.json b/auth/assets/custom-icons/_data/custom-icons.json
index 702c0dcd9e..73a0ac3142 100644
--- a/auth/assets/custom-icons/_data/custom-icons.json
+++ b/auth/assets/custom-icons/_data/custom-icons.json
@@ -35,9 +35,18 @@
{
"title": "Amazon"
},
+ {
+ "title": "Ankama",
+ "slug": "ankama"
+ },
{
"title": "Anycoin Direct",
"slug": "anycoindirect"
+ },
+ {
+ "title": "Aruba",
+ "slug": "aruba",
+ "hex": "ef8a33"
},
{
"title": "AscendEX"
@@ -199,6 +208,10 @@
{
"title": "Bugzilla"
},
+ {
+ "title": "ButterflyMX",
+ "slug": "butterflymx"
+ },
{
"title": "Bybit"
},
@@ -297,6 +310,9 @@
{
"title": "Discourse"
},
+ {
+ "title": "Deloitte"
+ },
{
"title": "DMarket"
},
@@ -352,6 +368,14 @@
{
"title": "Estateguru"
},
+ {
+ "title": "EVEOnline",
+ "slug": "eve_online",
+ "altNames": [
+ "EVE Online"
+ ],
+ "hex": "858585"
+ },
{
"title": "Fastmail"
},
@@ -376,9 +400,17 @@
{
"title": "ForUsAll"
},
+ {
+ "title": "FreeTaxUSA",
+ "slug": "freetaxusa"
+ },
{
"title": "G2A"
},
+ {
+ "title": "Gate.io",
+ "slug": "gateio.svg"
+ },
{
"title": "GitHub"
},
@@ -717,7 +749,8 @@
{
"title": "nintendo",
"altNames": [
- "任天堂"
+ "任天堂",
+ "Nintendo Account"
]
},
{
@@ -734,6 +767,15 @@
{
"title": "Notesnook"
},
+ {
+ "title": "NoIp",
+ "slug": "noip",
+ "altNames": [
+ "No IP",
+ "No-IP",
+ "noip.com"
+ ]
+ },
{
"title": "Notion"
},
@@ -760,6 +802,11 @@
"altNames": [
"欧易"
]
+ },
+ {
+ "title": "OnShape",
+ "slug": "onshape",
+ "hex": "7abb5e"
},
{
"title": "Parqet",
@@ -814,6 +861,13 @@
"PostScanMail"
]
},
+ {
+ "title": "Prey Project",
+ "slug": "prey_project",
+ "altNames": [
+ "PreyProject"
+ ]
+ },
{
"title": "Privacy Guides",
"slug": "privacyguides"
@@ -857,6 +911,11 @@
{
"title": "RealMe",
"slug": "realme"
+ },
+ {
+ "title": "RealVNC",
+ "slug": "realvnc",
+ "hex": "488aec"
},
{
"title": "Registro br",
@@ -901,6 +960,10 @@
{
"title": "Samsung"
},
+ {
+ "title": "Seafile",
+ "slug": "seafile"
+ },
{
"title": "Sendgrid"
},
@@ -1138,6 +1201,9 @@
{
"title": "Wolvesville"
},
+ {
+ "title": "Workflowy"
+ },
{
"title": "WorkOS",
"altNames": [
@@ -1179,6 +1245,12 @@
},
{
"title": "Zoom"
+ },
+ {
+ "title": "BingX"
+ },
+ {
+ "title": "CoinSpot"
}
]
}
diff --git a/auth/assets/custom-icons/icons/ankama.svg b/auth/assets/custom-icons/icons/ankama.svg
new file mode 100644
index 0000000000..5e21c7c4e8
--- /dev/null
+++ b/auth/assets/custom-icons/icons/ankama.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/auth/assets/custom-icons/icons/aruba.svg b/auth/assets/custom-icons/icons/aruba.svg
new file mode 100644
index 0000000000..c078116929
--- /dev/null
+++ b/auth/assets/custom-icons/icons/aruba.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/auth/assets/custom-icons/icons/bingx.svg b/auth/assets/custom-icons/icons/bingx.svg
new file mode 100644
index 0000000000..9bcb83f42d
--- /dev/null
+++ b/auth/assets/custom-icons/icons/bingx.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/auth/assets/custom-icons/icons/butterflymx.svg b/auth/assets/custom-icons/icons/butterflymx.svg
new file mode 100644
index 0000000000..b73c3b15b9
--- /dev/null
+++ b/auth/assets/custom-icons/icons/butterflymx.svg
@@ -0,0 +1,27 @@
+
+
diff --git a/auth/assets/custom-icons/icons/coinspot.svg b/auth/assets/custom-icons/icons/coinspot.svg
new file mode 100644
index 0000000000..0d94e75a88
--- /dev/null
+++ b/auth/assets/custom-icons/icons/coinspot.svg
@@ -0,0 +1,130 @@
+
+
+
diff --git a/auth/assets/custom-icons/icons/deloitte.svg b/auth/assets/custom-icons/icons/deloitte.svg
new file mode 100644
index 0000000000..990f467189
--- /dev/null
+++ b/auth/assets/custom-icons/icons/deloitte.svg
@@ -0,0 +1,15 @@
+
\ No newline at end of file
diff --git a/auth/assets/custom-icons/icons/eve_online.svg b/auth/assets/custom-icons/icons/eve_online.svg
new file mode 100644
index 0000000000..816807454d
--- /dev/null
+++ b/auth/assets/custom-icons/icons/eve_online.svg
@@ -0,0 +1,3 @@
+
+
diff --git a/auth/assets/custom-icons/icons/freetaxusa.svg b/auth/assets/custom-icons/icons/freetaxusa.svg
new file mode 100644
index 0000000000..a4fc2eb654
--- /dev/null
+++ b/auth/assets/custom-icons/icons/freetaxusa.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/auth/assets/custom-icons/icons/gateio.svg b/auth/assets/custom-icons/icons/gateio.svg
new file mode 100644
index 0000000000..83972c0d84
--- /dev/null
+++ b/auth/assets/custom-icons/icons/gateio.svg
@@ -0,0 +1,15 @@
+
+
diff --git a/auth/assets/custom-icons/icons/noip.svg b/auth/assets/custom-icons/icons/noip.svg
new file mode 100644
index 0000000000..c15b4caa5f
--- /dev/null
+++ b/auth/assets/custom-icons/icons/noip.svg
@@ -0,0 +1,22 @@
+
\ No newline at end of file
diff --git a/auth/assets/custom-icons/icons/prey_project.svg b/auth/assets/custom-icons/icons/prey_project.svg
new file mode 100644
index 0000000000..cc3c19b8c2
--- /dev/null
+++ b/auth/assets/custom-icons/icons/prey_project.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/auth/assets/custom-icons/icons/realvnc.svg b/auth/assets/custom-icons/icons/realvnc.svg
new file mode 100644
index 0000000000..07bcac774a
--- /dev/null
+++ b/auth/assets/custom-icons/icons/realvnc.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/auth/assets/custom-icons/icons/seafile.svg b/auth/assets/custom-icons/icons/seafile.svg
new file mode 100644
index 0000000000..0794ace85e
--- /dev/null
+++ b/auth/assets/custom-icons/icons/seafile.svg
@@ -0,0 +1,13 @@
+
\ No newline at end of file
diff --git a/auth/assets/custom-icons/icons/workflowy.svg b/auth/assets/custom-icons/icons/workflowy.svg
new file mode 100644
index 0000000000..df6419cdba
--- /dev/null
+++ b/auth/assets/custom-icons/icons/workflowy.svg
@@ -0,0 +1,8 @@
+
diff --git a/auth/flutter b/auth/flutter
index 68415ad1d9..2663184aa7 160000
--- a/auth/flutter
+++ b/auth/flutter
@@ -1 +1 @@
-Subproject commit 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3
+Subproject commit 2663184aa79047d0a33a14a3b607954f8fdd8730
diff --git a/auth/lib/core/network.dart b/auth/lib/core/network.dart
index c14c9e758b..0f5ae3555d 100644
--- a/auth/lib/core/network.dart
+++ b/auth/lib/core/network.dart
@@ -8,6 +8,7 @@ import 'package:ente_auth/utils/package_info_util.dart';
import 'package:ente_auth/utils/platform_util.dart';
import 'package:fk_user_agent/fk_user_agent.dart';
import 'package:flutter/foundation.dart';
+import 'package:native_dio_adapter/native_dio_adapter.dart';
import 'package:uuid/uuid.dart';
int kConnectTimeout = 15000;
@@ -50,6 +51,10 @@ class Network {
},
),
);
+
+ _dio.httpClientAdapter = NativeAdapter();
+ _enteDio.httpClientAdapter = NativeAdapter();
+
_setupInterceptors(endpoint);
Bus.instance.on().listen((event) {
diff --git a/auth/lib/events/opened_settings_event.dart b/auth/lib/events/opened_settings_event.dart
deleted file mode 100644
index 3aadeb1222..0000000000
--- a/auth/lib/events/opened_settings_event.dart
+++ /dev/null
@@ -1,3 +0,0 @@
-import 'package:ente_auth/events/event.dart';
-
-class OpenedSettingsEvent extends Event {}
diff --git a/auth/lib/json/converter.dart b/auth/lib/json/converter.dart
deleted file mode 100644
index 9f45f8f8e5..0000000000
--- a/auth/lib/json/converter.dart
+++ /dev/null
@@ -1,17 +0,0 @@
-import 'dart:typed_data';
-
-import "package:json_annotation/json_annotation.dart";
-
-class Uint8ListConverter implements JsonConverter> {
- const Uint8ListConverter();
-
- @override
- Uint8List fromJson(List? json) {
- return json == null ? Uint8List(0) : Uint8List.fromList(json);
- }
-
- @override
- List toJson(Uint8List object) {
- return object.toList();
- }
-}
diff --git a/auth/lib/l10n/arb/app_ar.arb b/auth/lib/l10n/arb/app_ar.arb
index d2a3985d20..9b8e3e7462 100644
--- a/auth/lib/l10n/arb/app_ar.arb
+++ b/auth/lib/l10n/arb/app_ar.arb
@@ -482,7 +482,6 @@
"importFailureDescNew": "تعذر إعراب الملف المنتقى.",
"duplicateCodes": "رموز مكررة",
"noDuplicates": "✨ لا تكرارات",
- "youveNoDuplicateCodesThatCanBeCleared": "ليس لديك رموز مكررة يمكن مسحها",
"deselectAll": "ألغِ تحديد الكل",
"selectAll": "حدد الكل",
"deleteDuplicates": "احذف التكرار"
diff --git a/auth/lib/l10n/arb/app_bg.arb b/auth/lib/l10n/arb/app_bg.arb
index 156adf4bdc..d76ffbcc0d 100644
--- a/auth/lib/l10n/arb/app_bg.arb
+++ b/auth/lib/l10n/arb/app_bg.arb
@@ -499,10 +499,11 @@
"appLockOfflineModeWarning": "Избрахте да продължите без резервни копия. Ако забравите паролата на приложението си, ще бъдете заключени от достъп до вашите данни.",
"duplicateCodes": "Повтарящи се кодове",
"noDuplicates": "✨ Няма дубликати",
- "youveNoDuplicateCodesThatCanBeCleared": "Нямате повтарящи се кодове, които могат да бъдат изчистени",
"deduplicateCodes": "Премахване на повтарящи се кодове",
"deselectAll": "Демаркиране на всички",
"selectAll": "Избиране на всички",
"deleteDuplicates": "Изтриване на дубликатите",
- "plainHTML": "Обикновен HTML"
+ "plainHTML": "Обикновен HTML",
+ "tellUsWhatYouThink": "Кажете ни какво мислите",
+ "freeStorageOfferDescription": "Използвайте промокод „AUTH“, за да получите 10% отстъпка през първата година"
}
\ No newline at end of file
diff --git a/auth/lib/l10n/arb/app_ca.arb b/auth/lib/l10n/arb/app_ca.arb
index adef48b36e..012427ea50 100644
--- a/auth/lib/l10n/arb/app_ca.arb
+++ b/auth/lib/l10n/arb/app_ca.arb
@@ -88,6 +88,8 @@
"useRecoveryKey": "Usa la clau de recuperació",
"incorrectPasswordTitle": "Contrasenya incorrecta",
"welcomeBack": "Benvingut de nou!",
+ "emailAlreadyRegistered": "El correu electrònic ja està registrat.",
+ "emailNotRegistered": "El correu electrònic no està registrat.",
"madeWithLoveAtPrefix": "fet amb ❤️ a ",
"supportDevs": "Subscriu-te a ente per donar-nos suport",
"supportDiscount": "Usa el codi de descompte \"AUTH\" per obtenir un 10% de descompte el primer any",
@@ -497,10 +499,17 @@
"appLockOfflineModeWarning": "Has triat procedir sense còpies de seguretat. Si oblides el bloqueig de l'aplicació, no podràs accedir a les teves dades.",
"duplicateCodes": "Codis duplicats",
"noDuplicates": "✨ Sense duplicats",
- "youveNoDuplicateCodesThatCanBeCleared": "No teniu codis duplicats que es puguin esborrar",
"deduplicateCodes": "Desduplica codis",
"deselectAll": "Desselecciona-ho tot",
"selectAll": "Seleccionar-ho tot",
"deleteDuplicates": "Elimina duplicats",
- "plainHTML": "HTML pla"
+ "plainHTML": "HTML pla",
+ "tellUsWhatYouThink": "Digueu-nos què us sembla",
+ "dropReview": "Deixa una ressenya a l'App/Play Store",
+ "supportEnte": "Donar suport a ente",
+ "giveUsAStarOnGithub": "Dona'ns una estrella a Github",
+ "free5GB": "5 GB gratuïts a ente Photos",
+ "loginWithAuthAccount": "Inicieu sessió amb el vostre compte Auth",
+ "freeStorageOffer": "10% de descompte a ente photos",
+ "freeStorageOfferDescription": "Utilitzeu el codi \"AUTH\" per obtenir un 10% de descompte el primer any"
}
\ No newline at end of file
diff --git a/auth/lib/l10n/arb/app_cs.arb b/auth/lib/l10n/arb/app_cs.arb
index 04e8e411fb..5dfb19cc33 100644
--- a/auth/lib/l10n/arb/app_cs.arb
+++ b/auth/lib/l10n/arb/app_cs.arb
@@ -495,7 +495,6 @@
"appLockOfflineModeWarning": "Zvolili jste si pokračování bez zálohování. Pokud zapomenete heslo do aplikace, přístup k datům bude uzamčen.",
"duplicateCodes": "Duplikovat kódy",
"noDuplicates": "✨ Žádné duplikáty",
- "youveNoDuplicateCodesThatCanBeCleared": "Nemáte žádné duplicitní kódy k odstranění",
"deduplicateCodes": "Deduplikovat kódy",
"deselectAll": "Zrušit výběr všech položek",
"selectAll": "Vybrat vše",
diff --git a/auth/lib/l10n/arb/app_de.arb b/auth/lib/l10n/arb/app_de.arb
index 8bce3046c8..62c84330d4 100644
--- a/auth/lib/l10n/arb/app_de.arb
+++ b/auth/lib/l10n/arb/app_de.arb
@@ -88,6 +88,8 @@
"useRecoveryKey": "Wiederherstellungsschlüssel verwenden",
"incorrectPasswordTitle": "Falsches Passwort",
"welcomeBack": "Willkommen zurück!",
+ "emailAlreadyRegistered": "E-Mail ist bereits registriert.",
+ "emailNotRegistered": "E-Mail-Adresse nicht registriert.",
"madeWithLoveAtPrefix": "gemacht mit ❤️ bei ",
"supportDevs": "Bei ente registrieren, um das Projekt zu unterstützen",
"supportDiscount": "Benutzen Sie den Rabattcode \"AUTH\" für 10 % Rabatt im ersten Jahr",
@@ -145,6 +147,7 @@
"leaveFamily": "Familie verlassen",
"leaveFamilyMessage": "Sind Sie sicher, dass Sie den Familien-Plan verlassen wollen?",
"inFamilyPlanMessage": "Sie haben einen Familien-Plan!",
+ "hintForDesktop": "Klicken Sie mit der rechten Maustaste auf einen Code zum Bearbeiten oder Entfernen.",
"scan": "Scannen",
"scanACode": "Scan einen Code",
"verify": "Überprüfen Sie",
@@ -154,6 +157,7 @@
"twoFactorAuthTitle": "Zwei-Faktor-Authentifizierung",
"passkeyAuthTitle": "Passkey Authentifizierung",
"verifyPasskey": "Passkey verifizieren",
+ "loginWithTOTP": "Mit TOTP anmelden",
"recoverAccount": "Konto wiederherstellen",
"enterRecoveryKeyHint": "Geben Sie Ihren Wiederherstellungsschlüssel ein",
"recover": "Wiederherstellen",
@@ -255,6 +259,10 @@
"areYouSureYouWantToLogout": "Sind sie sicher, dass sie sich ausloggen möchten?",
"yesLogout": "Ja ausloggen",
"exit": "Schließen",
+ "theme": "Theme",
+ "lightTheme": "Hell",
+ "darkTheme": "Dunkel",
+ "systemTheme": "System",
"verifyingRecoveryKey": "Verifiziere Wiederherstellungsschlüssel...",
"recoveryKeyVerified": "Wiederherstellungsschlüssel verifiziert",
"recoveryKeySuccessBody": "Großartig! Ihr Wiederherstellungsschlüssel ist gültig. Vielen Dank für die Verifizierung.\n\nBitte denken sie daran, dass sie ihren Wiederherstellungsschlüssel sicher aufbewahren.",
@@ -325,6 +333,10 @@
}
}
},
+ "manualSort": "Benutzerdefiniert",
+ "editOrder": "Reihenfolge bearbeiten",
+ "mostFrequentlyUsed": "Häufig verwendet",
+ "mostRecentlyUsed": "Zuletzt verwendet",
"activeSessions": "Aktive Sitzungen",
"somethingWentWrongPleaseTryAgain": "Ein Fehler ist aufgetreten, bitte versuche es erneut",
"thisWillLogYouOutOfThisDevice": "Dadurch wirst du von diesem Gerät abgemeldet!",
@@ -444,6 +456,7 @@
"customEndpoint": "Mit {endpoint} verbunden",
"pinText": "Anpinnen",
"unpinText": "Lösen",
+ "pinned": "Angeheftet",
"tags": "Tags",
"createNewTag": "Neuen Tag erstellen",
"tag": "Tag",
@@ -478,5 +491,16 @@
"setNewPin": "Neue PIN festlegen",
"importFailureDescNew": "Die ausgewählte Datei konnte nicht verarbeitet werden.",
"appLockNotEnabled": "App-Sperre nicht aktiviert",
- "appLockNotEnabledDescription": "Bitte aktivieren Sie die App-Sperre über Security > App-Sperre"
+ "appLockNotEnabledDescription": "Bitte aktivieren Sie die App-Sperre über Security > App-Sperre",
+ "authToViewPasskey": "Bitte authentifizieren, um deinen Passkey zu sehen",
+ "duplicateCodes": "Doppelte Codes",
+ "noDuplicates": "✨ Keine Duplikate",
+ "deselectAll": "Alle abwählen",
+ "selectAll": "Alles auswählen",
+ "deleteDuplicates": "Duplikate löschen",
+ "plainHTML": "Reines HTML",
+ "tellUsWhatYouThink": "Sagen Sie uns, was Sie denken",
+ "dropReview": "Eine Bewertung im App/Play Store ablegen",
+ "giveUsAStarOnGithub": "Gib uns einen Stern auf Github",
+ "loginWithAuthAccount": "Mit Ihrem Auth Account anmelden"
}
\ No newline at end of file
diff --git a/auth/lib/l10n/arb/app_en.arb b/auth/lib/l10n/arb/app_en.arb
index a51ec12366..9f450d8de3 100644
--- a/auth/lib/l10n/arb/app_en.arb
+++ b/auth/lib/l10n/arb/app_en.arb
@@ -499,7 +499,7 @@
"appLockOfflineModeWarning": "You have chosen to proceed without backups. If you forget your applock, you will be locked out from accessing your data.",
"duplicateCodes": "Duplicate codes",
"noDuplicates": "✨ No duplicates",
- "youveNoDuplicateCodesThatCanBeCleared": "You've no duplicate codes that can be cleared",
+ "youveNoDuplicateCodesThatCanBeCleared": "You don't have any duplicate codes that can be cleared",
"deduplicateCodes": "Deduplicate codes",
"deselectAll": "Deselect all",
"selectAll": "Select all",
diff --git a/auth/lib/l10n/arb/app_es.arb b/auth/lib/l10n/arb/app_es.arb
index 9ae3c65aae..c224d6677c 100644
--- a/auth/lib/l10n/arb/app_es.arb
+++ b/auth/lib/l10n/arb/app_es.arb
@@ -499,10 +499,16 @@
"appLockOfflineModeWarning": "Has elegido proceder sin copia de seguridad. Si olvidas el código de desbloqueo de la aplicación, se bloqueará el acceso a sus datos.",
"duplicateCodes": "Duplicar códigos",
"noDuplicates": "✨ No hay duplicados",
- "youveNoDuplicateCodesThatCanBeCleared": "No tienes códigos duplicados que se puedan borrar",
"deduplicateCodes": "Desduplicar códigos",
"deselectAll": "Deseleccionar todo",
"selectAll": "Seleccionar todo",
"deleteDuplicates": "Eliminar duplicados",
- "plainHTML": "HTML plano"
+ "plainHTML": "HTML plano",
+ "tellUsWhatYouThink": "Cuéntanos cuál es su opinión",
+ "dropReview": "Danos una reseña en la App/Play Store",
+ "supportEnte": "Apoya a ente",
+ "giveUsAStarOnGithub": "Danos una estrella en GitHub",
+ "free5GB": "5 GB gratis en ente Fotos",
+ "freeStorageOffer": "10% de descuento en ente fotos",
+ "freeStorageOfferDescription": "Usa el cupón \"AUTH\" para obtener un 10% de descuento en el primer año"
}
\ No newline at end of file
diff --git a/auth/lib/l10n/arb/app_fr.arb b/auth/lib/l10n/arb/app_fr.arb
index 49a4dd04a3..14dd5571d6 100644
--- a/auth/lib/l10n/arb/app_fr.arb
+++ b/auth/lib/l10n/arb/app_fr.arb
@@ -499,7 +499,6 @@
"appLockOfflineModeWarning": "Vous avez choisi de fonctionner sans sauvegardes. Si vous oubliez votre outil Applock, vous serez bloqué dans l'accès à vos données.",
"duplicateCodes": "Codes dupliqués",
"noDuplicates": "✨ Pas de doublons",
- "youveNoDuplicateCodesThatCanBeCleared": "Vous n'avez aucun code en doublon pouvant être supprimé",
"deduplicateCodes": "Codes dédupliqués",
"deselectAll": "Tout désélectionner",
"selectAll": "Tout sélectionner",
diff --git a/auth/lib/l10n/arb/app_hi.arb b/auth/lib/l10n/arb/app_hi.arb
index 6f311b95d5..728ef319cd 100644
--- a/auth/lib/l10n/arb/app_hi.arb
+++ b/auth/lib/l10n/arb/app_hi.arb
@@ -6,12 +6,15 @@
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
},
+ "onBoardingBody": "अपने 2FA कोड का सुरक्षित रूप से बैकअप लें",
"onBoardingGetStarted": "प्रारंभ करें",
"setupFirstAccount": "अपना पहला अकाउंट सेटअप करें",
"importScanQrCode": "एक QR कोड स्कैन करें",
"qrCode": "QR कोड",
"importEnterSetupKey": "",
"importAccountPageTitle": "अकाउंट विवरण डालें",
+ "secretCanNotBeEmpty": "सीक्रेट खाली नहीं हो सकता है",
+ "bothIssuerAndAccountCanNotBeEmpty": "दोनों इश्यूअर और अकाउंट ख़ाली नहीं हो सकते है",
"incorrectDetails": "ग़लत विवरण",
"pleaseVerifyDetails": "कृपया विवरण सत्यापित करें और पुनः प्रयास करें",
"codeIssuerHint": "ज़ारीकर्ता",
@@ -32,18 +35,24 @@
},
"codeAccountHint": "अकाउंट (you@domain.com)",
"codeTagHint": "टैग",
+ "accountKeyType": "की का प्रकार",
"sessionExpired": "सत्र की अवधि समाप्त",
"@sessionExpired": {
"description": "Title of the dialog when the users current session is invalid/expired"
},
"pleaseLoginAgain": "कृपया फिर से लॉगिन करें",
"loggingOut": "लॉग आउट हो रहा है...",
+ "timeBasedKeyType": "समय आधारित (TOTP)",
+ "counterBasedKeyType": "काउंटर आधारित (HOTP)",
"saveAction": "सेव करें",
+ "nextTotpTitle": "अगला",
+ "deleteCodeTitle": "कोड डिलीट करें?",
"deleteCodeMessage": "क्या आप वाकई इस कोड को हटाना चाहते हैं? इस क्रिया को वापस नहीं किया जा सकता",
"trashCode": "?",
"trashCodeMessage": "क्या आप वाकई {account} के लिए कोड नष्ट करना चाहते हैं?",
"trash": "नष्ट करें",
"viewLogsAction": "लॉग देखें",
+ "sendLogsDescription": "यह आपकी समस्या को सुलझाने में हमारी सहायता के लिए लॉग भेजेगा। हालाँकि हम यह सुनिश्चित करने के लिए सावधानी बरतते हैं कि संवेदनशील जानकारी लॉग न हो, हम आपको इन लॉग को साझा करने से पहले देखने के लिए प्रोत्साहित करते हैं।",
"preparingLogsTitle": "लॉग तैयार किये जा रहे हैं...",
"emailLogsTitle": "लॉग ईमेल करें",
"emailLogsMessage": "कृपया {email} पर लॉग ईमेल करें",
@@ -57,6 +66,7 @@
"copyEmailAction": "ईमेल कॉपी करें",
"exportLogsAction": "लॉग एक्सपोर्ट करें",
"reportABug": "बग रिपोर्ट करें",
+ "crashAndErrorReporting": "क्रैश एवं त्रुटि रिपोर्टिंग",
"reportBug": "बग रिपोर्ट करें",
"emailUsMessage": "कृपया हमें {email} पर ईमेल करें",
"@emailUsMessage": {
@@ -69,14 +79,37 @@
"contactSupport": "सपोर्ट टीम से संपर्क करें",
"rateUsOnStore": "हमें {storeName} पर रेट करें",
"blog": "ब्लॉग",
+ "merchandise": "मर्चेंडाइज़",
"verifyPassword": "पासवर्ड सत्यापित करें",
"pleaseWait": "कृपया प्रतीक्षा करें...",
+ "generatingEncryptionKeysTitle": "एन्क्रिप्शन कुंजियाँ उत्पन्न हो रही हैं...",
+ "recreatePassword": "पासवर्ड दोबारा बनाएं",
+ "recreatePasswordMessage": "वर्तमान डिवाइस आपके पासवर्ड को सत्यापित करने के लिए पर्याप्त शक्तिशाली नहीं है, इसलिए हमें इसे सभी डिवाइसों के साथ काम करने वाले तरीके से एक बार पुन: उत्पन्न करने की आवश्यकता है। \n\nकृपया अपनी पुनर्प्राप्ति कुंजी का उपयोग करके लॉगिन करें और अपना पासवर्ड पुनः बनाएं (यदि आप चाहें तो उसी का दोबारा उपयोग कर सकते हैं)।",
+ "useRecoveryKey": "रिकवरी कुंजी का उपयोग करें",
"incorrectPasswordTitle": "ग़लत पासवर्ड",
"welcomeBack": "आपका पुनः स्वागत है!",
+ "emailAlreadyRegistered": "ईमेल पहले से ही पंजीकृत है।",
+ "emailNotRegistered": "ईमेल पंजीकृत नहीं है।",
+ "madeWithLoveAtPrefix": " ❤️ से बनाया गया ",
+ "supportDevs": "हमें समर्थन देने के लिए ente की सदस्यता लें",
+ "supportDiscount": "पहले साल 10% छूट पाने के लिए कूपन कोड \"AUTH\" का उपयोग करें",
"changeEmail": "ईमेल बदलें",
"changePassword": "पासवर्ड बदलें",
"data": "डेटा",
+ "importCodes": "कोड आयात करें",
+ "importTypePlainText": "साधारण टेक्स्ट",
+ "importTypeEnteEncrypted": "Ente द्वारा एनक्रिप्टेड टेक्स्ट",
+ "passwordForDecryptingExport": "डीक्रिप्ट करने के लिए पासवर्ड",
"passwordEmptyError": "पासवर्ड रिक्त नहीं हो सकता है",
+ "importFromApp": "{appName} से कोड इंपोर्ट करें",
+ "importGoogleAuthGuide": "ट्रांसफर अकाउंट्स\" विकल्प का उपयोग करके अपने खातों को Google प्रमाणक से एक क्यूआर कोड में निर्यात करें। फिर किसी अन्य डिवाइस का उपयोग करके QR कोड को स्कैन करें।\n\nटिप: क्यूआर कोड की तस्वीर लेने के लिए आप अपने लैपटॉप के वेबकैम का उपयोग कर सकते हैं।",
+ "importSelectJsonFile": "JSON फाइल चुनें",
+ "importSelectAppExport": "{appName} की निर्यात फ़ाइल का चयन करें",
+ "importEnteEncGuide": "Ente से निर्यात की गई एन्क्रिप्टेड JSON फ़ाइल का चयन करें",
+ "importRaivoGuide": "Raivo की सेटिंग्स में \"एक्सपोर्ट ओटीपी टू जिप आर्काइव\" विकल्प का उपयोग करें।\n\nज़िप फ़ाइल निकालें और JSON फ़ाइल आयात करें।",
+ "importBitwardenGuide": "बिटवर्डन टूल्स के भीतर \"एक्सपोर्ट वॉल्ट\" विकल्प का उपयोग करें और अनएन्क्रिप्टेड JSON फ़ाइल आयात करें।",
+ "importAegisGuide": "Aegis की सेटिंग्स में \"एक्सपोर्ट द वॉल्ट\" विकल्प का उपयोग करें।\n\nयदि आपकी वॉल्ट एन्क्रिप्टेड है, तो आपको वॉल्ट को डिक्रिप्ट करने के लिए वॉल्ट पासवर्ड दर्ज करना होगा।",
+ "import2FasGuide": "2FAS में \"सेटिंग्स->बैकअप-एक्सपोर्ट\" विकल्प का उपयोग करें।\n\nयदि आपका बैकअप एन्क्रिप्टेड है, तो आपको बैकअप को डिक्रिप्ट करने के लिए पासवर्ड दर्ज करना होगा",
"importLabel": "इंपोर्ट",
"selectFile": "फ़ाइल का चयन करें",
"emailVerificationToggle": "ईमेल सत्यापन",
diff --git a/auth/lib/l10n/arb/app_hu.arb b/auth/lib/l10n/arb/app_hu.arb
index 10fcee33ec..b68a3d8d7a 100644
--- a/auth/lib/l10n/arb/app_hu.arb
+++ b/auth/lib/l10n/arb/app_hu.arb
@@ -499,10 +499,17 @@
"appLockOfflineModeWarning": "Úgy döntött, hogy biztonsági mentés nélkül folytatja. Ha elfelejti az alkalmazászárat, akkor nem férhet hozzá adataihoz.",
"duplicateCodes": "Ismétlődő kódok",
"noDuplicates": "✨Nincs ismétlődés",
- "youveNoDuplicateCodesThatCanBeCleared": "Nincsenek ismétlődő kódjai, amelyeket törölni lehetne",
"deduplicateCodes": "Ismétlődő kódok",
"deselectAll": "Összes kijelölés megszüntetése",
"selectAll": "Összes kijelölése",
"deleteDuplicates": "Ismétlődések törlése",
- "plainHTML": "Sima HTML kód"
+ "plainHTML": "Sima HTML kód",
+ "tellUsWhatYouThink": "Mondja el mit gondol",
+ "dropReview": "Írjon véleményt az App/Play Store-ban",
+ "supportEnte": "Támogassa ente ",
+ "giveUsAStarOnGithub": "Adj nekünk egy csillagot a Githubon",
+ "free5GB": "5GB ingyen ente Photos",
+ "loginWithAuthAccount": "Jelentkezzen be Auth fiókjával",
+ "freeStorageOffer": "10% kedvezmény on ente photos",
+ "freeStorageOfferDescription": "Használja az \"AUTH\" kódot, hogy 10% kedvezményt kapjon az első évben"
}
\ No newline at end of file
diff --git a/auth/lib/l10n/arb/app_id.arb b/auth/lib/l10n/arb/app_id.arb
index 628c1d650f..c791a866a9 100644
--- a/auth/lib/l10n/arb/app_id.arb
+++ b/auth/lib/l10n/arb/app_id.arb
@@ -497,7 +497,6 @@
"appLockOfflineModeWarning": "Anda telah memilih untuk mengunci aplikasi tanpa cadangan apa pun. Jika Anda lupa kode Pengunci Apl Anda, Anda tidak akan dapat mengakses data-data Anda.",
"duplicateCodes": "Kode duplikat",
"noDuplicates": "✨ Tak ada duplikat",
- "youveNoDuplicateCodesThatCanBeCleared": "Kamu tidak memiliki kode duplikat yang dapat dihapus",
"deduplicateCodes": "Hapus kode duplikat",
"deselectAll": "Batalkan semua pilihan",
"selectAll": "Pilih semua",
diff --git a/auth/lib/l10n/arb/app_it.arb b/auth/lib/l10n/arb/app_it.arb
index 17281db08a..c68a87301b 100644
--- a/auth/lib/l10n/arb/app_it.arb
+++ b/auth/lib/l10n/arb/app_it.arb
@@ -499,7 +499,6 @@
"appLockOfflineModeWarning": "Hai scelto di procedere senza backup. Se dimentichi il tuo codice di blocco dell'app, non potrai più accedere ai tuoi dati.",
"duplicateCodes": "Codici duplicati",
"noDuplicates": "✨ Nessun doppione",
- "youveNoDuplicateCodesThatCanBeCleared": "Non ci sono codici duplicati che possono essere cancellati",
"deduplicateCodes": "Codici deduplicati",
"deselectAll": "Deselezionare tutti",
"selectAll": "Seleziona tutti",
diff --git a/auth/lib/l10n/arb/app_ja.arb b/auth/lib/l10n/arb/app_ja.arb
index 3ad6e048ef..49cd9a1e84 100644
--- a/auth/lib/l10n/arb/app_ja.arb
+++ b/auth/lib/l10n/arb/app_ja.arb
@@ -499,7 +499,17 @@
"appLockOfflineModeWarning": "バックアップなしで進むことを選択しました。アプリロックを忘れると、データにアクセスできなくなります。",
"duplicateCodes": "重複コード",
"noDuplicates": "✨ 重複なし",
+ "deduplicateCodes": "重複コード",
+ "deselectAll": "すべての選択を解除",
+ "selectAll": "すべて選択",
+ "deleteDuplicates": "重複を削除",
"plainHTML": "Plain HTML",
"tellUsWhatYouThink": "ご意見をお聞かせください",
- "loginWithAuthAccount": "認証アカウントでログイン"
+ "dropReview": "App/Playストアにレビューを投稿する",
+ "supportEnte": "enteをサポートする",
+ "giveUsAStarOnGithub": "Githubで星をつける",
+ "free5GB": "enteフォトで5GB無料",
+ "loginWithAuthAccount": "認証アカウントでログイン",
+ "freeStorageOffer": "enteの写真が10%オフ",
+ "freeStorageOfferDescription": "クーポンコード \"AUTH\" の使用で初年度が10%オフになります"
}
\ No newline at end of file
diff --git a/auth/lib/l10n/arb/app_ko.arb b/auth/lib/l10n/arb/app_ko.arb
index 0af9fa10f0..a250219cee 100644
--- a/auth/lib/l10n/arb/app_ko.arb
+++ b/auth/lib/l10n/arb/app_ko.arb
@@ -499,7 +499,6 @@
"appLockOfflineModeWarning": "백업 없이 진행하는 것을 선택하셨습니다. App 잠금 방법을 잊어버리신 경우, 데이터에 접근하실 수 없게 됩니다.",
"duplicateCodes": "중복된 코드",
"noDuplicates": "✨ 중복 없음",
- "youveNoDuplicateCodesThatCanBeCleared": "지울 수 있는 중복 코드가 없습니다",
"deduplicateCodes": "중복된 코드 제거",
"deselectAll": "모두 선택 해제",
"selectAll": "모두 선택",
diff --git a/auth/lib/l10n/arb/app_lt.arb b/auth/lib/l10n/arb/app_lt.arb
index aa00c7b1ab..71b96d3027 100644
--- a/auth/lib/l10n/arb/app_lt.arb
+++ b/auth/lib/l10n/arb/app_lt.arb
@@ -499,11 +499,15 @@
"appLockOfflineModeWarning": "Pasirinkote tęsti be atsarginių kopijų. Jei pamiršite programos užraktą, jums bus užrakinta prieiga prie duomenų.",
"duplicateCodes": "Dubliuoti kodus",
"noDuplicates": "✨ Dublikatų nėra",
- "youveNoDuplicateCodesThatCanBeCleared": "Neturite dubliuotų kodų, kuriuos būtų galima išvalyti.",
"deduplicateCodes": "Atdubliuoti kodus",
"deselectAll": "Naikinti visų pasirinkimą",
"selectAll": "Pasirinkti viską",
"deleteDuplicates": "Ištrinti dublikatus",
"plainHTML": "Grynasis HTML",
+ "tellUsWhatYouThink": "Pasakykite mums, ką manote",
+ "giveUsAStarOnGithub": "Suteikite mums žvaigždutę platformoje „Github“",
+ "free5GB": "5 GB nemokami programai „ente“ nuotraukos",
+ "loginWithAuthAccount": "Prisijungti su jūsų „Auth“ paskyra",
+ "freeStorageOffer": "10 % nuolaida programai „ente“ nuotraukos",
"freeStorageOfferDescription": "Naudokite kodą „AUTH“, kad gautumėte 10 % nuolaida pirmiesiems metams. "
}
\ No newline at end of file
diff --git a/auth/lib/l10n/arb/app_ml.arb b/auth/lib/l10n/arb/app_ml.arb
index 9e26dfeeb6..ed441ead94 100644
--- a/auth/lib/l10n/arb/app_ml.arb
+++ b/auth/lib/l10n/arb/app_ml.arb
@@ -1 +1,28 @@
-{}
\ No newline at end of file
+{
+ "blog": "ബ്ലോഗ്",
+ "verifyPassword": "പാസ്വേഡ് സ്ഥിരീകരിക്കുക",
+ "recreatePassword": "പാസ്വേഡ് പുനഃസൃഷ്ടിക്കുക",
+ "incorrectPasswordTitle": "തെറ്റായ പാസ്വേഡ്",
+ "welcomeBack": "വീണ്ടും സ്വാഗതം!",
+ "emailAlreadyRegistered": "ഇമെയിൽ ഇതിനകം രജിസ്റ്റർ ചെയ്തിട്ടുണ്ട്.",
+ "emailNotRegistered": "ഇമെയിൽ രജിസ്റ്റർ ചെയ്തിട്ടില്ല.",
+ "changeEmail": "ഇമെയിൽ മാറ്റുക",
+ "changePassword": "പാസ്സ്വേർഡ് മാറ്റുക",
+ "ok": "ശരി",
+ "cancel": "റദ്ദാക്കുക",
+ "yes": "അതെ",
+ "no": "അല്ല",
+ "email": "ഇമെയിൽ",
+ "somethingWentWrongMessage": "എന്തോ കുഴപ്പമുണ്ടായി, ദയവായി വീണ്ടും ശ്രമിക്കുക",
+ "inFamilyPlanMessage": "നിങ്ങൾ ഒരു ഫാമിലി പ്ലാനിലാണ്!",
+ "scan": "സ്കാൻ ചെയ്യുക",
+ "scanACode": "കോഡ് സ്കാൻ ചെയ്യുക",
+ "verify": "പരിശോധിക്കുക",
+ "verifyEmail": "ഇമെയിൽ സ്ഥിരീകരിക്കുക",
+ "enterCodeHint": "നിങ്ങളുടെ ഓതന്റിക്കേറ്റർ ആപ്പിൽ നിന്നുള്ള 6 അക്ക കോഡ് നൽകുക",
+ "twoFactorAuthTitle": "ടു-ഫാക്ടർ ആധികാരികത",
+ "createNewAccount": "പുതിയ അക്കൗണ്ട് സൃഷ്ടിക്കുക",
+ "confirmPassword": "പാസ്വേഡ് സ്ഥിരീകരിക്കുക",
+ "language": "ഭാഷ",
+ "security": "സുരക്ഷ"
+}
\ No newline at end of file
diff --git a/auth/lib/l10n/arb/app_nl.arb b/auth/lib/l10n/arb/app_nl.arb
index 020646852f..c3d8fa7dd8 100644
--- a/auth/lib/l10n/arb/app_nl.arb
+++ b/auth/lib/l10n/arb/app_nl.arb
@@ -499,7 +499,6 @@
"appLockOfflineModeWarning": "Je hebt ervoor gekozen om verder te gaan zonder backups. Als je jouw applock vergeet, wordt je uitgesloten van toegang tot je gegevens.",
"duplicateCodes": "Dubbele codes",
"noDuplicates": "✨ Geen dubbele",
- "youveNoDuplicateCodesThatCanBeCleared": "Je hebt geen dubbele codes die kunnen worden gewist",
"deduplicateCodes": "Dubbele codes",
"deselectAll": "Alles deselecteren",
"selectAll": "Alles selecteren",
diff --git a/auth/lib/l10n/arb/app_pl.arb b/auth/lib/l10n/arb/app_pl.arb
index 95eddd5fd5..e2c6b26f6a 100644
--- a/auth/lib/l10n/arb/app_pl.arb
+++ b/auth/lib/l10n/arb/app_pl.arb
@@ -499,7 +499,7 @@
"appLockOfflineModeWarning": "Wybrano kontynuowanie bez kopii zapasowych. Jeśli zapomnisz blokady aplikacji, utracisz dostęp do swoich danych.",
"duplicateCodes": "Zduplikowane kody",
"noDuplicates": "✨ Brak duplikatów",
- "youveNoDuplicateCodesThatCanBeCleared": "Nie masz duplikatów kodów, które mogą być wyczyszczone",
+ "youveNoDuplicateCodesThatCanBeCleared": "Nie masz żadnych duplikatów kodów do usunięcia",
"deduplicateCodes": "Deduplikuj kody",
"deselectAll": "Odznacz wszystko",
"selectAll": "Zaznacz wszystko",
diff --git a/auth/lib/l10n/arb/app_pt.arb b/auth/lib/l10n/arb/app_pt.arb
index 5b65e71b1e..cc7d6f4975 100644
--- a/auth/lib/l10n/arb/app_pt.arb
+++ b/auth/lib/l10n/arb/app_pt.arb
@@ -499,7 +499,7 @@
"appLockOfflineModeWarning": "Você prosseguiu sem cópias de segurança. Caso, se esqueça de seu aplicativo de bloqueio, você não poderá mais acessar seus dados.",
"duplicateCodes": "Duplicar códigos",
"noDuplicates": "✨ Sem duplicados",
- "youveNoDuplicateCodesThatCanBeCleared": "Você não possui códigos duplicados para limpar",
+ "youveNoDuplicateCodesThatCanBeCleared": "Você não possui códigos duplicados que possam ser excluídos",
"deduplicateCodes": "Desduplicar códigos",
"deselectAll": "Deselecionar tudo",
"selectAll": "Selecionar tudo",
diff --git a/auth/lib/l10n/arb/app_sv.arb b/auth/lib/l10n/arb/app_sv.arb
index a096aa931e..facf5c1c1e 100644
--- a/auth/lib/l10n/arb/app_sv.arb
+++ b/auth/lib/l10n/arb/app_sv.arb
@@ -451,7 +451,6 @@
"appLockOfflineModeWarning": "Du har valt att fortsätta utan säkerhetskopior. Om du glömmer ditt applås, kommer du att bli utelåst från att komma åt dina data.",
"duplicateCodes": "Dubblettkoder",
"noDuplicates": "✨ Inga dubbletter",
- "youveNoDuplicateCodesThatCanBeCleared": "Du har inga dubblettkoder som kan rensas bort",
"deduplicateCodes": "Deduplicera koder",
"deselectAll": "Avmarkera alla",
"selectAll": "Markera alla",
diff --git a/auth/lib/l10n/arb/app_tr.arb b/auth/lib/l10n/arb/app_tr.arb
index 965689a53d..aee7870c06 100644
--- a/auth/lib/l10n/arb/app_tr.arb
+++ b/auth/lib/l10n/arb/app_tr.arb
@@ -499,7 +499,6 @@
"appLockOfflineModeWarning": "Yedekleme olmadan devam etmeyi seçtiniz. Eğer uygulama parolanızı unutursanız, verilerinize erişiminiz engellenir.",
"duplicateCodes": "Yinelenen kodlar",
"noDuplicates": "✨ Yinelenen yok",
- "youveNoDuplicateCodesThatCanBeCleared": "Temizlenebilecek yinelenen kodunuz yok",
"deduplicateCodes": "Kodları tekilleştir",
"deselectAll": "Tümünün seçimini kaldır",
"selectAll": "Tümünü seç",
diff --git a/auth/lib/l10n/arb/app_uk.arb b/auth/lib/l10n/arb/app_uk.arb
index a758171d89..09c485b7c2 100644
--- a/auth/lib/l10n/arb/app_uk.arb
+++ b/auth/lib/l10n/arb/app_uk.arb
@@ -497,7 +497,6 @@
"appLockOfflineModeWarning": "Ви обрали продовжити без резервних копій. Якщо ви забудете свій пароль, доступ до ваших даних буде заблоковано.",
"duplicateCodes": "Дублікати кодів",
"noDuplicates": "✨ Немає дублікатів",
- "youveNoDuplicateCodesThatCanBeCleared": "У вас немає дублікатів кодів, які можна очистити",
"deduplicateCodes": "Дедуплікувати коди",
"deselectAll": "Зняти виділення",
"selectAll": "Вибрати все",
diff --git a/auth/lib/l10n/arb/app_vi.arb b/auth/lib/l10n/arb/app_vi.arb
index e186b4bbfd..1c7dbecb1e 100644
--- a/auth/lib/l10n/arb/app_vi.arb
+++ b/auth/lib/l10n/arb/app_vi.arb
@@ -499,7 +499,6 @@
"appLockOfflineModeWarning": "Bạn đã chọn tiếp tục mà không có bản sao lưu. Nếu bạn quên khóa ứng dụng, bạn sẽ bị khóa khỏi việc truy cập dữ liệu của mình.",
"duplicateCodes": "Mã trùng lặp",
"noDuplicates": "✨ Không có trùng lặp",
- "youveNoDuplicateCodesThatCanBeCleared": "Bạn không có mã trùng lặp nào có thể được xóa",
"deduplicateCodes": "Loại bỏ mã trùng lặp",
"deselectAll": "Bỏ chọn tất cả",
"selectAll": "Chọn tất cả",
diff --git a/auth/lib/l10n/arb/app_zh.arb b/auth/lib/l10n/arb/app_zh.arb
index a15b3f3896..b9c7ebc4ab 100644
--- a/auth/lib/l10n/arb/app_zh.arb
+++ b/auth/lib/l10n/arb/app_zh.arb
@@ -499,7 +499,6 @@
"appLockOfflineModeWarning": "您已选择继续而不备份。如果您忘记了应用锁,您将无法访问数据。",
"duplicateCodes": "重复代码",
"noDuplicates": "✨ 没有重复",
- "youveNoDuplicateCodesThatCanBeCleared": "您没有可清除的重复代码",
"deduplicateCodes": "删除重复代码",
"deselectAll": "取消全选",
"selectAll": "全选",
diff --git a/auth/lib/models/magic_metadata.dart b/auth/lib/models/magic_metadata.dart
deleted file mode 100644
index 9edab547ee..0000000000
--- a/auth/lib/models/magic_metadata.dart
+++ /dev/null
@@ -1,73 +0,0 @@
-import 'dart:convert';
-
-const visibilityVisible = 0;
-const visibilityArchive = 1;
-
-const magicKeyVisibility = 'visibility';
-
-const pubMagicKeyEditedTime = 'editedTime';
-const pubMagicKeyEditedName = 'editedName';
-
-class MagicMetadata {
- // 0 -> visible
- // 1 -> archived
- // 2 -> hidden etc?
- int visibility;
-
- MagicMetadata({required this.visibility});
-
- factory MagicMetadata.fromEncodedJson(String encodedJson) =>
- MagicMetadata.fromJson(jsonDecode(encodedJson));
-
- factory MagicMetadata.fromJson(dynamic json) => MagicMetadata.fromMap(json);
-
- static fromMap(Map? map) {
- if (map == null) return null;
- return MagicMetadata(
- visibility: map[magicKeyVisibility] ?? visibilityVisible,
- );
- }
-}
-
-class PubMagicMetadata {
- int? editedTime;
- String? editedName;
-
- PubMagicMetadata({this.editedTime, this.editedName});
-
- factory PubMagicMetadata.fromEncodedJson(String encodedJson) =>
- PubMagicMetadata.fromJson(jsonDecode(encodedJson));
-
- factory PubMagicMetadata.fromJson(dynamic json) =>
- PubMagicMetadata.fromMap(json);
-
- static fromMap(Map? map) {
- if (map == null) return null;
- return PubMagicMetadata(
- editedTime: map[pubMagicKeyEditedTime],
- editedName: map[pubMagicKeyEditedName],
- );
- }
-}
-
-class CollectionMagicMetadata {
- // 0 -> visible
- // 1 -> archived
- // 2 -> hidden etc?
- int visibility;
-
- CollectionMagicMetadata({required this.visibility});
-
- factory CollectionMagicMetadata.fromEncodedJson(String encodedJson) =>
- CollectionMagicMetadata.fromJson(jsonDecode(encodedJson));
-
- factory CollectionMagicMetadata.fromJson(dynamic json) =>
- CollectionMagicMetadata.fromMap(json);
-
- static fromMap(Map? map) {
- if (map == null) return null;
- return CollectionMagicMetadata(
- visibility: map[magicKeyVisibility] ?? visibilityVisible,
- );
- }
-}
diff --git a/auth/lib/models/public_key.dart b/auth/lib/models/public_key.dart
deleted file mode 100644
index 0d14a4a557..0000000000
--- a/auth/lib/models/public_key.dart
+++ /dev/null
@@ -1,6 +0,0 @@
-class PublicKey {
- final String email;
- final String publicKey;
-
- PublicKey(this.email, this.publicKey);
-}
diff --git a/auth/lib/services/auth_feature_flag.dart b/auth/lib/services/auth_feature_flag.dart
deleted file mode 100644
index 92a1c540d7..0000000000
--- a/auth/lib/services/auth_feature_flag.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-import 'package:ente_auth/core/configuration.dart';
-import 'package:flutter/foundation.dart';
-
-class FeatureFlagService {
- FeatureFlagService._privateConstructor();
- static final FeatureFlagService instance =
- FeatureFlagService._privateConstructor();
-
- static final _internalUserIDs = const String.fromEnvironment(
- "internal_user_ids",
- defaultValue: "1,2,3,4,191,125,1580559962388044,1580559962392434,10000025",
- ).split(",").map((element) {
- return int.parse(element);
- }).toSet();
-
- bool isInternalUserOrDebugBuild() {
- final String? email = Configuration.instance.getEmail();
- final userID = Configuration.instance.getUserID();
- return (email != null && email.endsWith("@ente.io")) ||
- _internalUserIDs.contains(userID) ||
- kDebugMode;
- }
-}
diff --git a/auth/lib/services/window_listener_service.dart b/auth/lib/services/window_listener_service.dart
index 73f431116f..bb5d1cbcfa 100644
--- a/auth/lib/services/window_listener_service.dart
+++ b/auth/lib/services/window_listener_service.dart
@@ -6,7 +6,7 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:window_manager/window_manager.dart';
class WindowListenerService {
- static const double minWindowHeight = 320.0;
+ static const double minWindowHeight = 600.0;
static const double minWindowWidth = 800.0;
static const double maxWindowHeight = 8192.0;
static const double maxWindowWidth = 8192.0;
diff --git a/auth/lib/store/user_store.dart b/auth/lib/store/user_store.dart
deleted file mode 100644
index b191d169d8..0000000000
--- a/auth/lib/store/user_store.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-import 'package:shared_preferences/shared_preferences.dart';
-
-class UserStore {
- UserStore._privateConstructor();
-
- // ignore: unused_field
- late SharedPreferences _preferences;
-
- static final UserStore instance = UserStore._privateConstructor();
-
- Future init() async {
- _preferences = await SharedPreferences.getInstance();
- }
-}
diff --git a/auth/lib/ui/account/login_pwd_verification_page.dart b/auth/lib/ui/account/login_pwd_verification_page.dart
index d5ae7a3dbc..6d43988e2c 100644
--- a/auth/lib/ui/account/login_pwd_verification_page.dart
+++ b/auth/lib/ui/account/login_pwd_verification_page.dart
@@ -113,7 +113,7 @@ class _LoginPasswordVerificationPageState
);
} else {
_logger.severe('API failure during SRP login', e, s);
- if (e.type == DioExceptionType.unknown) {
+ if (e.type == DioExceptionType.connectionError) {
await _showContactSupportDialog(
context,
context.l10n.noInternetConnection,
diff --git a/auth/lib/ui/common/bottom_shadow.dart b/auth/lib/ui/common/bottom_shadow.dart
deleted file mode 100644
index 2de7e944e2..0000000000
--- a/auth/lib/ui/common/bottom_shadow.dart
+++ /dev/null
@@ -1,25 +0,0 @@
-import 'package:flutter/material.dart';
-
-class BottomShadowWidget extends StatelessWidget {
- final double offsetDy;
- final Color? shadowColor;
- const BottomShadowWidget({this.offsetDy = 28, this.shadowColor, super.key});
-
- @override
- Widget build(BuildContext context) {
- return Container(
- height: 8,
- decoration: BoxDecoration(
- color: Colors.transparent,
- boxShadow: [
- BoxShadow(
- color: shadowColor ?? Theme.of(context).colorScheme.surface,
- spreadRadius: 42,
- blurRadius: 42,
- offset: Offset(0, offsetDy), // changes position of shadow
- ),
- ],
- ),
- );
- }
-}
diff --git a/auth/lib/ui/common/linear_progress_dialog.dart b/auth/lib/ui/common/linear_progress_dialog.dart
deleted file mode 100644
index 08c46d6c97..0000000000
--- a/auth/lib/ui/common/linear_progress_dialog.dart
+++ /dev/null
@@ -1,49 +0,0 @@
-import 'package:ente_auth/ente_theme_data.dart';
-import 'package:flutter/material.dart';
-
-class LinearProgressDialog extends StatefulWidget {
- final String message;
-
- const LinearProgressDialog(this.message, {super.key});
-
- @override
- LinearProgressDialogState createState() => LinearProgressDialogState();
-}
-
-class LinearProgressDialogState extends State {
- double? _progress;
-
- @override
- void initState() {
- _progress = 0;
- super.initState();
- }
-
- void setProgress(double progress) {
- setState(() {
- _progress = progress;
- });
- }
-
- @override
- Widget build(BuildContext context) {
- return PopScope(
- canPop: false,
- child: AlertDialog(
- title: Text(
- widget.message,
- style: const TextStyle(
- fontSize: 16,
- ),
- textAlign: TextAlign.center,
- ),
- content: LinearProgressIndicator(
- value: _progress,
- valueColor: AlwaysStoppedAnimation(
- Theme.of(context).colorScheme.alternativeColor,
- ),
- ),
- ),
- );
- }
-}
diff --git a/auth/lib/ui/common/rename_dialog.dart b/auth/lib/ui/common/rename_dialog.dart
deleted file mode 100644
index ad93d1abaa..0000000000
--- a/auth/lib/ui/common/rename_dialog.dart
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-import 'package:ente_auth/utils/dialog_util.dart';
-import 'package:flutter/material.dart';
-
-class RenameDialog extends StatefulWidget {
- final String name;
- final String type;
- final int maxLength;
-
- const RenameDialog(this.name, this.type, {super.key, this.maxLength = 100});
-
- @override
- State createState() => _RenameDialogState();
-}
-
-class _RenameDialogState extends State {
- String? _newName;
-
- @override
- void initState() {
- super.initState();
- _newName = widget.name;
- }
-
- @override
- Widget build(BuildContext context) {
- return AlertDialog(
- title: const Text("Enter a new name"),
- content: SingleChildScrollView(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.start,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- TextFormField(
- decoration: InputDecoration(
- hintText: '${widget.type} name',
- hintStyle: const TextStyle(
- color: Colors.white30,
- ),
- contentPadding: const EdgeInsets.all(12),
- ),
- onChanged: (value) {
- setState(() {
- _newName = value;
- });
- },
- autocorrect: false,
- keyboardType: TextInputType.text,
- initialValue: _newName,
- autofocus: true,
- ),
- ],
- ),
- ),
- actions: [
- TextButton(
- child: const Text(
- "Cancel",
- style: TextStyle(
- color: Colors.redAccent,
- ),
- ),
- onPressed: () {
- Navigator.of(context).pop(null);
- },
- ),
- TextButton(
- child: Text(
- "Rename",
- style: TextStyle(
- color: Theme.of(context).colorScheme.onSurface,
- ),
- ),
- onPressed: () {
- if (_newName!.trim().isEmpty) {
- showErrorDialog(
- context,
- "Empty name",
- "${widget.type} name cannot be empty",
- );
- return;
- }
- if (_newName!.trim().length > widget.maxLength) {
- showErrorDialog(
- context,
- "Name too large",
- "${widget.type} name should be less than ${widget.maxLength} characters",
- );
- return;
- }
- Navigator.of(context).pop(_newName!.trim());
- },
- ),
- ],
- );
- }
-}
diff --git a/auth/lib/ui/components/home_header_widget.dart b/auth/lib/ui/components/home_header_widget.dart
deleted file mode 100644
index 0079cc7fa7..0000000000
--- a/auth/lib/ui/components/home_header_widget.dart
+++ /dev/null
@@ -1,41 +0,0 @@
-import 'package:ente_auth/core/event_bus.dart';
-import 'package:ente_auth/events/opened_settings_event.dart';
-import 'package:flutter/material.dart';
-
-class HomeHeaderWidget extends StatefulWidget {
- final Widget centerWidget;
- const HomeHeaderWidget({required this.centerWidget, super.key});
-
- @override
- State createState() => _HomeHeaderWidgetState();
-}
-
-class _HomeHeaderWidgetState extends State {
- @override
- Widget build(BuildContext context) {
- final hasNotch = View.of(context).viewPadding.top > 65;
- return Padding(
- padding: EdgeInsets.fromLTRB(4, hasNotch ? 4 : 8, 4, 4),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- IconButton(
- visualDensity: const VisualDensity(horizontal: -2, vertical: -2),
- onPressed: () {
- Scaffold.of(context).openDrawer();
- Bus.instance.fire(OpenedSettingsEvent());
- },
- splashColor: Colors.transparent,
- icon: const Icon(
- Icons.menu_outlined,
- ),
- ),
- AnimatedSwitcher(
- duration: const Duration(milliseconds: 250),
- child: widget.centerWidget,
- ),
- ],
- ),
- );
- }
-}
diff --git a/auth/lib/ui/settings/danger_section_widget.dart b/auth/lib/ui/settings/danger_section_widget.dart
deleted file mode 100644
index 4f8160c38e..0000000000
--- a/auth/lib/ui/settings/danger_section_widget.dart
+++ /dev/null
@@ -1,69 +0,0 @@
-import 'package:ente_auth/l10n/l10n.dart';
-import 'package:ente_auth/services/user_service.dart';
-import 'package:ente_auth/theme/ente_theme.dart';
-import 'package:ente_auth/ui/account/delete_account_page.dart';
-import 'package:ente_auth/ui/components/captioned_text_widget.dart';
-import 'package:ente_auth/ui/components/expandable_menu_item_widget.dart';
-import 'package:ente_auth/ui/components/menu_item_widget.dart';
-import 'package:ente_auth/ui/settings/common_settings.dart';
-import 'package:ente_auth/utils/dialog_util.dart';
-import 'package:ente_auth/utils/navigation_util.dart';
-import 'package:flutter/material.dart';
-
-class DangerSectionWidget extends StatelessWidget {
- const DangerSectionWidget({super.key});
-
- @override
- Widget build(BuildContext context) {
- return ExpandableMenuItemWidget(
- title: context.l10n.exit,
- selectionOptionsWidget: _getSectionOptions(context),
- leadingIcon: Icons.logout_outlined,
- );
- }
-
- Widget _getSectionOptions(BuildContext context) {
- return Column(
- children: [
- sectionOptionSpacing,
- MenuItemWidget(
- captionedTextWidget: CaptionedTextWidget(
- title: context.l10n.logout,
- ),
- pressedColor: getEnteColorScheme(context).fillFaint,
- trailingIcon: Icons.chevron_right_outlined,
- trailingIconIsMuted: true,
- onTap: () async {
- _onLogoutTapped(context);
- },
- ),
- sectionOptionSpacing,
- MenuItemWidget(
- captionedTextWidget: CaptionedTextWidget(
- title: context.l10n.deleteAccount,
- ),
- pressedColor: getEnteColorScheme(context).fillFaint,
- trailingIcon: Icons.chevron_right_outlined,
- trailingIconIsMuted: true,
- onTap: () async {
- // ignore: unawaited_futures
- routeToPage(context, const DeleteAccountPage());
- },
- ),
- sectionOptionSpacing,
- ],
- );
- }
-
- void _onLogoutTapped(BuildContext context) {
- showChoiceActionSheet(
- context,
- title: context.l10n.areYouSureYouWantToLogout,
- firstButtonLabel: context.l10n.yesLogout,
- isCritical: true,
- firstButtonOnTap: () async {
- await UserService.instance.logout(context);
- },
- );
- }
-}
diff --git a/auth/lib/ui/settings/debug_section_widget.dart b/auth/lib/ui/settings/debug_section_widget.dart
deleted file mode 100644
index 03406f7911..0000000000
--- a/auth/lib/ui/settings/debug_section_widget.dart
+++ /dev/null
@@ -1,94 +0,0 @@
-import 'package:ente_auth/core/configuration.dart';
-import 'package:ente_auth/l10n/l10n.dart';
-import 'package:ente_auth/ui/settings/common_settings.dart';
-import 'package:ente_auth/ui/settings/settings_section_title.dart';
-import 'package:ente_auth/ui/settings/settings_text_item.dart';
-import 'package:ente_crypto_dart/ente_crypto_dart.dart';
-import 'package:expandable/expandable.dart';
-import 'package:flutter/material.dart';
-
-class DebugSectionWidget extends StatelessWidget {
- const DebugSectionWidget({super.key});
-
- @override
- Widget build(BuildContext context) {
- // This is a debug only section not shown to end users, so these strings are
- // not translated.
- return ExpandablePanel(
- header: const SettingsSectionTitle("Debug"),
- collapsed: Container(),
- expanded: _getSectionOptions(context),
- theme: getExpandableTheme(),
- );
- }
-
- Widget _getSectionOptions(BuildContext context) {
- return Column(
- children: [
- GestureDetector(
- behavior: HitTestBehavior.translucent,
- onTap: () async {
- _showKeyAttributesDialog(context);
- },
- child: const SettingsTextItem(
- text: "Key attributes",
- icon: Icons.navigate_next,
- ),
- ),
- ],
- );
- }
-
- void _showKeyAttributesDialog(BuildContext context) {
- final l10n = context.l10n;
- final keyAttributes = Configuration.instance.getKeyAttributes()!;
- final AlertDialog alert = AlertDialog(
- title: const Text("key attributes"),
- content: SingleChildScrollView(
- child: Column(
- children: [
- const Text(
- "Key",
- style: TextStyle(fontWeight: FontWeight.bold),
- ),
- Text(CryptoUtil.bin2base64(Configuration.instance.getKey()!)),
- const Padding(padding: EdgeInsets.all(12)),
- const Text(
- "Encrypted Key",
- style: TextStyle(fontWeight: FontWeight.bold),
- ),
- Text(keyAttributes.encryptedKey),
- const Padding(padding: EdgeInsets.all(12)),
- const Text(
- "Key Decryption Nonce",
- style: TextStyle(fontWeight: FontWeight.bold),
- ),
- Text(keyAttributes.keyDecryptionNonce),
- const Padding(padding: EdgeInsets.all(12)),
- const Text(
- "KEK Salt",
- style: TextStyle(fontWeight: FontWeight.bold),
- ),
- Text(keyAttributes.kekSalt),
- const Padding(padding: EdgeInsets.all(12)),
- ],
- ),
- ),
- actions: [
- TextButton(
- child: Text(l10n.ok),
- onPressed: () {
- Navigator.of(context, rootNavigator: true).pop('dialog');
- },
- ),
- ],
- );
-
- showDialog(
- context: context,
- builder: (BuildContext context) {
- return alert;
- },
- );
- }
-}
diff --git a/auth/lib/ui/settings/made_with_love_widget.dart b/auth/lib/ui/settings/made_with_love_widget.dart
deleted file mode 100644
index a8e12c106b..0000000000
--- a/auth/lib/ui/settings/made_with_love_widget.dart
+++ /dev/null
@@ -1,34 +0,0 @@
-import 'package:ente_auth/l10n/l10n.dart';
-import 'package:flutter/material.dart';
-import 'package:url_launcher/url_launcher.dart';
-
-class MadeWithLoveWidget extends StatelessWidget {
- const MadeWithLoveWidget({
- super.key,
- });
-
- @override
- Widget build(BuildContext context) {
- final l10n = context.l10n;
- return GestureDetector(
- onTap: () {
- launchUrl(Uri.parse("https://ente.io"));
- },
- child: RichText(
- text: TextSpan(
- text: l10n.madeWithLoveAtPrefix,
- style: DefaultTextStyle.of(context).style,
- children: const [
- TextSpan(
- text: 'ente.io',
- style: TextStyle(
- fontWeight: FontWeight.bold,
- color: Colors.green,
- ),
- ),
- ],
- ),
- ),
- );
- }
-}
diff --git a/auth/lib/ui/settings/settings_text_item.dart b/auth/lib/ui/settings/settings_text_item.dart
deleted file mode 100644
index afaf56432c..0000000000
--- a/auth/lib/ui/settings/settings_text_item.dart
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-import 'dart:io';
-
-import 'package:flutter/material.dart';
-
-class SettingsTextItem extends StatelessWidget {
- final String text;
- final IconData icon;
- const SettingsTextItem({
- super.key,
- required this.text,
- required this.icon,
- });
-
- @override
- Widget build(BuildContext context) {
- return Column(
- children: [
- Padding(padding: EdgeInsets.all(Platform.isIOS ? 4 : 6)),
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Align(
- alignment: Alignment.centerLeft,
- child: Text(text, style: Theme.of(context).textTheme.titleMedium),
- ),
- Icon(icon),
- ],
- ),
- Padding(padding: EdgeInsets.all(Platform.isIOS ? 4 : 6)),
- ],
- );
- }
-}
diff --git a/auth/lib/ui/settings/support_dev_widget.dart b/auth/lib/ui/settings/support_dev_widget.dart
deleted file mode 100644
index 849b954153..0000000000
--- a/auth/lib/ui/settings/support_dev_widget.dart
+++ /dev/null
@@ -1,83 +0,0 @@
-import 'package:dotted_border/dotted_border.dart';
-import 'package:ente_auth/core/configuration.dart';
-import 'package:ente_auth/l10n/l10n.dart';
-import 'package:ente_auth/models/subscription.dart';
-import 'package:ente_auth/services/billing_service.dart';
-import 'package:ente_auth/theme/ente_theme.dart';
-import 'package:flutter/material.dart';
-import 'package:styled_text/styled_text.dart';
-import 'package:url_launcher/url_launcher.dart';
-
-class SupportDevWidget extends StatelessWidget {
- const SupportDevWidget({
- super.key,
- });
-
- @override
- Widget build(BuildContext context) {
- final l10n = context.l10n;
-
- // fetch
- if (Configuration.instance.hasConfiguredAccount()) {
- return FutureBuilder(
- future: BillingService.instance.getSubscription(),
- builder: (context, snapshot) {
- if (snapshot.hasData) {
- final subscription = snapshot.data;
- if (subscription != null && subscription.productID == "free") {
- return buildWidget(l10n, context);
- }
- }
- return const SizedBox.shrink();
- },
- );
- } else {
- return buildWidget(l10n, context);
- }
- }
-
- Widget buildWidget(AppLocalizations l10n, BuildContext context) {
- return GestureDetector(
- onTap: () {
- launchUrl(Uri.parse("https://ente.io"));
- },
- child: DottedBorder(
- borderType: BorderType.RRect,
- radius: const Radius.circular(12),
- padding: const EdgeInsets.all(6),
- dashPattern: const [3, 3],
- color: getEnteColorScheme(context).primaryGreen,
- child: ClipRRect(
- borderRadius: const BorderRadius.all(Radius.circular(12)),
- child: Padding(
- padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 6),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- StyledText(
- text: l10n.supportDevs,
- style: getEnteTextTheme(context).large,
- tags: {
- 'bold-green': StyledTextTag(
- style: TextStyle(
- fontWeight: FontWeight.bold,
- color: getEnteColorScheme(context).primaryGreen,
- ),
- ),
- },
- ),
- const Padding(padding: EdgeInsets.all(6)),
- Text(
- l10n.supportDiscount,
- style: const TextStyle(
- color: Colors.grey,
- ),
- ),
- ],
- ),
- ),
- ),
- ),
- );
- }
-}
diff --git a/auth/lib/ui/settings_section_title.dart b/auth/lib/ui/settings_section_title.dart
deleted file mode 100644
index 613744d49d..0000000000
--- a/auth/lib/ui/settings_section_title.dart
+++ /dev/null
@@ -1 +0,0 @@
-// TODO Implement this library.
diff --git a/auth/lib/utils/dialog_util.dart b/auth/lib/utils/dialog_util.dart
index f747b41f4d..1f64414f8f 100644
--- a/auth/lib/utils/dialog_util.dart
+++ b/auth/lib/utils/dialog_util.dart
@@ -113,12 +113,12 @@ String parseErrorForUI(
if (dioError.response?.data["code"] != null) {
errorInfo = "Reason: ${dioError.response!.data["code"]}";
} else {
- errorInfo = "Reason: ${dioError.response!.data}";
+ errorInfo = "Reason: ${dioError.response!.data.toString()}";
}
- } else if (dioError.type == DioExceptionType.unknown) {
- errorInfo = "Reason: $dioError.error";
+ } else if (dioError.type == DioExceptionType.badCertificate) {
+ errorInfo = "Reason: ${dioError.error.toString()}";
} else {
- errorInfo = "Reason: $dioError.type";
+ errorInfo = "Reason: ${dioError.type.toString()}";
}
} else {
if (kDebugMode) {
diff --git a/auth/pubspec.lock b/auth/pubspec.lock
index 3d5d6e9cab..9795a507a8 100644
--- a/auth/pubspec.lock
+++ b/auth/pubspec.lock
@@ -250,10 +250,10 @@ packages:
dependency: "direct main"
description:
name: collection
- sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
+ sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
url: "https://pub.dev"
source: hosted
- version: "1.18.0"
+ version: "1.19.0"
confetti:
dependency: "direct main"
description:
@@ -286,6 +286,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.1"
+ cronet_http:
+ dependency: transitive
+ description:
+ name: cronet_http
+ sha256: "3af9c4d57bf07ef4b307e77b22be4ad61bea19ee6ff65e62184863f3a09f1415"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.2"
cross_file:
dependency: transitive
description:
@@ -310,6 +318,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.0"
+ cupertino_http:
+ dependency: transitive
+ description:
+ name: cupertino_http
+ sha256: "6fcf79586ad872ddcd6004d55c8c2aab3cdf0337436e8f99837b1b6c30665d0c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.2"
dart_style:
dependency: transitive
description:
@@ -346,10 +362,10 @@ packages:
dependency: "direct main"
description:
name: dio
- sha256: "5598aa796bbf4699afd5c67c0f5f6e2ed542afc956884b9cd58c306966efc260"
+ sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9"
url: "https://pub.dev"
source: hosted
- version: "5.7.0"
+ version: "5.8.0+1"
dio_web_adapter:
dependency: transitive
description:
@@ -861,6 +877,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.2"
+ http_profile:
+ dependency: transitive
+ description:
+ name: http_profile
+ sha256: "7e679e355b09aaee2ab5010915c932cce3f2d1c11c3b2dc177891687014ffa78"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.1.0"
image:
dependency: transitive
description:
@@ -885,6 +909,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.4"
+ jni:
+ dependency: transitive
+ description:
+ name: jni
+ sha256: f377c585ea9c08d48b427dc2e03780af2889d1bb094440da853c6883c1acba4b
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.10.1"
js:
dependency: transitive
description:
@@ -1061,6 +1093,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.2"
+ native_dio_adapter:
+ dependency: "direct main"
+ description:
+ name: native_dio_adapter
+ sha256: "7420bc9517b2abe09810199a19924617b45690a44ecfb0616ac9babc11875c03"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.4.0"
nested:
dependency: transitive
description:
@@ -1077,6 +1117,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.5.0"
+ objective_c:
+ dependency: transitive
+ description:
+ name: objective_c
+ sha256: "62e79ab8c3ed6f6a340ea50dd48d65898f5d70425d404f0d99411f6e56e04584"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.1.0"
otp:
dependency: "direct main"
description:
diff --git a/auth/pubspec.yaml b/auth/pubspec.yaml
index 179586a3b2..7816992bd5 100644
--- a/auth/pubspec.yaml
+++ b/auth/pubspec.yaml
@@ -21,7 +21,7 @@ dependencies:
connectivity_plus: ^6.0.5
convert: ^3.1.1
device_info_plus: ^9.1.1
- dio: ^5.4.0
+ dio: ^5.8.0+1
dotted_border: ^2.0.0+2
dropdown_button2: ^2.3.9
email_validator: ^3.0.0
@@ -72,6 +72,7 @@ dependencies:
logging: ^1.0.1
modal_bottom_sheet: ^3.0.0
move_to_background: ^1.0.2
+ native_dio_adapter: ^1.4.0
otp: ^3.1.1
package_info_plus: ^8.0.2
password_strength: ^0.2.0
diff --git a/cli/main.go b/cli/main.go
index 990d751b01..15dc6ac5a3 100644
--- a/cli/main.go
+++ b/cli/main.go
@@ -15,7 +15,7 @@ import (
"strings"
)
-var AppVersion = "0.2.2"
+var AppVersion = "0.2.3"
func main() {
cliConfigDir, err := GetCLIConfigDir()
@@ -50,18 +50,21 @@ func main() {
}
}
- // Define a set of commands that do not require KeyHolder initialisation.
- skipKeyHolderCommands := map[string]struct{}{"version": {}, "docs": {}, "help": {}}
+ // Define a set of commands that do not require KeyHolder or cli initialisation.
+ skipInitCommands := map[string]struct{}{"version": {}, "docs": {}, "help": {}}
var keyHolder *secrets.KeyHolder
-
// Only initialise KeyHolder if the command isn't in the skip list.
+ shouldInit := len(os.Args) > 1
if len(os.Args) > 1 {
- if _, skip := skipKeyHolderCommands[os.Args[1]]; !skip {
- keyHolder = secrets.NewKeyHolder(secrets.GetOrCreateClISecret())
+ if _, skip := skipInitCommands[os.Args[1]]; skip {
+ shouldInit = false
}
}
+ if shouldInit {
+ keyHolder = secrets.NewKeyHolder(secrets.GetOrCreateClISecret())
+ }
ctrl := pkg.ClICtrl{
Client: api.NewClient(api.Params{
Debug: viper.GetBool("log.http"),
@@ -71,16 +74,10 @@ func main() {
KeyHolder: keyHolder,
}
- err = ctrl.Init()
- if err != nil {
- panic(err)
+ if len(os.Args) == 1 {
+ // If no arguments are passed, show help
+ os.Args = append(os.Args, "help")
}
- defer func() {
- if err := db.Close(); err != nil {
- panic(err)
- }
- }()
-
if len(os.Args) == 2 && os.Args[1] == "docs" {
log.Println("Generating docs")
err = cmd.GenerateDocs()
@@ -89,9 +86,16 @@ func main() {
}
return
}
- if len(os.Args) == 1 {
- // If no arguments are passed, show help
- os.Args = append(os.Args, "help")
+ if shouldInit {
+ err = ctrl.Init()
+ if err != nil {
+ panic(err)
+ }
+ defer func() {
+ if err := db.Close(); err != nil {
+ panic(err)
+ }
+ }()
}
if os.Args[1] == "version" && viper.GetString("endpoint.api") != constants.EnteApiUrl {
log.Printf("Custom endpoint: %s\n", viper.GetString("endpoint.api"))
@@ -120,10 +124,10 @@ func initConfig(cliConfigDir string) {
func GetCLIConfigDir() (string, error) {
var configDir = os.Getenv("ENTE_CLI_CONFIG_DIR")
- if configDir == "" {
- // for backward compatibility, check for ENTE_CLI_CONFIG_PATH
- configDir = os.Getenv("ENTE_CLI_CONFIG_PATH")
- }
+ if configDir == "" {
+ // for backward compatibility, check for ENTE_CLI_CONFIG_PATH
+ configDir = os.Getenv("ENTE_CLI_CONFIG_PATH")
+ }
if configDir != "" {
// remove trailing slash (for all OS)
diff --git a/desktop/CHANGELOG.md b/desktop/CHANGELOG.md
index aa647dd8e6..bbefd6c513 100644
--- a/desktop/CHANGELOG.md
+++ b/desktop/CHANGELOG.md
@@ -1,11 +1,20 @@
# CHANGELOG
-## v1.7.9 (Unreleased)
+## v1.7.11 (Unreleased)
+
+- .
+
+## v1.7.10
+
+- Speed up selection for large libraries.
+- Support Japanese translations.
+- Fix video thumbnail generation on drag and drop.
+
+## v1.7.9
- Light mode.
- Faster and more stable thumbnail generation.
- Support `.supplemental-metadata` JSON files in Google Takeout.
-- .
## v1.7.8
diff --git a/desktop/build/io.ente.photos.appdata.xml b/desktop/build/io.ente.photos.appdata.xml
index 40ff45176d..591f51232f 100644
--- a/desktop/build/io.ente.photos.appdata.xml
+++ b/desktop/build/io.ente.photos.appdata.xml
@@ -38,8 +38,8 @@
-
- https://github.com/ente-io/photos-desktop/releases/tag/v1.7.8
+
+ https://github.com/ente-io/photos-desktop/releases
diff --git a/desktop/package.json b/desktop/package.json
index 3859892503..4570c525b0 100644
--- a/desktop/package.json
+++ b/desktop/package.json
@@ -1,6 +1,6 @@
{
"name": "ente",
- "version": "1.7.9-beta",
+ "version": "1.7.11-beta",
"private": true,
"description": "Desktop client for Ente Photos",
"repository": "github:ente-io/photos-desktop",
diff --git a/desktop/src/main.ts b/desktop/src/main.ts
index 8aa32169b1..46aab1bfc1 100644
--- a/desktop/src/main.ts
+++ b/desktop/src/main.ts
@@ -362,8 +362,18 @@ const createMainWindow = () => {
// do it (Step 2) unconditionally (i.e., on macOS too).
//
// https://www.electronjs.org/docs/latest/tutorial/custom-title-bar#create-a-custom-title-bar
+ //
+ // Note that by default on Windows, the color of the WCO title bar
+ // overlay (three buttons - minimize, maximize, close - on the top
+ // right) is static, and unlike Linux, doesn't adapt to the theme /
+ // content. Explicitly choosing a dark background, while it won't work
+ // always (if the user's theme is light), is better than picking a light
+ // background since the main image viewer is always dark.
titleBarStyle: "hidden",
- titleBarOverlay: true,
+ titleBarOverlay:
+ process.platform == "win32"
+ ? { color: "black", symbolColor: "#cdcdcd" }
+ : true,
// The color to show in the window until the web content gets loaded.
// https://www.electronjs.org/docs/latest/api/browser-window#setting-the-backgroundcolor-property
//
diff --git a/desktop/src/main/ipc.ts b/desktop/src/main/ipc.ts
index ff98e2ec88..b0a2eccf0c 100644
--- a/desktop/src/main/ipc.ts
+++ b/desktop/src/main/ipc.ts
@@ -41,6 +41,7 @@ import {
fsRm,
fsRmdir,
fsWriteFile,
+ fsWriteFileViaBackup,
} from "./services/fs";
import { convertToJPEG, generateImageThumbnail } from "./services/image";
import { logout } from "./services/logout";
@@ -154,6 +155,12 @@ export const attachIPCHandlers = () => {
fsWriteFile(path, contents),
);
+ ipcMain.handle(
+ "fsWriteFileViaBackup",
+ (_, path: string, contents: string) =>
+ fsWriteFileViaBackup(path, contents),
+ );
+
ipcMain.handle("fsIsDir", (_, dirPath: string) => fsIsDir(dirPath));
ipcMain.handle("fsFindFiles", (_, folderPath: string) =>
diff --git a/desktop/src/main/services/fs.ts b/desktop/src/main/services/fs.ts
index cdbded0beb..6cfe101ebf 100644
--- a/desktop/src/main/services/fs.ts
+++ b/desktop/src/main/services/fs.ts
@@ -24,6 +24,12 @@ export const fsReadTextFile = async (filePath: string) =>
export const fsWriteFile = (path: string, contents: string) =>
fs.writeFile(path, contents, { flush: true });
+export const fsWriteFileViaBackup = async (path: string, contents: string) => {
+ const backupPath = path + ".backup";
+ await fs.writeFile(backupPath, contents, { flush: true });
+ return fs.rename(backupPath, path);
+};
+
export const fsIsDir = async (dirPath: string) => {
if (!existsSync(dirPath)) return false;
const stat = await fs.stat(dirPath);
diff --git a/desktop/src/preload.ts b/desktop/src/preload.ts
index cb9d594511..3fab447722 100644
--- a/desktop/src/preload.ts
+++ b/desktop/src/preload.ts
@@ -178,6 +178,9 @@ const fsReadTextFile = (path: string) =>
const fsWriteFile = (path: string, contents: string) =>
ipcRenderer.invoke("fsWriteFile", path, contents);
+const fsWriteFileViaBackup = (path: string, contents: string) =>
+ ipcRenderer.invoke("fsWriteFileViaBackup", path, contents);
+
const fsIsDir = (dirPath: string) => ipcRenderer.invoke("fsIsDir", dirPath);
// - Conversion
@@ -373,6 +376,7 @@ contextBridge.exposeInMainWorld("electron", {
rm: fsRm,
readTextFile: fsReadTextFile,
writeFile: fsWriteFile,
+ writeFileViaBackup: fsWriteFileViaBackup,
isDir: fsIsDir,
findFiles: fsFindFiles,
},
diff --git a/docs/docs/.vitepress/sidebar.ts b/docs/docs/.vitepress/sidebar.ts
index 361811638a..40123e4795 100644
--- a/docs/docs/.vitepress/sidebar.ts
+++ b/docs/docs/.vitepress/sidebar.ts
@@ -135,8 +135,12 @@ export const sidebar = [
link: "/photos/faq/hidden-and-archive",
},
{
- text: "Machine Learning",
- link: "/photos/faq/machine-learning",
+ text: "Face recognition",
+ link: "/photos/faq/face-recognition",
+ },
+ {
+ text: "Video streaming",
+ link: "/photos/faq/video-streaming",
},
],
},
@@ -263,6 +267,10 @@ export const sidebar = [
text: "Hosting Ente without Docker",
link: "/self-hosting/guides/standalone-ente",
},
+ {
+ text: "Ente via Tailscale (Community)",
+ link: "/self-hosting/guides/Tailscale.md",
+ },
{
text: "Configure CLI for Self Hosted Instance",
link: "/self-hosting/guides/selfhost-cli",
diff --git a/docs/docs/photos/faq/machine-learning.md b/docs/docs/photos/faq/face-recognition.md
similarity index 80%
rename from docs/docs/photos/faq/machine-learning.md
rename to docs/docs/photos/faq/face-recognition.md
index 53bf5ca558..24c9650345 100644
--- a/docs/docs/photos/faq/machine-learning.md
+++ b/docs/docs/photos/faq/face-recognition.md
@@ -1,10 +1,10 @@
---
-title: Machine Learning FAQ
+title: Face recognition
description:
- Frequently asked questions about several features of Ente's ML suite
+ Frequently asked questions about Ente's face recognition
---
-# Machine Learning
+# Face recognition
## Can I merge or de-merge persons recognized by the app?
@@ -19,7 +19,7 @@ instead of typing the name again, tap on the already given name that should now
be listed.
De-merging a certain grouping can be done by going to the person, pressing
-`review suggestions` and then the top right `history icon`. Now press on the
+`Review suggestions` and then the top right `History icon`. Now press on the
`minus icon` beside the group you want to de-merge.
### Desktop
@@ -29,6 +29,16 @@ selecting an existing person, and use the "Review suggestions" sheet to de-merge
previously merged persons (click the top right history icon on the suggestion
sheet to see the previous merges, and if necessary, undo them).
+## How can I remove an incorrectly grouped face from a person?
+
+On our mobile app, open up the person from the People section, click on the
+three dots to open up overflow menu, and click on Edit. Now you will be
+presented with the list of all photos that were merged to create this person.
+
+You can click on the merged photos and select the photos you think are
+incorrectly grouped (by long-pressing on them) and select "Remove" from the
+action bar that pops up to remove any incorrect faces.
+
## How do I change the cover for a recognized person?
### Mobile
diff --git a/docs/docs/photos/faq/general.md b/docs/docs/photos/faq/general.md
index 0e911f82e6..72bbbf6ea2 100644
--- a/docs/docs/photos/faq/general.md
+++ b/docs/docs/photos/faq/general.md
@@ -112,3 +112,7 @@ https://github.com/ente-io/ente/tree/main/cli#readme.
Currently, the Ente mobile app allows you to see a map view of all the albums by
clicking on "Your map" under "Locations" on the search screen.
+
+## How to reset my password if I lost it?
+
+On the login page, enter your email and click on Forgot Password. Then, enter your recovery key and create a new password.
\ No newline at end of file
diff --git a/docs/docs/photos/faq/hidden-and-archive.md b/docs/docs/photos/faq/hidden-and-archive.md
index bdfb6f1b08..d9106da121 100644
--- a/docs/docs/photos/faq/hidden-and-archive.md
+++ b/docs/docs/photos/faq/hidden-and-archive.md
@@ -19,9 +19,6 @@ Keep in mind that hidden items will still show up in the "On device" albums
within Ente as long as they are present in your native gallery. But once you
remove them from your device, they'll stop showing up here.
-Hiding is currently only supported in the Ente mobile app, and items hidden from
-the mobile app will not be visible in the web and desktop app.
-
For more details, see [features/hide](/photos/features/hide).
### Archive
diff --git a/docs/docs/photos/faq/metadata.md b/docs/docs/photos/faq/metadata.md
index 936a3e67dc..03cf10da65 100644
--- a/docs/docs/photos/faq/metadata.md
+++ b/docs/docs/photos/faq/metadata.md
@@ -1,12 +1,11 @@
---
title: Metadata
-description: Handling of metadata, in particular creation dates, in Ente Photos
+description: Handling of metadata in Ente Photos
---
# Metadata
-This document describes Ente's handling of metadata, in particular photo
-creation dates.
+This document describes Ente's handling of metadata
## Import
@@ -46,7 +45,7 @@ importing that folder into Ente**. This way, we will be able to always correctly
map, for example, `flower.jpeg` and `flower.json` and show the same date for
`flower.jpeg` that you would've seen within Google Photos.
-### Screenshots
+### File name
In case the photo does not have a date in the Exif data (and it is not a Google
takeout), for example, for screenshots or Whatsapp forwards, Ente will still try
@@ -57,6 +56,28 @@ and deduce the correct date for the file from the name of the file.
> This process works great most of the time, but it is inherently based on
> heuristics and is not exact.
+If we are unable to decipher the creation time from these 3 sources, we will set
+the upload time as the photo's creation time.
+
+## Modifications
+
+Ente supports modifications to the following metadata:
+- File name
+- Date & time
+- Location
+
+The first two options are available on both mobile and desktop, while the
+ability to update location is only available within our mobile apps.
+
+### Bulk modifications
+
+You can bulk-edit creation time of photos from our desktop app, by
+multi-selecting items and selecting the "Fix time" option from the action bar.
+
+You can bulk-edit location coordinates of photos from our mobile app, by
+multi-selecting items and selecting the "Edit location" option from the action
+bar.
+
## Export
Ente guarantees that you will get back the _exact_ same original photos and
diff --git a/docs/docs/photos/faq/security-and-privacy.md b/docs/docs/photos/faq/security-and-privacy.md
index 0ee3f9b024..6f40ab043f 100644
--- a/docs/docs/photos/faq/security-and-privacy.md
+++ b/docs/docs/photos/faq/security-and-privacy.md
@@ -47,6 +47,9 @@ availability and durability. Our
[reliability document](https://ente.io/reliability) provides in-depth
information about our storage infrastructure and data replication strategies.
+In short, we store 3 copies of your data, across 3 different providers, in 3
+different countries. One of them is in an underground fall-out shelter in Paris.
+
### How does Ente's encryption compare to industry standards?
Our encryption model goes beyond industry standards. While many services use
@@ -55,14 +58,17 @@ in the unlikely event of a server breach, your data remains protected.
## Account Security
-### What happens if I forget my password?
+### What happens if I forget my password? {#account-recovery}
-You can reset your password using your recovery key that was provided to you
-during account creation. Please store this key securely, as it's your lifeline
-if you forget your password.
+If you are logged into Ente on any of your existing devices, you can use that
+device to reset your password and use your new password to log in.
-If you lose both your password and recovery key, we cannot recover your account
-or data due to our end-to-end encrypted architecture.
+If you are logged out of Ente on all your devices, you can reset your password
+using your recovery key that was provided to you during account creation.
+
+If you are logged out of Ente on all your devices and you have lost both your
+password and recovery key, we cannot recover your account or data due to our
+end-to-end encrypted architecture.
If you wish to delete your account in such scenarios, please reach out to
support@ente.io and we will help you out.
diff --git a/docs/docs/photos/faq/subscription.md b/docs/docs/photos/faq/subscription.md
index 475fbc524b..aa799127bc 100644
--- a/docs/docs/photos/faq/subscription.md
+++ b/docs/docs/photos/faq/subscription.md
@@ -157,6 +157,21 @@ The same applies to monthly plans.
If you prefer to have this credit refunded to your original payment method,
please contact support@ente.io, and we'll assist you.
+## How can I update my payment method?
+
+You can view and manage your payment method by clicking on the green
+subscription card within the Ente app, and selecting the "Manage payment method"
+button.
+
+You will be able to see all of your previous invoices, with details regarding
+their payment status. In case of failed payments, you will also have an option
+to retry those charges.
+
+## How can I cancel my subscription?
+
+You can cancel your subscription by clicking on the green subscription card
+within the Ente app, and selecting the "Cancel subscription" button.
+
## Is there an x GB plan?
We have experimented quite a bit and have found it hard to design a single
diff --git a/docs/docs/photos/faq/video-streaming.md b/docs/docs/photos/faq/video-streaming.md
new file mode 100644
index 0000000000..59a34907f6
--- /dev/null
+++ b/docs/docs/photos/faq/video-streaming.md
@@ -0,0 +1,63 @@
+---
+title: Video streaming FAQ
+description:
+ Frequently asked questions about Ente's video streaming feature
+---
+
+# Video streaming
+
+> [!NOTE]
+>
+> Video streaming is available in beta on mobile apps starting v0.9.98.
+
+### How to enable video streaming?
+
+- Open Settings -> General -> Advanced
+- Switch on the toggle for `Video streaming`
+
+### What happens when I enable video streaming?
+
+Enabling video streaming will start processing videos captured in the last 30
+days, generating streams for each. Both local and remote videos will be
+processed, so this may consume bandwidth for downloading of remote files and
+uploading of the generated streams.
+
+### How can I view video streams?
+
+Settings -> Backup > Backup status will show details regarding the processing
+status for videos. Processed videos will have a green play button next to them.
+You can open these videos by tapping on them.
+
+Processed videos will show a `Play stream` button, clicking which will load and
+play the stream.
+
+Clicking on the `Info` icon within the original video will show details about
+the generated stream.
+
+### What is a stream?
+
+Stream is an encrypted HLS file with an `.m3u8` playlist that helps play a video
+with support for seeking **without** downloading the full file.
+
+Currently it converts videos into `720p` with `2mbps` bitrate in `H.264` format.
+The generated stream is single blob (encrypted with AES) while the playlist file
+(`.m3u8`) is another blob (encrypted using XChaCha20).
+
+We cannot read the contents, duration or the number of chunks within the
+generated stream.
+
+### Will streams consume space in my storage?
+
+While this feature is in beta, we will not count the storage consumed by your
+streams against your storage quota. This may change in the future. If it does,
+we will provide an option to opt-in to one of the following:
+1. Original videos only
+2. Compressed streams only
+3. Both
+
+### Something doesn't seem right, what to do?
+
+As video streaming is still in beta, some things might not work correctly.
+Please create a thread within the `#feedback` channel on
+[Discord](https://discord.com/channels/948937918347608085/1121126215995113552)
+or reach out to [support@ente.io](mailto:support@ente.io).
diff --git a/docs/docs/photos/features/background.md b/docs/docs/photos/features/background.md
index e64939fd6a..ffed413f74 100644
--- a/docs/docs/photos/features/background.md
+++ b/docs/docs/photos/features/background.md
@@ -43,6 +43,10 @@ need to disable this "Optimize battery usage" mode in the system settings for
Ente if you wish for Ente to automatically back up your photos in the
background.
+On Android versions 15 and later, if an app is in private space and the private
+space is locked, Android doesn’t allow the app to run any background processes.
+As a result, background sync will not work.
+
### Desktop
In addition to our mobile apps, the background sync also works on our desktop
diff --git a/docs/docs/photos/features/machine-learning.md b/docs/docs/photos/features/machine-learning.md
index 7e14bafa81..215c1d98a8 100644
--- a/docs/docs/photos/features/machine-learning.md
+++ b/docs/docs/photos/features/machine-learning.md
@@ -50,5 +50,5 @@ end-to-end encrypted security that we use for syncing your photos.
Note that the desktop app does not currently support modifying the face
groupings, that is only supported by the mobile app.
-For more information on how to use Machine Learning please check out
-[the FAQ](../faq/machine-learning).
+For more information on how to use Machine Learning for face recognition please
+check out [the FAQ](../faq/face-recognition).
diff --git a/docs/docs/photos/features/passkeys.md b/docs/docs/photos/features/passkeys.md
index 5f7329bed7..fcbfc5b180 100644
--- a/docs/docs/photos/features/passkeys.md
+++ b/docs/docs/photos/features/passkeys.md
@@ -59,3 +59,6 @@ then select the "Recover two-factor" option in the error message that gets
shown. This will take you to a place where you can enter your Ente recovery key
and login into your account. Now you can go to the _Passkey_ page to delete the
lost passkey and/or add a new one.
+
+If you have lost access to both your passkey and recovery key, please reach out
+to [support@ente.io](mailto:support@ente.io) for help.
diff --git a/docs/docs/photos/features/trash.md b/docs/docs/photos/features/trash.md
index f324b48e9c..84a685279b 100644
--- a/docs/docs/photos/features/trash.md
+++ b/docs/docs/photos/features/trash.md
@@ -10,3 +10,9 @@ automatically deleted from Trash after 30 days. You can manaully select photos
to permanently delete or completely empty the trash if you wish.
Items in trash are included in your used storage calculation.
+
+## Recovery
+
+If you have deleted items accidentally, you can recover them from Trash by
+selecting these items, and clicking the "Restore" button on the action bar that
+pops up.
diff --git a/docs/docs/photos/troubleshooting/sharing-logs.md b/docs/docs/photos/troubleshooting/sharing-logs.md
index cd9417fac3..4e2eb2d2d3 100644
--- a/docs/docs/photos/troubleshooting/sharing-logs.md
+++ b/docs/docs/photos/troubleshooting/sharing-logs.md
@@ -20,23 +20,25 @@ the logs just make the process a bit faster and easier.
- Select for the option to _Report a Bug_.
- Tap on _Report a bug_.
+## Desktop and Web
+
+- Open settings (click on the three horizontal lines button located at the top
+ left corner of the screen).
+- Click on the _Help_ option towards the bottom of settings.
+- Click on _View logs_. This will show you the location of the logs on your
+ system (desktop), or download them from the browser onto your computer (web).
+- Go back to settings.
+- Click on _Support_. This will open your email client where you can attach the
+ logs in the email and describe the issue.
+
## Desktop
-- Click on _Help_ menu at the top of your screen, and select the _View logs_
- option.
-- Open settings (click on the three horizontal lines button located at the top
- left corner of the screen).
-- Click on _Support_. This will open your email client where you can attach the
- logs in the email and describe the issue.
+On the desktop app, you can also directly view the logs on your computer at the
+following locations:
-## Web
-
-- Open settings (click on the three horizontal lines button located at the top
- left corner of the screen).
-- Click on _Debug Logs_ towards the bottom of settings.
-- Click on _Download logs_
-- Click on _Support_. This will open your email client where you can attach the
- logs in the email and describe the issue.
+- macOS: `~/Library/Logs/ente/ente.log`
+- Linux: `~/.config/ente/logs/ente.log`
+- Windows: `%USERPROFILE%\AppData\Roaming\ente\logs\ente.log`
## Send email manually
diff --git a/docs/docs/self-hosting/guides/Tailscale.md b/docs/docs/self-hosting/guides/Tailscale.md
new file mode 100644
index 0000000000..1f0a7593ed
--- /dev/null
+++ b/docs/docs/self-hosting/guides/Tailscale.md
@@ -0,0 +1,286 @@
+---
+title: Self Hosting with Tailscale (Community)
+description: Guides for self-hosting Ente Photos and/or Ente Auth with Tailscale
+---
+# Guide
+
+This guide aims to achieve self-hosting Ente photos or Ente-Auth with tailscale (TSDPROXY) without exposing any port OR if someone is behind CGNAT and cannot open any port on the internet but want to run their own selfhosted service for themselves, friends and family only.
+
+Before getting start keep the following NOTE in mind.
+
+> [!NOTE]
+> If someone is behind double or triple CGNAT; must install tailscale system wide by running `curl -fsSL https://tailscale.com/install.sh | sh` in your linux terminal and `sudo tailscale up` otherwise dns resolver will fail and uploading will not work. This is not necessary for those who are not behing CGNAT.
+> This guide also work on docker rootless and normal.
+
+> [!CAUTION]
+Remember that current docker update 28.0.0 has some bug and cannot connect to external network. Make sure to install docker-ce 27.5.0, docker-ce-rootless-extras 27.5.0 and docker-ce-cli 27.5.0. Hopefully docker 28.1.0 will resolve this issue in next week. Refrence links are [Moby Github Repo Issues 49511](https://github.com/moby/moby/issues/49511) and [Moby Github Repo Issues 49519](https://github.com/moby/moby/issues/49519)
+
+> [!IMPORTANT]
+> For Docker rootless, the user must have local permissions for all directories required by the Ente-photos self-hosted server. This can be achieved by running `sudo chown -R 1000:1000 /home/ubuntu/docker/ente`. In the Linux terminal, you can check the UID with `id -u` or simply `id`. The first user typically has UID 1000.
+> To allow listening and pinging on any port without root privileges, create a file called `/etc/sysctl.d/99-rootless.conf` with the following content:
+> ```
+> net.ipv4.ip_unprivileged_port_start=0
+> net.ipv4.ping_group_range = 0 2147483647
+> ```
+> than run `sudo sysctl --system`.
+> Create `~/.config/systemd/user/docker.service.d/override.conf` with the following content:
+> ```
+> [Service]
+> Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_NET=slirp4netns"
+> Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=slirp4netns"
+> ```
+> and Restart the docker daemon
+> `systemctl --user restart docker`
+> Instead of `--volume /var/run/docker.sock:/var/run/docker.sock` in TSDPROXY compose.yaml, use `--volume $XDG_RUNTIME_DIR/docker.sock:/var/run/docker.sock`
+
+## GETTING START WITH SETUP ##
+First of all create a directory `sudo mkdir -p /home/ubuntu/docker/tsdproxy/config` than `cd docker/tsdproxy` and create compose.yaml file by running `sudo nano compose.yaml`. Populate it with the following:
+```
+services:
+ tsdproxy:
+ image: almeidapaulopt/tsdproxy
+ container_name: tsdproxy
+ restart: unless-stopped
+ environment:
+ TZ: Asia/Singapur # change me
+ volumes:
+ - $XDG_RUNTIME_DIR/docker.sock:/var/run/docker.sock # for docker rootless otherwise /var/run/docker.sock:/var/run/docker.sock
+ - tsdproxy_data:/data
+ - /home/lee/docker/tsdproxy/config:/config
+ networks:
+ - proxy
+ labels: # giving the labels here will create tsdproxy instance in tailscale admin counsle and GUI can be accessable through tailscale if device is connected
+ - tsdproxy.enable=true
+ - tsdproxy.name=tsdproxy
+ - tsdproxy.ephemeral=false # this is optional but useful
+
+volumes:
+ tsdproxy_data:
+ name: tsdproxy_data
+
+networks:
+ proxy:
+ name: proxy
+```
+Now login into your tailscale account admin counsle > settings > keys > Generate authkey. Give any description and must select resuable, because the key get purged if not selected after rebooting machine. It is advisable to create **Tags** in **ACLs settings** `tag: tsdproxy` `tag: ente` `tag: minio` as well. This will create a tag nodes with no key expirory. One is safe to reboot restart docker or machine.
+> Copy the generated authkey as it is shown only once.
+Make tsdproxy.yaml file in `cd docker/tsdproxy/config` by running `sudo nano tsdproxy.yaml` and pupolate it with the following contant:
+```
+defaultproxyprovider: default
+docker:
+ local:
+ host: unix:///var/run/docker.sock
+ defaultproxyprovider: default
+files: {}
+tailscale:
+ providers:
+ default:
+ authkey: ""
+ authkeyfile: "/config/authkey"
+ controlurl: https://controlplane.tailscale.com
+ datadir: /data/
+http:
+ hostname: 0.0.0.0
+ port: 8080
+log:
+ level: info
+ json: false
+proxyaccesslog: true
+```
+In the same directory run `sudo nano authkey` and paste the authkey just copied earlier from tailscale admin counsel.
+> Here Tailscale (TSDPROXY) setup is complet in all respect. Just run `docker compose up -d`. Check your tailscale amdin counsel and you will see tsdproxy node up and running. Make sure that **HTTPS** is enabled in tailscale DNS settings.
+> You can visit the TSDPROXY web GUI by https://tsdproxy.xyz.ts.net. (xyz is change value for everyone)
+
+## ente Part ##
+First make the following necessary files/directories:
+```
+sudo mkdir -p /home/ubuntu/docker/ente/custom-logs
+sudo mkdir -p /home/ubuntu/docker/ente/data
+sudo mkdir -p /home/ubuntu/docker/ente/minio-data
+sudo mkdir -p /home/ubuntu/docker/ente/postgres-data
+sudo mkdir -p /home/ubuntu/docker/ente/scripts/compose
+```
+Than give user permission for each of the above directory. `sudo chown -R 1000:1000 /home/ubuntu/docker/ente/custom-logs` etc etc. Make sure not to skip `/home/ubuntu/docker/tsdproxy/config`
+
+`cd docker/ente/script/compose` and run `sudo nano credentials.yaml` than populate it with the following:
+```
+db:
+ host: postgres
+ port: 5432
+ name: ente_db
+ user: pguser # change me
+ password: pgpass #change me
+
+s3:
+ are_local_buckets: true
+ b2-eu-cen:
+ key: test # change me
+ secret: testtest # change me
+ endpoint: https://minio.xyz.ts.net
+ region: eu-central-2
+ bucket: b2-eu-cen
+ wasabi-eu-central-2-v3:
+ key: test # change me
+ secret: testtest # change me
+ endpoint: localhost:3200
+ region: eu-central-2
+ bucket: wasabi-eu-central-2-v3
+ compliance: false
+ scw-eu-fr-v3:
+ key: test # change me
+ secret: testtest # change me
+ endpoint: localhost:3200
+ region: eu-central-2
+ bucket: scw-eu-fr-v3
+```
+
+In the same directory run `sudo nano minio-provision.sh` and populate it with the following contant:
+```
+#!/bin/sh
+
+# Script used to prepare the minio instance that runs as part of the development
+# Docker compose cluster.
+
+while ! mc config host add h0 http://minio:3200 test testtest #(change me)
+do
+ echo "waiting for minio..."
+ sleep 0.5
+done
+
+cd /data
+
+mc mb -p b2-eu-cen
+mc mb -p wasabi-eu-central-2-v3
+mc mb -p scw-eu-fr-v3
+```
+
+Now `cd docker/ente` and run `sudo nano docker-compose.yaml` and populate it with the following:
+```
+services:
+ museum:
+ image: ghcr.io/ente-io/server
+ ports:
+ - 9080:8080 # 9080 because tsdproxy is running on 8080:8080
+ # - 2112:2112 # Prometheus metrics
+ depends_on:
+ postgres:
+ condition: service_healthy
+ environment:
+ # Pass-in the config to connect to the DB and MinIO
+ ENTE_CREDENTIALS_FILE: /credentials.yaml
+ # ENTE_CLI_SECRETS_PATH: /cli-data/secret.txt
+ # ENTE_CLI_CONFIG_PATH: /cli-data/
+ volumes:
+ - /home/ubuntu/docker/ente/custom-logs:/var/logs
+ - /home/ubuntu/docker/ente/museum.yaml:/museum.yaml:ro
+ - /home/ubuntu/docker/ente/scripts/compose/credentials.yaml:/credentials.yaml:ro
+ #- /home/ubuntu/docker/ente/cli-data:/cli-data
+ #- /home/ubuntu/docker/ente/exports/ente-photos:/exports
+ - /home/ubuntu/docker/ente/data:/data:ro
+ networks:
+ - ente
+ - proxy
+ labels:
+ tsdproxy.enable: "true"
+ tsdproxy.name: "ente"
+
+# # Resolve "localhost:3200" in the museum container to the minio container.
+ socat:
+ image: alpine/socat
+ network_mode: service:museum
+ depends_on:
+ - museum
+ command: "TCP-LISTEN:3200,fork,reuseaddr TCP:minio:3200"
+
+ postgres:
+ image: postgres:15
+ ports:
+ - 5432:5432
+ environment:
+ POSTGRES_USER: pguser # change me
+ POSTGRES_PASSWORD: pgpass # change me
+ POSTGRES_DB: ente_db
+ # Wait for postgres to be accept connections before starting museum.
+ healthcheck:
+ test:
+ [
+ "CMD",
+ "pg_isready",
+ "-q",
+ "-d",
+ "ente_db",
+ "-U",
+ "pguser" # change it accouding to the POSTGRES_USER: pguser
+ ]
+ start_period: 40s
+ start_interval: 1s
+ volumes:
+ - /home/ubuntu/docker/ente/postgres-data:/var/lib/postgresql/data
+ networks:
+ - ente
+
+ minio:
+ image: minio/minio
+ # Use different ports than the minio defaults to avoid conflicting
+ # with the ports used by Prometheus.
+ ports:
+ - 3200:3200 # API
+ - 3201:3201 # Console
+ environment:
+ MINIO_ROOT_USER: test # change me
+ MINIO_ROOT_PASSWORD: testtest # change me
+ MINIO_SERVER_URL: https://minio.xyz.ts.net
+ command: server /data --address ":3200" --console-address ":3201"
+ volumes:
+ - /home/ubuntu/docker/ente/minio-data:/data
+ networks:
+ - ente
+ - proxy
+ labels:
+ tsdproxy.enable: "true"
+ tsdproxy.name: "minio"
+
+ minio-provision:
+ image: minio/mc
+ depends_on:
+ - minio
+ volumes:
+ - /home/ubuntu/docker/ente/scripts/compose/minio-provision.sh:/provision.sh:ro
+ - /home/ubuntu/docker/ente/minio-data:/data
+ networks:
+ - ente
+ entrypoint: sh /provision.sh
+
+
+networks:
+ ente:
+ name: ente
+
+ proxy:
+ external: true
+```
+
+> Thats it. Run `docker compose up -d`. Wait till every container become healthy. Open web browser. Make sure tailscale is installed on the machine. Visit https://ente.xyz.ts.net/ping. It will pong. All good if you see it. First time it will take minute or two to get SSL cert. Downnload Desktop or mobile app. Tap 7 time on the screen, which will prompt developer mode. Add https://ente.xyz.ts.net. Add new user. When asked for OTP. Just go to linux terminal and run `docker logs ente-museum-1`. Search for userauth. Feed the six digit and Done.
+
+> For getting 100TB (limitless) storage. Just Install ente-cli for windows. Extract it and add folder. Name it **export**. Add config.yaml file along and populate it with the following:
+```
+endpoint:
+ api: "https://ente.xyz.ts.net"
+ accounts: "http://localhost:3001"
+
+log: false
+```
+Right-Click in the directory where you have extracted ente-cli. Select `open in terminal`. Run
+```
+.\ente.exe account bob # change bob to yours
+```
+Hit Enter twice.
+For export directory, just write export. As already created **export** folder earlier.
+**Write email. The one which is already used befor when creating ente account in ente desktop app.**
+Type the same Password used before for the account.Run
+```
+.\ente.ext account list
+```
+This will list all account details. Copy Acount ID.
+> Navigate to museum.yaml file. `cd docker/ente`. Run `sudo nano museum.yaml` and add the account ID under Admins. Delete any previous entries.
+Restart ente-museum-1 container from linux terminal. Run `docker restart ente-museum-1`. All well, now you will have 100TB storage. Repeat if for any other accounts you want to give unlimited storage access.
diff --git a/docs/docs/self-hosting/guides/configuring-s3.md b/docs/docs/self-hosting/guides/configuring-s3.md
index 8da933d686..dcc209e8b1 100644
--- a/docs/docs/self-hosting/guides/configuring-s3.md
+++ b/docs/docs/self-hosting/guides/configuring-s3.md
@@ -54,20 +54,30 @@ The same principle applies if you're deploying to your custom domain.
## Replication
-If you're wondering why there are 3 buckets on MinIO UI - that's because our
-production instance uses these to perform [replication](https://ente.io/reliability/).
-
-In a self hosted Ente Instance replication is turned off by default.
-When replication is turned off, only the first bucket (`b2-eu-cen`) is used,
-and you can ignore the other two. Use the `s3.hot_storage.primary` option
-if you'd like to set one of the other predefined buckets as the primary bucket.
-
> [!IMPORTANT]
> As of now, Replication works only if all the 3 storage type
> needs are fulfilled (1 Hot, 1 Cold and 1 Glacier Storage).
>
> [Reference](https://github.com/ente-io/ente/discussions/3167#discussioncomment-10585970)
+If you're wondering why there are 3 buckets on MinIO UI - that's because our
+production instance uses these to perform [replication](https://ente.io/reliability/).
+
+If you're also wondering about why the bucket names are specifically what they are,
+it's because that is exactly what we are using on our production instance.
+We use `b2-eu-cen` as hot, `wasabi-eu-central-2-v3` as cold (also the secondary hot)
+and `scw-eu-fr-v3` as glacier storage. As of now, all of this is hardcoded.
+Hence, the same hardcoded configuration is applied when you self host Ente.
+
+In a Self hosted Ente Instance replication is turned off by default.
+When replication is turned off, only the first bucket (`b2-eu-cen`) is used,
+and the other two are ignored. Only the names here are specifically fixed, but
+in the configuration body you can put any other keys. It does not have any relation
+with `b2`, `wasabi` or even `scaleway`.
+
+Use the `s3.hot_storage.primary` option if you'd like to set one of the other
+predefined buckets as the primary bucket.
+
## SSL Configuration
> [!NOTE]
diff --git a/infra/services/grafana/README.md b/infra/services/grafana/README.md
new file mode 100644
index 0000000000..5c9ef8ef96
--- /dev/null
+++ b/infra/services/grafana/README.md
@@ -0,0 +1,37 @@
+# Grafana
+
+Grafana data is stored in a persistent Docker volume named `grafana-storage`. To
+create a backup of this, use
+
+```sh
+docker run --rm \
+ --mount source=grafana-storage,target=/g \
+ -v $(pwd):/backup \
+ busybox \
+ tar -cvzf /backup/grafana-storage.backup.tar.gz /g
+```
+
+## Installation
+
+Restore the volume:
+
+```sh
+docker run --rm \
+ --mount source=grafana-storage,target=/g \
+ -v $(pwd):/backup \
+ busybox \
+ tar -xvzf /backup/grafana-storage.backup.tar.gz -C /
+```
+
+Add the Grafana nginx config
+
+```sh
+sudo mv grafana.nginx.conf /root/nginx/conf.d
+```
+
+and reload the nginx service before starting Grafana for the first time.
+
+```sh
+sudo systemctl reload nginx
+sudo systemctl start grafana
+```
diff --git a/infra/services/grafana/grafana.nginx.conf b/infra/services/grafana/grafana.nginx.conf
new file mode 100644
index 0000000000..046f42153c
--- /dev/null
+++ b/infra/services/grafana/grafana.nginx.conf
@@ -0,0 +1,24 @@
+# Needed for web sockets
+map $http_upgrade $connection_upgrade {
+ default upgrade;
+ '' close;
+}
+
+server {
+ listen 443 ssl http2;
+ listen [::]:443 ssl http2;
+ ssl_certificate /etc/ssl/certs/cert.pem;
+ ssl_certificate_key /etc/ssl/private/key.pem;
+
+ server_name grafana.ente.io;
+
+ location / {
+ proxy_pass http://host.docker.internal:3001;
+ 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;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection $connection_upgrade;
+ }
+}
diff --git a/infra/services/grafana/grafana.service b/infra/services/grafana/grafana.service
new file mode 100644
index 0000000000..22003a5bc5
--- /dev/null
+++ b/infra/services/grafana/grafana.service
@@ -0,0 +1,14 @@
+[Unit]
+Documentation=https://grafana.com/docs/grafana/latest/setup-grafana/configure-docker/
+Requires=docker.service
+After=docker.service
+
+[Service]
+ExecStartPre=docker pull grafana/grafana-oss
+ExecStartPre=-docker stop grafana
+ExecStartPre=-docker rm grafana
+ExecStart=docker run --name grafana \
+ -p 3001:3001 \
+ -v grafana-storage:/var/lib/grafana \
+ -e "GF_SERVER_HTTP_PORT=3001" \
+ grafana/grafana-oss
diff --git a/mobile/.metadata b/mobile/.metadata
index 01d2dcb9ad..98bea013b5 100644
--- a/mobile/.metadata
+++ b/mobile/.metadata
@@ -4,7 +4,7 @@
# This file should be version controlled and should not be manually edited.
version:
- revision: 0b8abb4724aa590dd0f429683339b1e045a1594d
- channel: stable
+ revision: "2663184aa79047d0a33a14a3b607954f8fdd8730"
+ channel: "stable"
project_type: app
diff --git a/mobile/android/.gitignore b/mobile/android/.gitignore
index bc2100d8f7..55afd919c6 100644
--- a/mobile/android/.gitignore
+++ b/mobile/android/.gitignore
@@ -5,3 +5,9 @@ gradle-wrapper.jar
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
+
+# Remember to never publicly share your keystore.
+# See https://flutter.dev/to/reference-keystore
+key.properties
+**/*.keystore
+**/*.jks
diff --git a/mobile/android/app/build.gradle b/mobile/android/app/build.gradle
index ad09d00b94..98d792b9f3 100644
--- a/mobile/android/app/build.gradle
+++ b/mobile/android/app/build.gradle
@@ -28,13 +28,23 @@ if (keystorePropertiesFile.exists()) {
}
android {
- compileSdkVersion 34
- ndkVersion "26.0.10792818"
+ namespace = "io.ente.photos"
+ compileSdk = 35
+ ndkVersion = flutter.ndkVersion
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = JavaVersion.VERSION_1_8
+ }
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
-
+
lintOptions {
disable 'InvalidPackage'
warningsAsErrors false
@@ -42,11 +52,11 @@ android {
}
defaultConfig {
- applicationId "io.ente.photos"
- minSdkVersion 26
- targetSdkVersion 34
- versionCode flutterVersionCode.toInteger()
- versionName flutterVersionName
+ applicationId = "io.ente.photos"
+ minSdk = 26
+ targetSdk = flutter.targetSdkVersion
+ versionCode = flutter.versionCode
+ versionName = flutter.versionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
consumerProguardFiles 'proguard-rules.pro'
@@ -115,14 +125,14 @@ rootProject.allprojects {
if (details.requested.group == 'com.github.bumptech.glide'
&& details.requested.name.contains('glide')) {
details.useVersion "4.15.1"
- }
}
+ }
}
}
}
flutter {
- source '../..'
+ source = "../.."
}
dependencies {
diff --git a/mobile/android/app/proguard-rules.pro b/mobile/android/app/proguard-rules.pro
index f35c179f30..797953c7f9 100644
--- a/mobile/android/app/proguard-rules.pro
+++ b/mobile/android/app/proguard-rules.pro
@@ -2,3 +2,6 @@
# To ensure that stack traces is unambiguous
# https://developer.android.com/studio/build/shrink-code#decode-stack-trace
-keepattributes LineNumberTable,SourceFile
+
+-keep class org.chromium.net.** { *; }
+-keep class org.xmlpull.v1.** { *; }
\ No newline at end of file
diff --git a/mobile/android/build.gradle b/mobile/android/build.gradle
index b8ba53408f..9a142ee48d 100644
--- a/mobile/android/build.gradle
+++ b/mobile/android/build.gradle
@@ -12,18 +12,15 @@ allprojects {
// url "${project(':background_fetch').projectDir}/libs"
// }
}
- ext {
- compileSdkVersion = 34
- targetSdkVersion = 34
- appCompatVersion = "1.7.0"
- }
}
-rootProject.buildDir = '../build'
+rootProject.buildDir = "../build"
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
- project.evaluationDependsOn(':app')
+}
+subprojects {
+ project.evaluationDependsOn(":app")
}
tasks.register("clean", Delete) {
diff --git a/mobile/android/gradle.properties b/mobile/android/gradle.properties
index ed508580fa..fce68493b1 100644
--- a/mobile/android/gradle.properties
+++ b/mobile/android/gradle.properties
@@ -1,3 +1,3 @@
org.gradle.jvmargs=-Xmx4608m
android.useAndroidX=true
-android.enableJetifier=true
+android.enableJetifier=true
\ No newline at end of file
diff --git a/mobile/android/gradle/wrapper/gradle-wrapper.properties b/mobile/android/gradle/wrapper/gradle-wrapper.properties
index a7e3608ded..7bb2df6ba6 100644
--- a/mobile/android/gradle/wrapper/gradle-wrapper.properties
+++ b/mobile/android/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,5 @@
-#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
-distributionSha256Sum=a8da5b02437a60819cad23e10fc7e9cf32bcb57029d9cb277e26eeff76ce014b
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
diff --git a/mobile/android/settings.gradle b/mobile/android/settings.gradle
index 0fff0ecaf2..b9e43bd376 100644
--- a/mobile/android/settings.gradle
+++ b/mobile/android/settings.gradle
@@ -18,8 +18,8 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
- id "com.android.application" version "7.1.2" apply false
- id "org.jetbrains.kotlin.android" version "1.8.21" apply false
+ id "com.android.application" version "8.1.0" apply false
+ id "org.jetbrains.kotlin.android" version "1.8.22" apply false
}
-include ":app"
\ No newline at end of file
+include ":app"
diff --git a/mobile/fastlane/metadata/android/tr/full_description.txt b/mobile/fastlane/metadata/android/tr/full_description.txt
index 2362583f60..a978db8478 100644
--- a/mobile/fastlane/metadata/android/tr/full_description.txt
+++ b/mobile/fastlane/metadata/android/tr/full_description.txt
@@ -1,6 +1,6 @@
-ente, fotoğraflarınızı ve videolarınızı yedeklemek ve paylaşmak için basit bir uygulamadır.
+ente, fotoğraflarınızı ve videolarınızı yedekleyip paylaşmanızı sağlayan kullanimi kolay bir uygulamadır.
-Google Fotoğraflar'a gizlilik dostu bir alternatif arıyorsanız doğru yere geldiniz. Ente ile uçtan uca şifrelenmiş olarak (e2ee) saklanırlar. Bu, onları yalnızca sizin görebileceğiniz anlamına gelir.
+Anılarınızı saklamak için gizlilik dostu bir alternatif arıyorsanız, doğru yere geldiniz. Ente ile uçtan uca şifrelenmiş olarak (e2ee) saklanırlar. Bu, onları yalnızca sizin görebileceğiniz anlamına gelir.
Android, iOS, web ve masaüstünde açık kaynaklı uygulamalarımız var ve fotoğraflarınız bunların tümü arasında uçtan uca şifrelenmiş (e2ee) şekilde sorunsuz bir şekilde senkronize edilecek.
diff --git a/mobile/fastlane/metadata/ios/tr/name.txt b/mobile/fastlane/metadata/ios/tr/name.txt
index 04e5a9c011..06a3a6ebe6 100644
--- a/mobile/fastlane/metadata/ios/tr/name.txt
+++ b/mobile/fastlane/metadata/ios/tr/name.txt
@@ -1 +1 @@
-ente fotoğraf uygulaması
+Ente Fotoğraflar
diff --git a/mobile/fastlane/metadata/ios/tr/subtitle.txt b/mobile/fastlane/metadata/ios/tr/subtitle.txt
index cbc438b5f0..e0b41db095 100644
--- a/mobile/fastlane/metadata/ios/tr/subtitle.txt
+++ b/mobile/fastlane/metadata/ios/tr/subtitle.txt
@@ -1 +1 @@
-Şifrelenmiş depolama sistemi
+Ente - şifrelenmiş depolama sistemi
diff --git a/mobile/ios/Podfile.lock b/mobile/ios/Podfile.lock
index 4a76000080..f7c69935af 100644
--- a/mobile/ios/Podfile.lock
+++ b/mobile/ios/Podfile.lock
@@ -5,6 +5,8 @@ PODS:
- Flutter
- connectivity_plus (0.0.1):
- Flutter
+ - cupertino_http (0.0.1):
+ - Flutter
- FlutterMacOS
- dart_ui_isolate (0.0.1):
- Flutter
@@ -19,31 +21,31 @@ PODS:
- Flutter
- file_saver (0.0.1):
- Flutter
- - Firebase/CoreOnly (11.2.0):
- - FirebaseCore (= 11.2.0)
- - Firebase/Messaging (11.2.0):
+ - Firebase/CoreOnly (11.8.0):
+ - FirebaseCore (~> 11.8.0)
+ - Firebase/Messaging (11.8.0):
- Firebase/CoreOnly
- - FirebaseMessaging (~> 11.2.0)
- - firebase_core (3.6.0):
- - Firebase/CoreOnly (= 11.2.0)
+ - FirebaseMessaging (~> 11.8.0)
+ - firebase_core (3.12.0):
+ - Firebase/CoreOnly (= 11.8.0)
- Flutter
- - firebase_messaging (15.1.3):
- - Firebase/Messaging (= 11.2.0)
+ - firebase_messaging (15.2.3):
+ - Firebase/Messaging (= 11.8.0)
- firebase_core
- Flutter
- - FirebaseCore (11.2.0):
- - FirebaseCoreInternal (~> 11.0)
+ - FirebaseCore (11.8.1):
+ - FirebaseCoreInternal (~> 11.8.0)
- GoogleUtilities/Environment (~> 8.0)
- GoogleUtilities/Logger (~> 8.0)
- - FirebaseCoreInternal (11.6.0):
+ - FirebaseCoreInternal (11.8.0):
- "GoogleUtilities/NSData+zlib (~> 8.0)"
- - FirebaseInstallations (11.4.0):
- - FirebaseCore (~> 11.0)
+ - FirebaseInstallations (11.8.0):
+ - FirebaseCore (~> 11.8.0)
- GoogleUtilities/Environment (~> 8.0)
- GoogleUtilities/UserDefaults (~> 8.0)
- PromisesObjC (~> 2.4)
- - FirebaseMessaging (11.2.0):
- - FirebaseCore (~> 11.0)
+ - FirebaseMessaging (11.8.0):
+ - FirebaseCore (~> 11.8.0)
- FirebaseInstallations (~> 11.0)
- GoogleDataTransport (~> 10.0)
- GoogleUtilities/AppDelegateSwizzler (~> 8.0)
@@ -54,7 +56,7 @@ PODS:
- Flutter (1.0.0)
- flutter_email_sender (0.0.1):
- Flutter
- - flutter_image_compress (1.0.0):
+ - flutter_image_compress_common (1.0.0):
- Flutter
- Mantle
- SDWebImage
@@ -68,7 +70,7 @@ PODS:
- OrderedSet (~> 6.0.3)
- flutter_local_notifications (0.0.1):
- Flutter
- - flutter_native_splash (0.0.1):
+ - flutter_native_splash (2.4.3):
- Flutter
- flutter_secure_storage (6.0.0):
- Flutter
@@ -76,7 +78,6 @@ PODS:
- Flutter
- fluttertoast (0.0.2):
- Flutter
- - Toast
- GoogleDataTransport (10.1.0):
- nanopb (~> 3.30910.0)
- PromisesObjC (~> 2.4)
@@ -115,17 +116,17 @@ PODS:
- FlutterMacOS
- integration_test (0.0.1):
- Flutter
- - libwebp (1.3.2):
- - libwebp/demux (= 1.3.2)
- - libwebp/mux (= 1.3.2)
- - libwebp/sharpyuv (= 1.3.2)
- - libwebp/webp (= 1.3.2)
- - libwebp/demux (1.3.2):
+ - libwebp (1.5.0):
+ - libwebp/demux (= 1.5.0)
+ - libwebp/mux (= 1.5.0)
+ - libwebp/sharpyuv (= 1.5.0)
+ - libwebp/webp (= 1.5.0)
+ - libwebp/demux (1.5.0):
- libwebp/webp
- - libwebp/mux (1.3.2):
+ - libwebp/mux (1.5.0):
- libwebp/demux
- - libwebp/sharpyuv (1.3.2)
- - libwebp/webp (1.3.2):
+ - libwebp/sharpyuv (1.5.0)
+ - libwebp/webp (1.5.0):
- libwebp/sharpyuv
- local_auth_darwin (0.0.1):
- Flutter
@@ -141,8 +142,6 @@ PODS:
- Flutter
- media_kit_libs_ios_video (1.0.4):
- Flutter
- - media_kit_native_event_loop (1.0.0):
- - Flutter
- media_kit_video (0.0.1):
- Flutter
- motion_sensors (0.0.1):
@@ -158,6 +157,8 @@ PODS:
- nanopb/encode (3.30910.0)
- native_video_player (1.0.0):
- Flutter
+ - objective_c (0.0.1):
+ - Flutter
- onnxruntime (0.0.1):
- Flutter
- onnxruntime-objc (= 1.18.0)
@@ -182,21 +183,19 @@ PODS:
- privacy_screen (0.0.1):
- Flutter
- PromisesObjC (2.4.0)
- - receive_sharing_intent (1.8.0):
+ - receive_sharing_intent (1.8.1):
- Flutter
- - screen_brightness_ios (0.1.0):
- - Flutter
- - SDWebImage (5.20.0):
- - SDWebImage/Core (= 5.20.0)
- - SDWebImage/Core (5.20.0)
+ - SDWebImage (5.21.0):
+ - SDWebImage/Core (= 5.21.0)
+ - SDWebImage/Core (5.21.0)
- SDWebImageWebPCoder (0.14.6):
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.17)
- - Sentry/HybridSDK (8.36.0)
- - sentry_flutter (8.9.0):
+ - Sentry/HybridSDK (8.44.0)
+ - sentry_flutter (8.13.2):
- Flutter
- FlutterMacOS
- - Sentry/HybridSDK (= 8.36.0)
+ - Sentry/HybridSDK (= 8.44.0)
- share_plus (0.0.1):
- Flutter
- shared_preferences_foundation (0.0.1):
@@ -205,28 +204,28 @@ PODS:
- sqflite_darwin (0.0.4):
- Flutter
- FlutterMacOS
- - "sqlite3 (3.46.1+1)":
- - "sqlite3/common (= 3.46.1+1)"
- - "sqlite3/common (3.46.1+1)"
- - "sqlite3/dbstatvtab (3.46.1+1)":
+ - sqlite3 (3.49.1):
+ - sqlite3/common (= 3.49.1)
+ - sqlite3/common (3.49.1)
+ - sqlite3/dbstatvtab (3.49.1):
- sqlite3/common
- - "sqlite3/fts5 (3.46.1+1)":
+ - sqlite3/fts5 (3.49.1):
- sqlite3/common
- - "sqlite3/perf-threadsafe (3.46.1+1)":
+ - sqlite3/perf-threadsafe (3.49.1):
- sqlite3/common
- - "sqlite3/rtree (3.46.1+1)":
+ - sqlite3/rtree (3.49.1):
- sqlite3/common
- sqlite3_flutter_libs (0.0.1):
- Flutter
- - "sqlite3 (~> 3.46.0+1)"
+ - FlutterMacOS
+ - sqlite3 (~> 3.49.0)
- sqlite3/dbstatvtab
- sqlite3/fts5
- sqlite3/perf-threadsafe
- sqlite3/rtree
- system_info_plus (0.0.1):
- Flutter
- - Toast (4.1.1)
- - ua_client_hints (1.4.0):
+ - ua_client_hints (1.4.1):
- Flutter
- uni_links (0.0.1):
- Flutter
@@ -246,7 +245,8 @@ PODS:
DEPENDENCIES:
- background_fetch (from `.symlinks/plugins/background_fetch/ios`)
- battery_info (from `.symlinks/plugins/battery_info/ios`)
- - connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`)
+ - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
+ - cupertino_http (from `.symlinks/plugins/cupertino_http/darwin`)
- dart_ui_isolate (from `.symlinks/plugins/dart_ui_isolate/ios`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- ffmpeg_kit_flutter_full_gpl (from `.symlinks/plugins/ffmpeg_kit_flutter_full_gpl/ios`)
@@ -255,7 +255,7 @@ DEPENDENCIES:
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
- Flutter (from `Flutter`)
- flutter_email_sender (from `.symlinks/plugins/flutter_email_sender/ios`)
- - flutter_image_compress (from `.symlinks/plugins/flutter_image_compress/ios`)
+ - flutter_image_compress_common (from `.symlinks/plugins/flutter_image_compress_common/ios`)
- flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`)
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
@@ -272,12 +272,12 @@ DEPENDENCIES:
- maps_launcher (from `.symlinks/plugins/maps_launcher/ios`)
- media_extension (from `.symlinks/plugins/media_extension/ios`)
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
- - media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
- motion_sensors (from `.symlinks/plugins/motion_sensors/ios`)
- motionphoto (from `.symlinks/plugins/motionphoto/ios`)
- move_to_background (from `.symlinks/plugins/move_to_background/ios`)
- native_video_player (from `.symlinks/plugins/native_video_player/ios`)
+ - objective_c (from `.symlinks/plugins/objective_c/ios`)
- onnxruntime (from `.symlinks/plugins/onnxruntime/ios`)
- open_mail_app (from `.symlinks/plugins/open_mail_app/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
@@ -286,12 +286,11 @@ DEPENDENCIES:
- photo_manager (from `.symlinks/plugins/photo_manager/ios`)
- privacy_screen (from `.symlinks/plugins/privacy_screen/ios`)
- receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
- - screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`)
- 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`)
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
- - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`)
+ - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/darwin`)
- system_info_plus (from `.symlinks/plugins/system_info_plus/ios`)
- ua_client_hints (from `.symlinks/plugins/ua_client_hints/ios`)
- uni_links (from `.symlinks/plugins/uni_links/ios`)
@@ -322,7 +321,6 @@ SPEC REPOS:
- SDWebImageWebPCoder
- Sentry
- sqlite3
- - Toast
EXTERNAL SOURCES:
background_fetch:
@@ -330,7 +328,9 @@ EXTERNAL SOURCES:
battery_info:
:path: ".symlinks/plugins/battery_info/ios"
connectivity_plus:
- :path: ".symlinks/plugins/connectivity_plus/darwin"
+ :path: ".symlinks/plugins/connectivity_plus/ios"
+ cupertino_http:
+ :path: ".symlinks/plugins/cupertino_http/darwin"
dart_ui_isolate:
:path: ".symlinks/plugins/dart_ui_isolate/ios"
device_info_plus:
@@ -347,8 +347,8 @@ EXTERNAL SOURCES:
:path: Flutter
flutter_email_sender:
:path: ".symlinks/plugins/flutter_email_sender/ios"
- flutter_image_compress:
- :path: ".symlinks/plugins/flutter_image_compress/ios"
+ flutter_image_compress_common:
+ :path: ".symlinks/plugins/flutter_image_compress_common/ios"
flutter_inappwebview_ios:
:path: ".symlinks/plugins/flutter_inappwebview_ios/ios"
flutter_local_notifications:
@@ -381,8 +381,6 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/media_extension/ios"
media_kit_libs_ios_video:
:path: ".symlinks/plugins/media_kit_libs_ios_video/ios"
- media_kit_native_event_loop:
- :path: ".symlinks/plugins/media_kit_native_event_loop/ios"
media_kit_video:
:path: ".symlinks/plugins/media_kit_video/ios"
motion_sensors:
@@ -393,6 +391,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/move_to_background/ios"
native_video_player:
:path: ".symlinks/plugins/native_video_player/ios"
+ objective_c:
+ :path: ".symlinks/plugins/objective_c/ios"
onnxruntime:
:path: ".symlinks/plugins/onnxruntime/ios"
open_mail_app:
@@ -409,8 +409,6 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/privacy_screen/ios"
receive_sharing_intent:
:path: ".symlinks/plugins/receive_sharing_intent/ios"
- screen_brightness_ios:
- :path: ".symlinks/plugins/screen_brightness_ios/ios"
sentry_flutter:
:path: ".symlinks/plugins/sentry_flutter/ios"
share_plus:
@@ -420,7 +418,7 @@ EXTERNAL SOURCES:
sqflite_darwin:
:path: ".symlinks/plugins/sqflite_darwin/darwin"
sqlite3_flutter_libs:
- :path: ".symlinks/plugins/sqlite3_flutter_libs/ios"
+ :path: ".symlinks/plugins/sqlite3_flutter_libs/darwin"
system_info_plus:
:path: ".symlinks/plugins/system_info_plus/ios"
ua_client_hints:
@@ -439,82 +437,81 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/wakelock_plus/ios"
SPEC CHECKSUMS:
- background_fetch: 39f11371c0dce04b001c4bfd5e782bcccb0a85e2
- battery_info: 09f5c9ee65394f2291c8c6227bedff345b8a730c
- connectivity_plus: ddd7f30999e1faaef5967c23d5b6d503d10434db
- dart_ui_isolate: d5bcda83ca4b04f129d70eb90110b7a567aece14
- device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
+ background_fetch: 94b36ee293e82972852dba8ede1fbcd3bd3d9d57
+ battery_info: 83f3aae7be2fccefab1d2bf06b8aa96f11c8bcdd
+ connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
+ cupertino_http: 94ac07f5ff090b8effa6c5e2c47871d48ab7c86c
+ dart_ui_isolate: 46f6714abe6891313267153ef6f9748d8ecfcab1
+ device_info_plus: 335f3ce08d2e174b9fdc3db3db0f4e3b1f66bd89
ffmpeg-kit-ios-full-gpl: 80adc341962e55ef709e36baa8ed9a70cf4ea62b
- ffmpeg_kit_flutter_full_gpl: 8d15c14c0c3aba616fac04fe44b3d27d02e3c330
- file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808
- Firebase: 98e6bf5278170668a7983e12971a66b2cd57fc8c
- firebase_core: 2bedc3136ec7c7b8561c6123ed0239387b53f2af
- firebase_messaging: 15d114e1a41fc31e4fbabcd48d765a19eec94a38
- FirebaseCore: a282032ae9295c795714ded2ec9c522fc237f8da
- FirebaseCoreInternal: d98ab91e2d80a56d7b246856a8885443b302c0c2
- FirebaseInstallations: 6ef4a1c7eb2a61ee1f74727d7f6ce2e72acf1414
- FirebaseMessaging: c9ec7b90c399c7a6100297e9d16f8a27fc7f7152
+ ffmpeg_kit_flutter_full_gpl: ce18b888487c05c46ed252cd2e7956812f2e3bd1
+ file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6
+ Firebase: d80354ed7f6df5f9aca55e9eb47cc4b634735eaf
+ firebase_core: 6cbed78b4f298ed103a9fd034e6dbc846320480f
+ firebase_messaging: 5e0adf2eb18b0ee59aa0c109314c091a0497ecac
+ FirebaseCore: 99fe0c4b44a39f37d99e6404e02009d2db5d718d
+ FirebaseCoreInternal: df24ce5af28864660ecbd13596fc8dd3a8c34629
+ FirebaseInstallations: 6c963bd2a86aca0481eef4f48f5a4df783ae5917
+ FirebaseMessaging: 487b634ccdf6f7b7ff180fdcb2a9935490f764e8
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
- flutter_email_sender: 02d7443217d8c41483223627972bfdc09f74276b
- flutter_image_compress: 5a5e9aee05b6553048b8df1c3bc456d0afaac433
- flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4
- flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086
- flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778
- flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
- flutter_sodium: c84426b4de738514b5b66cfdeb8a06634e72fe0b
- fluttertoast: e9a18c7be5413da53898f660530c56f35edfba9c
+ flutter_email_sender: aa1e9772696691d02cd91fea829856c11efb8e58
+ flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
+ flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
+ flutter_local_notifications: ad39620c743ea4c15127860f4b5641649a988100
+ flutter_native_splash: 6cad9122ea0fad137d23137dd14b937f3e90b145
+ flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13
+ flutter_sodium: 7e4621538491834eba53bd524547854bcbbd6987
+ fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
- home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57
- image_editor_common: d6f6644ae4a6de80481e89fe6d0a8c49e30b4b43
- image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
- in_app_purchase_storekit: 8c3b0b3eb1b0f04efbff401c3de6266d4258d433
- integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
- libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009
- local_auth_darwin: 66e40372f1c29f383a314c738c7446e2f7fdadc3
- local_auth_ios: 5046a18c018dd973247a0564496c8898dbb5adf9
+ home_widget: f169fc41fd807b4d46ab6615dc44d62adbf9f64f
+ image_editor_common: 3de87e7c4804f4ae24c8f8a998362b98c105cac1
+ image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
+ in_app_purchase_storekit: d1a48cb0f8b29dbf5f85f782f5dd79b21b90a5e6
+ integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
+ libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
+ local_auth_darwin: 553ce4f9b16d3fdfeafce9cf042e7c9f77c1c391
+ local_auth_ios: f7a1841beef3151d140a967c2e46f30637cdf451
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
- maps_launcher: 2e5b6a2d664ec6c27f82ffa81b74228d770ab203
- media_extension: 6d30dc1431ebaa63f43c397c37917b1a0a597a4c
- media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
- media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
- media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
- motion_sensors: 03f55b7c637a7e365a0b5f9697a449f9059d5d91
- motionphoto: d4a432b8c8f22fb3ad966258597c0103c9c5ff16
- move_to_background: 39a5b79b26d577b0372cbe8a8c55e7aa9fcd3a2d
+ maps_launcher: edf829809ba9e894d70e569bab11c16352dedb45
+ media_extension: 671e2567880d96c95c65c9a82ccceed8f2e309fd
+ media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854
+ media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
+ motion_sensors: 741e702c17467b9569a92165dda8d4d88c6167f1
+ motionphoto: 23e2aeb5c6380112f69468d71f970fa7438e5ed1
+ move_to_background: 7e3467dd2a1d1013e98c9c1cb93fd53cd7ef9d84
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
- native_video_player: d12af78a1a4a8cf09775a5177d5b392def6fd23c
- onnxruntime: e7c2ae44385191eaad5ae64c935a72debaddc997
+ native_video_player: e363dd14f6a498ad8a8f7e6486a0db046ad19f13
+ objective_c: 89e720c30d716b036faf9c9684022048eee1eee2
+ onnxruntime: f9b296392c96c42882be020a59dbeac6310d81b2
onnxruntime-c: a909204639a1f035f575127ac406f781ac797c9c
onnxruntime-objc: b6fab0f1787aa6f7190c2013f03037df4718bd8b
- open_mail_app: 794172f6a22cd16319d3ddaf45e945b2f74952b0
+ open_mail_app: 7314a609e88eed22d53671279e189af7a0ab0f11
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
- package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
- path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
- permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
- photo_manager: ff695c7a1dd5bc379974953a2b5c0a293f7c4c8a
- privacy_screen: 1a131c052ceb3c3659934b003b0d397c2381a24e
+ package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
+ path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
+ permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
+ photo_manager: d2fbcc0f2d82458700ee6256a15018210a81d413
+ privacy_screen: 3159a541f5d3a31bea916cfd4e58f9dc722b3fd4
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
- receive_sharing_intent: df9c334dc9feadcbd3266e5cb49c8443405e1c9f
- screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
- SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8
+ receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
+ SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
- Sentry: f8374b5415bc38dfb5645941b3ae31230fbeae57
- sentry_flutter: 0eb93e5279eb41e2392212afe1ccd2fecb4f8cbe
- share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad
- shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
- sqflite_darwin: a553b1fd6fe66f53bbb0fe5b4f5bab93f08d7a13
- sqlite3: 0bb0e6389d824e40296f531b858a2a0b71c0d2fb
- sqlite3_flutter_libs: c00457ebd31e59fa6bb830380ddba24d44fbcd3b
- system_info_plus: 5393c8da281d899950d751713575fbf91c7709aa
- Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
- ua_client_hints: 46bb5817a868f9e397c0ba7e3f2f5c5d90c35156
- uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
- url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
- video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3
- video_thumbnail: c4e2a3c539e247d4de13cd545344fd2d26ffafd1
- volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9
- wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47
+ Sentry: 0f9bc9adfc0b960e7f3bb5ec67e9a3d8193f3bdb
+ sentry_flutter: f4a0466dc8855998ffd59378ec33507c7dc32d7b
+ share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
+ shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
+ sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
+ sqlite3: fc1400008a9b3525f5914ed715a5d1af0b8f4983
+ sqlite3_flutter_libs: 3c323550ef3b928bc0aa9513c841e45a7d242832
+ system_info_plus: 555ce7047fbbf29154726db942ae785c29211740
+ ua_client_hints: 92fe0d139619b73ec9fcb46cc7e079a26178f586
+ uni_links: f191d616c4db8750f74c72c988e79a83dd297fac
+ url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
+ video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b
+ video_thumbnail: 584ccfa55d8fd2f3d5507218b0a18d84c839c620
+ volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12
+ wakelock_plus: 04623e3f525556020ebd4034310f20fe7fda8b49
PODFILE CHECKSUM: 20e086e6008977d43a3d40260f3f9bffcac748dd
diff --git a/mobile/ios/Runner.xcodeproj/project.pbxproj b/mobile/ios/Runner.xcodeproj/project.pbxproj
index 65b1ae54d5..183710c51f 100644
--- a/mobile/ios/Runner.xcodeproj/project.pbxproj
+++ b/mobile/ios/Runner.xcodeproj/project.pbxproj
@@ -288,15 +288,15 @@
"${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework",
"${BUILT_PRODUCTS_DIR}/SDWebImageWebPCoder/SDWebImageWebPCoder.framework",
"${BUILT_PRODUCTS_DIR}/Sentry/Sentry.framework",
- "${BUILT_PRODUCTS_DIR}/Toast/Toast.framework",
"${BUILT_PRODUCTS_DIR}/background_fetch/background_fetch.framework",
"${BUILT_PRODUCTS_DIR}/battery_info/battery_info.framework",
"${BUILT_PRODUCTS_DIR}/connectivity_plus/connectivity_plus.framework",
+ "${BUILT_PRODUCTS_DIR}/cupertino_http/cupertino_http.framework",
"${BUILT_PRODUCTS_DIR}/dart_ui_isolate/dart_ui_isolate.framework",
"${BUILT_PRODUCTS_DIR}/device_info_plus/device_info_plus.framework",
"${BUILT_PRODUCTS_DIR}/file_saver/file_saver.framework",
"${BUILT_PRODUCTS_DIR}/flutter_email_sender/flutter_email_sender.framework",
- "${BUILT_PRODUCTS_DIR}/flutter_image_compress/flutter_image_compress.framework",
+ "${BUILT_PRODUCTS_DIR}/flutter_image_compress_common/flutter_image_compress_common.framework",
"${BUILT_PRODUCTS_DIR}/flutter_inappwebview_ios/flutter_inappwebview_ios.framework",
"${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework",
"${BUILT_PRODUCTS_DIR}/flutter_native_splash/flutter_native_splash.framework",
@@ -314,20 +314,19 @@
"${BUILT_PRODUCTS_DIR}/maps_launcher/maps_launcher.framework",
"${BUILT_PRODUCTS_DIR}/media_extension/media_extension.framework",
"${BUILT_PRODUCTS_DIR}/media_kit_libs_ios_video/media_kit_libs_ios_video.framework",
- "${BUILT_PRODUCTS_DIR}/media_kit_native_event_loop/media_kit_native_event_loop.framework",
"${BUILT_PRODUCTS_DIR}/media_kit_video/media_kit_video.framework",
"${BUILT_PRODUCTS_DIR}/motion_sensors/motion_sensors.framework",
"${BUILT_PRODUCTS_DIR}/motionphoto/motionphoto.framework",
"${BUILT_PRODUCTS_DIR}/move_to_background/move_to_background.framework",
"${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
"${BUILT_PRODUCTS_DIR}/native_video_player/native_video_player.framework",
+ "${BUILT_PRODUCTS_DIR}/objective_c/objective_c.framework",
"${BUILT_PRODUCTS_DIR}/open_mail_app/open_mail_app.framework",
"${BUILT_PRODUCTS_DIR}/package_info_plus/package_info_plus.framework",
"${BUILT_PRODUCTS_DIR}/path_provider_foundation/path_provider_foundation.framework",
"${BUILT_PRODUCTS_DIR}/photo_manager/photo_manager.framework",
"${BUILT_PRODUCTS_DIR}/privacy_screen/privacy_screen.framework",
"${BUILT_PRODUCTS_DIR}/receive_sharing_intent/receive_sharing_intent.framework",
- "${BUILT_PRODUCTS_DIR}/screen_brightness_ios/screen_brightness_ios.framework",
"${BUILT_PRODUCTS_DIR}/sentry_flutter/sentry_flutter.framework",
"${BUILT_PRODUCTS_DIR}/share_plus/share_plus.framework",
"${BUILT_PRODUCTS_DIR}/shared_preferences_foundation/shared_preferences_foundation.framework",
@@ -383,15 +382,15 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sentry.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Toast.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/background_fetch.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/battery_info.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity_plus.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/cupertino_http.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/dart_ui_isolate.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info_plus.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_saver.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_email_sender.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_image_compress.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_image_compress_common.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_inappwebview_ios.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_native_splash.framework",
@@ -409,20 +408,19 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/maps_launcher.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/media_extension.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/media_kit_libs_ios_video.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/media_kit_native_event_loop.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/media_kit_video.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/motion_sensors.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/motionphoto.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/move_to_background.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/native_video_player.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/objective_c.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/open_mail_app.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info_plus.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_foundation.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/photo_manager.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/privacy_screen.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/receive_sharing_intent.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/screen_brightness_ios.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sentry_flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share_plus.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_foundation.framework",
diff --git a/mobile/lib/app.dart b/mobile/lib/app.dart
index 96111aa10b..4596e06710 100644
--- a/mobile/lib/app.dart
+++ b/mobile/lib/app.dart
@@ -16,7 +16,7 @@ import "package:photos/l10n/l10n.dart";
import "package:photos/service_locator.dart";
import 'package:photos/services/app_lifecycle_service.dart';
import "package:photos/services/home_widget_service.dart";
-import 'package:photos/services/sync_service.dart';
+import 'package:photos/services/sync/sync_service.dart';
import 'package:photos/ui/tabs/home_widget.dart';
import "package:photos/ui/viewer/actions/file_viewer.dart";
import "package:photos/utils/intent_util.dart";
diff --git a/mobile/lib/core/configuration.dart b/mobile/lib/core/configuration.dart
index e15193a5d3..e18f4e3a40 100644
--- a/mobile/lib/core/configuration.dart
+++ b/mobile/lib/core/configuration.dart
@@ -3,6 +3,7 @@ import 'dart:convert';
import "dart:io";
import 'package:bip39/bip39.dart' as bip39;
+import "package:ente_crypto/ente_crypto.dart";
import "package:flutter/services.dart";
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:logging/logging.dart';
@@ -12,16 +13,16 @@ import 'package:photos/core/error-reporting/super_logging.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/db/collections_db.dart';
import 'package:photos/db/files_db.dart';
-import 'package:photos/db/memories_db.dart';
+import "package:photos/db/memories_db.dart";
import "package:photos/db/ml/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';
-import 'package:photos/models/key_gen_result.dart';
-import 'package:photos/models/private_key_attributes.dart';
+import 'package:photos/models/api/user/key_attributes.dart';
+import 'package:photos/models/api/user/key_gen_result.dart';
+import 'package:photos/models/api/user/private_key_attributes.dart';
import 'package:photos/services/collections_service.dart';
import 'package:photos/services/favorites_service.dart';
import "package:photos/services/home_widget_service.dart";
@@ -29,8 +30,7 @@ import 'package:photos/services/ignored_files_service.dart';
import "package:photos/services/machine_learning/face_ml/person/person_service.dart";
import 'package:photos/services/memories_service.dart';
import 'package:photos/services/search_service.dart';
-import 'package:photos/services/sync_service.dart';
-import 'package:photos/utils/crypto_util.dart';
+import 'package:photos/services/sync/sync_service.dart';
import 'package:photos/utils/file_uploader.dart';
import "package:photos/utils/lock_screen_settings.dart";
import 'package:photos/utils/validator_util.dart';
@@ -248,7 +248,7 @@ class Configuration {
// decrypt the master key
final kekSalt = CryptoUtil.getSaltToDeriveKey();
final derivedKeyResult = await CryptoUtil.deriveSensitiveKey(
- utf8.encode(password) as Uint8List,
+ utf8.encode(password),
kekSalt,
);
final loginKey = await CryptoUtil.deriveLoginKey(derivedKeyResult.key);
@@ -294,7 +294,7 @@ class Configuration {
// decrypt the master key
final kekSalt = CryptoUtil.getSaltToDeriveKey();
final derivedKeyResult = await CryptoUtil.deriveSensitiveKey(
- utf8.encode(password) as Uint8List,
+ utf8.encode(password),
kekSalt,
);
final loginKey = await CryptoUtil.deriveLoginKey(derivedKeyResult.key);
@@ -332,7 +332,7 @@ class Configuration {
// Derive key-encryption-key from the entered password and existing
// mem and ops limits
keyEncryptionKey ??= await CryptoUtil.deriveKey(
- utf8.encode(password) as Uint8List,
+ utf8.encode(password),
CryptoUtil.base642bin(attributes.kekSalt),
attributes.memLimit!,
attributes.opsLimit!,
diff --git a/mobile/lib/core/constants.dart b/mobile/lib/core/constants.dart
index f55c3344ed..58f1fb6963 100644
--- a/mobile/lib/core/constants.dart
+++ b/mobile/lib/core/constants.dart
@@ -113,3 +113,5 @@ final tempDirCleanUpInterval = kDebugMode
const kFilterChipHeight = 32.0;
const kMaxAppbarFilters = 14;
+
+const kLivePhotoHashSeparator = ':';
diff --git a/mobile/lib/core/error-reporting/super_logging.dart b/mobile/lib/core/error-reporting/super_logging.dart
index 7c0bef58be..dbe2258098 100644
--- a/mobile/lib/core/error-reporting/super_logging.dart
+++ b/mobile/lib/core/error-reporting/super_logging.dart
@@ -18,6 +18,7 @@ import 'package:photos/core/error-reporting/tunneled_transport.dart';
import "package:photos/core/errors.dart";
import 'package:photos/models/typedefs.dart';
import "package:photos/utils/device_info.dart";
+import "package:photos/utils/ram_check_util.dart";
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart';
@@ -205,6 +206,12 @@ class SuperLogging {
}),
);
+ unawaited(
+ checkDeviceTotalRAM().then((ram) {
+ if (ram != null) $.info("Device RAM: ${ram}MB");
+ }),
+ );
+
if (appConfig.body == null) return;
if (enable && sentryIsEnabled) {
@@ -236,7 +243,7 @@ class SuperLogging {
}
static _shouldSkipSentry(Object error) {
- if (error is DioError) {
+ if (error is DioException) {
return true;
}
final bool result = error is StorageLimitExceededError ||
diff --git a/mobile/lib/core/errors.dart b/mobile/lib/core/errors.dart
index f1c7c24b3c..0c0d16949a 100644
--- a/mobile/lib/core/errors.dart
+++ b/mobile/lib/core/errors.dart
@@ -20,7 +20,7 @@ extension InvalidReasonExn on InvalidReason {
class InvalidFileError extends ArgumentError {
final InvalidReason reason;
- InvalidFileError(String message, this.reason) : super(message);
+ InvalidFileError(String super.message, this.reason);
@override
String toString() {
@@ -58,24 +58,22 @@ bool isHandledSyncError(Object errObj) {
class LockAlreadyAcquiredError extends Error {}
+class LockFreedError extends Error{}
+
class UnauthorizedError extends Error {}
class RequestCancelledError extends Error {}
class InvalidSyncStatusError extends AssertionError {
- InvalidSyncStatusError(String message) : super(message);
+ InvalidSyncStatusError(String super.message);
}
class UnauthorizedEditError extends AssertionError {}
class InvalidStateError extends AssertionError {
- InvalidStateError(String message) : super(message);
+ InvalidStateError(String super.message);
}
-class KeyDerivationError extends Error {}
-
-class LoginKeyDerivationError extends Error {}
-
class SrpSetupNotCompleteError extends Error {}
class SharingNotPermittedForFreeAccountsError extends Error {}
diff --git a/mobile/lib/core/network/network.dart b/mobile/lib/core/network/network.dart
index a55a1a807e..ba2540b401 100644
--- a/mobile/lib/core/network/network.dart
+++ b/mobile/lib/core/network/network.dart
@@ -1,6 +1,7 @@
import 'dart:io';
import 'package:dio/dio.dart';
+import 'package:native_dio_adapter/native_dio_adapter.dart';
import 'package:package_info_plus/package_info_plus.dart';
import "package:photos/core/configuration.dart";
import "package:photos/core/event_bus.dart";
@@ -8,18 +9,17 @@ import 'package:photos/core/network/ente_interceptor.dart';
import "package:photos/events/endpoint_updated_event.dart";
import "package:ua_client_hints/ua_client_hints.dart";
-int kConnectTimeout = 15000;
-
class NetworkClient {
late Dio _dio;
late Dio _enteDio;
+ static const kConnectTimeout = 15;
Future init(PackageInfo packageInfo) async {
final String ua = await userAgent();
final endpoint = Configuration.instance.getHttpEndpoint();
_dio = Dio(
BaseOptions(
- connectTimeout: kConnectTimeout,
+ connectTimeout: const Duration(seconds: kConnectTimeout),
headers: {
HttpHeaders.userAgentHeader: ua,
'X-Client-Version': packageInfo.version,
@@ -30,7 +30,7 @@ class NetworkClient {
_enteDio = Dio(
BaseOptions(
baseUrl: endpoint,
- connectTimeout: kConnectTimeout,
+ connectTimeout: const Duration(seconds: kConnectTimeout),
headers: {
HttpHeaders.userAgentHeader: ua,
'X-Client-Version': packageInfo.version,
@@ -38,6 +38,10 @@ class NetworkClient {
},
),
);
+
+ _dio.httpClientAdapter = NativeAdapter();
+ _enteDio.httpClientAdapter = NativeAdapter();
+
_setupInterceptors(endpoint);
Bus.instance.on().listen((event) {
diff --git a/mobile/lib/data/years.dart b/mobile/lib/data/years.dart
index 2b2e04d911..5f496d2a68 100644
--- a/mobile/lib/data/years.dart
+++ b/mobile/lib/data/years.dart
@@ -1,4 +1,4 @@
-import 'package:photos/utils/date_time_util.dart';
+import 'package:photos/utils/standalone/date_time.dart';
class YearsData {
final List yearsData = [];
diff --git a/mobile/lib/db/collections_db.dart b/mobile/lib/db/collections_db.dart
index 178e81302e..c73b9a8e35 100644
--- a/mobile/lib/db/collections_db.dart
+++ b/mobile/lib/db/collections_db.dart
@@ -251,20 +251,20 @@ class CollectionsDB {
Map _getRowForCollection(Collection collection) {
final row = {};
row[columnID] = collection.id;
- row[columnOwner] = collection.owner!.toJson();
+ row[columnOwner] = collection.owner.toJson();
row[columnEncryptedKey] = collection.encryptedKey;
row[columnKeyDecryptionNonce] = collection.keyDecryptionNonce;
row[columnName] = collection.name;
row[columnEncryptedName] = collection.encryptedName;
row[columnNameDecryptionNonce] = collection.nameDecryptionNonce;
- row[columnType] = Collection.typeToString(collection.type);
+ row[columnType] = typeToString(collection.type);
row[columnEncryptedPath] = collection.attributes.encryptedPath;
row[columnPathDecryptionNonce] = collection.attributes.pathDecryptionNonce;
row[columnVersion] = collection.attributes.version;
row[columnSharees] =
- json.encode(collection.sharees?.map((x) => x?.toMap()).toList());
+ json.encode(collection.sharees.map((x) => x.toMap()).toList());
row[columnPublicURLs] =
- json.encode(collection.publicURLs?.map((x) => x?.toMap()).toList());
+ json.encode(collection.publicURLs.map((x) => x.toMap()).toList());
row[columnUpdationTime] = collection.updationTime;
if (collection.isDeleted) {
row[columnIsDeleted] = _sqlBoolTrue;
@@ -290,7 +290,7 @@ class CollectionsDB {
row[columnName],
row[columnEncryptedName],
row[columnNameDecryptionNonce],
- Collection.typeFromString(row[columnType]),
+ typeFromString(row[columnType]),
CollectionAttributes(
encryptedPath: row[columnEncryptedPath],
pathDecryptionNonce: row[columnPathDecryptionNonce],
diff --git a/mobile/lib/utils/sqlite_util.dart b/mobile/lib/db/enum/conflict_algo.dart
similarity index 100%
rename from mobile/lib/utils/sqlite_util.dart
rename to mobile/lib/db/enum/conflict_algo.dart
diff --git a/mobile/lib/db/file_updation_db.dart b/mobile/lib/db/file_updation_db.dart
index 3d781b7867..e4f79380a8 100644
--- a/mobile/lib/db/file_updation_db.dart
+++ b/mobile/lib/db/file_updation_db.dart
@@ -14,7 +14,6 @@ class FileUpdationDB {
static const tableName = 're_upload_tracker';
static const columnLocalID = 'local_id';
static const columnReason = 'reason';
- static const livePhotoCheck = 'livePhotoCheck';
static const androidMissingGPS = 'androidMissingGPS';
static const modificationTimeUpdated = 'modificationTimeUpdated';
diff --git a/mobile/lib/db/files_db.dart b/mobile/lib/db/files_db.dart
index 4452f12097..b4bffc79a3 100644
--- a/mobile/lib/db/files_db.dart
+++ b/mobile/lib/db/files_db.dart
@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
+import "package:photos/db/enum/conflict_algo.dart";
import "package:photos/extensions/stop_watch.dart";
import 'package:photos/models/backup_status.dart';
import 'package:photos/models/file/file.dart';
@@ -15,8 +16,6 @@ import 'package:photos/models/location/location.dart';
import "package:photos/models/metadata/common_keys.dart";
import "package:photos/services/filter/db_filters.dart";
import 'package:photos/utils/file_uploader_util.dart';
-import "package:photos/utils/primitive_wrapper.dart";
-import "package:photos/utils/sqlite_util.dart";
import 'package:sqlite_async/sqlite_async.dart';
class FilesDB {
@@ -468,72 +467,61 @@ class FilesDB {
final startTime = DateTime.now();
final db = await sqliteAsyncDB;
- ///Strong batch counter in an object so that it gets passed by reference
- ///Primitives are passed by value
- final genIdNotNullbatchCounter = PrimitiveWrapper(0);
- final genIdNullbatchCounter = PrimitiveWrapper(0);
- final genIdNullParameterSets = >[];
- final genIdNotNullParameterSets = >[];
+ final withIdParams = >[];
+ const withIdColumnNames = _columnNames;
+ final withoutIdParams = >[];
+ final withoutIdColumns =
+ _columnNames.where((column) => column != columnGeneratedID).toList();
- final genIdNullcolumnNames =
- _columnNames.where((element) => element != columnGeneratedID);
+ // Sort files into appropriate parameter sets
+ for (final file in files) {
+ if (file.generatedID == null) {
+ withoutIdParams.add(_getParameterSetForFile(file));
- for (EnteFile file in files) {
- final fileGenIdIsNull = file.generatedID == null;
-
- if (!fileGenIdIsNull) {
- await _batchAndInsertFile(
- file,
- conflictAlgorithm,
- db,
- genIdNotNullParameterSets,
- genIdNotNullbatchCounter,
- isGenIdNull: fileGenIdIsNull,
- );
+ if (withoutIdParams.length == 400) {
+ await _insertBatch(
+ conflictAlgorithm,
+ withoutIdColumns,
+ db,
+ withoutIdParams,
+ );
+ withoutIdParams.clear();
+ }
} else {
- await _batchAndInsertFile(
- file,
- conflictAlgorithm,
- db,
- genIdNullParameterSets,
- genIdNullbatchCounter,
- isGenIdNull: fileGenIdIsNull,
- );
+ withIdParams.add(_getParameterSetForFile(file));
+ if (withIdParams.length == 400) {
+ await _insertBatch(
+ conflictAlgorithm,
+ withIdColumnNames,
+ db,
+ withIdParams,
+ );
+ withIdParams.clear();
+ }
}
}
- if (genIdNotNullbatchCounter.value > 0) {
+ // Insert any remaining files
+ if (withIdParams.isNotEmpty) {
await _insertBatch(
conflictAlgorithm,
- _columnNames,
+ withIdColumnNames,
db,
- genIdNotNullParameterSets,
+ withIdParams,
);
- genIdNotNullbatchCounter.value = 0;
- genIdNotNullParameterSets.clear();
- }
- if (genIdNullbatchCounter.value > 0) {
- await _insertBatch(
- conflictAlgorithm,
- genIdNullcolumnNames,
- db,
- genIdNullParameterSets,
- );
- genIdNullbatchCounter.value = 0;
- genIdNullParameterSets.clear();
}
- final endTime = DateTime.now();
- final duration = Duration(
- microseconds:
- endTime.microsecondsSinceEpoch - startTime.microsecondsSinceEpoch,
- );
+ if (withoutIdParams.isNotEmpty) {
+ await _insertBatch(
+ conflictAlgorithm,
+ withoutIdColumns,
+ db,
+ withoutIdParams,
+ );
+ }
+ final duration = DateTime.now().difference(startTime);
_logger.info(
- "Batch insert of " +
- files.length.toString() +
- " took " +
- duration.inMilliseconds.toString() +
- "ms.",
+ "Batch insert of ${files.length} took ${duration.inMilliseconds}ms.",
);
}
@@ -1272,15 +1260,26 @@ class FilesDB {
);
}
- Future> getLocalFiles(List localIDs) async {
+ Future> getLocalFiles(
+ List localIDs, {
+ bool dedupeByLocalID = false,
+ }) async {
+ late final String query;
final inParam = localIDs.map((id) => "'$id'").join(',');
final db = await instance.sqliteAsyncDB;
- final results = await db.getAll(
- '''
+ if (dedupeByLocalID) {
+ query = '''
+ SELECT * FROM $filesTable
+ WHERE $columnLocalID IN ($inParam)
+ GROUP BY $columnLocalID;
+ ''';
+ } else {
+ query = '''
SELECT * FROM $filesTable
WHERE $columnLocalID IN ($inParam);
- ''',
- );
+ ''';
+ }
+ final results = await db.getAll(query);
return convertToFiles(results);
}
@@ -1733,6 +1732,7 @@ class FilesDB {
Future> getAllFilesAfterDate({
required FileType fileType,
required DateTime beginDate,
+ required int userID,
}) async {
final db = await instance.sqliteAsyncDB;
final results = await db.getAll(
@@ -1741,6 +1741,7 @@ class FilesDB {
WHERE $columnFileType = ?
AND $columnCreationTime > ?
AND $columnUploadedFileID != -1
+ AND $columnOwnerID = $userID
ORDER BY $columnCreationTime DESC
''',
[getInt(fileType), beginDate.microsecondsSinceEpoch],
@@ -1941,28 +1942,6 @@ class FilesDB {
return values;
}
- Future _batchAndInsertFile(
- EnteFile file,
- SqliteAsyncConflictAlgorithm conflictAlgorithm,
- SqliteDatabase db,
- List> parameterSets,
- PrimitiveWrapper batchCounter, {
- required bool isGenIdNull,
- }) async {
- parameterSets.add(_getParameterSetForFile(file));
- batchCounter.value++;
-
- final columnNames = isGenIdNull
- ? _columnNames.where((column) => column != columnGeneratedID)
- : _columnNames;
- if (batchCounter.value == 400) {
- _logger.info("Inserting batch with genIdNull: $isGenIdNull");
- await _insertBatch(conflictAlgorithm, columnNames, db, parameterSets);
- batchCounter.value = 0;
- parameterSets.clear();
- }
- }
-
Future _insertBatch(
SqliteAsyncConflictAlgorithm conflictAlgorithm,
Iterable columnNames,
diff --git a/mobile/lib/db/memories_db.dart b/mobile/lib/db/memories_db.dart
index eb84627b41..acee44fec9 100644
--- a/mobile/lib/db/memories_db.dart
+++ b/mobile/lib/db/memories_db.dart
@@ -3,7 +3,7 @@ import 'dart:io';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
-import 'package:photos/models/memory.dart';
+import 'package:photos/models/memories/memory.dart';
import 'package:sqflite/sqflite.dart';
class MemoriesDB {
diff --git a/mobile/lib/db/ml/base.dart b/mobile/lib/db/ml/base.dart
index c2685b1214..a99f70f813 100644
--- a/mobile/lib/db/ml/base.dart
+++ b/mobile/lib/db/ml/base.dart
@@ -108,9 +108,6 @@ abstract class IMLDataDB {
Future> getAllClipVectors();
Future