From f910da0964e8217b59aa3b3f50cd987a092e5cf4 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Mon, 20 Nov 2023 13:28:27 +0530 Subject: [PATCH 01/10] Handle loginKey and keyDerivation err during SRP based login --- lib/core/errors.dart | 4 +- lib/generated/intl/messages_cs.dart | 1 + lib/generated/intl/messages_de.dart | 1 + lib/generated/intl/messages_en.dart | 9 +- lib/generated/intl/messages_es.dart | 1 + lib/generated/intl/messages_fr.dart | 66 +++++- lib/generated/intl/messages_it.dart | 1 + lib/generated/intl/messages_ko.dart | 1 + lib/generated/intl/messages_nl.dart | 1 + lib/generated/intl/messages_no.dart | 1 + lib/generated/intl/messages_pl.dart | 1 + lib/generated/intl/messages_pt.dart | 1 + lib/generated/intl/messages_zh.dart | 42 +++- lib/generated/l10n.dart | 24 ++- lib/l10n/intl_en.arb | 4 +- lib/services/user_service.dart | 201 +++++++----------- .../account/login_pwd_verification_page.dart | 100 ++++++++- lib/utils/crypto_util.dart | 151 +++++++------ 18 files changed, 400 insertions(+), 210 deletions(-) diff --git a/lib/core/errors.dart b/lib/core/errors.dart index 634988e0daba08ff2d998fe497b6b9cdc8c7b319..a9e175b88a563f703e5a686084f6728e627765ce 100644 --- a/lib/core/errors.dart +++ b/lib/core/errors.dart @@ -7,8 +7,8 @@ enum InvalidReason { livePhotoVideoMissing, thumbnailMissing, unknown, - } + extension InvalidReasonExn on InvalidReason { bool get isLivePhotoErr => this == InvalidReason.livePhotoToImageTypeChanged || @@ -73,6 +73,8 @@ class InvalidStateError extends AssertionError { class KeyDerivationError extends Error {} +class LoginKeyDerivationError extends Error {} + class SrpSetupNotCompleteError extends Error {} class SharingNotPermittedForFreeAccountsError extends Error {} diff --git a/lib/generated/intl/messages_cs.dart b/lib/generated/intl/messages_cs.dart index 815bedb4acdeddc6fc43d2db938c2c0cfdb54e33..a0b3b9f7d94395163d0ad789e17517d3b288b4a9 100644 --- a/lib/generated/intl/messages_cs.dart +++ b/lib/generated/intl/messages_cs.dart @@ -24,6 +24,7 @@ class MessageLookup extends MessageLookupByLibrary { static Map _notInlinedMessages(_) => { "addToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Add to hidden album"), + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "deleteConfirmDialogBody": MessageLookupByLibrary.simpleMessage( "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted."), "fileTypes": MessageLookupByLibrary.simpleMessage("File types"), diff --git a/lib/generated/intl/messages_de.dart b/lib/generated/intl/messages_de.dart index 1c31ebad29150c417ded9dd25404196fd42a5983..1b935485f22a99fd8c899c8d823015af61edd5fd 100644 --- a/lib/generated/intl/messages_de.dart +++ b/lib/generated/intl/messages_de.dart @@ -442,6 +442,7 @@ class MessageLookup extends MessageLookupByLibrary { "contactSupport": MessageLookupByLibrary.simpleMessage("Support kontaktieren"), "contactToManageSubscription": m10, + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "continueLabel": MessageLookupByLibrary.simpleMessage("Weiter"), "continueOnFreeTrial": MessageLookupByLibrary.simpleMessage( "Mit kostenloser Testversion fortfahren"), diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index 5cbdf629e98ab2bbcff844887a0978fd965a8816..ad75c50ab5537eae163981b7e4a4428603570c24 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -441,6 +441,7 @@ class MessageLookup extends MessageLookupByLibrary { "contactSupport": MessageLookupByLibrary.simpleMessage("Contact support"), "contactToManageSubscription": m10, + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "contents": MessageLookupByLibrary.simpleMessage("Contents"), "continueLabel": MessageLookupByLibrary.simpleMessage("Continue"), "continueOnFreeTrial": @@ -879,6 +880,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("No hidden photos or videos"), "noImagesWithLocation": MessageLookupByLibrary.simpleMessage("No images with location"), + "noInternetConnection": + MessageLookupByLibrary.simpleMessage("No internet connection"), "noPhotosAreBeingBackedUpRightNow": MessageLookupByLibrary.simpleMessage( "No photos are being backed up right now"), @@ -926,7 +929,6 @@ class MessageLookup extends MessageLookupByLibrary { "paymentFailedTalkToProvider": m33, "paymentFailedWithReason": m34, "pendingSync": MessageLookupByLibrary.simpleMessage("Pending sync"), - "people": MessageLookupByLibrary.simpleMessage("People"), "peopleUsingYourCode": MessageLookupByLibrary.simpleMessage("People using your code"), "permDeleteWarning": MessageLookupByLibrary.simpleMessage( @@ -950,6 +952,9 @@ class MessageLookup extends MessageLookupByLibrary { "playStoreFreeTrialValidTill": m35, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("PlayStore subscription"), + "pleaseCheckYourInternetConnectionAndTryAgain": + MessageLookupByLibrary.simpleMessage( + "Please check your internet connection and try again."), "pleaseContactSupportAndWeWillBeHappyToHelp": MessageLookupByLibrary.simpleMessage( "Please contact support@ente.io and we will be happy to help!"), @@ -1120,7 +1125,7 @@ class MessageLookup extends MessageLookupByLibrary { "Albums, file names, and types"), "searchHint4": MessageLookupByLibrary.simpleMessage("Location"), "searchHint5": MessageLookupByLibrary.simpleMessage( - "Coming soon: Photo contents, faces"), + "Coming soon: Faces & magic search ✨"), "searchHintText": MessageLookupByLibrary.simpleMessage( "Albums, months, days, years, ..."), "searchLocationEmptySection": MessageLookupByLibrary.simpleMessage( diff --git a/lib/generated/intl/messages_es.dart b/lib/generated/intl/messages_es.dart index 9d6829d71d8e49e4bb84118354e0a257c28b8d00..49927717532088d93f29383350013d3cbb4bf616 100644 --- a/lib/generated/intl/messages_es.dart +++ b/lib/generated/intl/messages_es.dart @@ -398,6 +398,7 @@ class MessageLookup extends MessageLookupByLibrary { "contactSupport": MessageLookupByLibrary.simpleMessage("Contactar con soporte"), "contactToManageSubscription": m10, + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "continueLabel": MessageLookupByLibrary.simpleMessage("Continuar"), "continueOnFreeTrial": MessageLookupByLibrary.simpleMessage( "Continuar con el plan gratuito"), diff --git a/lib/generated/intl/messages_fr.dart b/lib/generated/intl/messages_fr.dart index 264b5dd967358354d98ce97ac6abcf5759801075..79391df748efab504c5f8f5aa4816f2e4049ff7e 100644 --- a/lib/generated/intl/messages_fr.dart +++ b/lib/generated/intl/messages_fr.dart @@ -140,6 +140,9 @@ class MessageLookup extends MessageLookupByLibrary { static String m41(endDate) => "Renouvellement le ${endDate}"; + static String m64(count) => + "${Intl.plural(count, one: '${count} résultat trouvé', other: '${count} résultats trouvés')}"; + static String m42(count) => "${count} sélectionné(s)"; static String m43(count, yourCount) => @@ -189,6 +192,8 @@ class MessageLookup extends MessageLookupByLibrary { static String m59(count) => "${Intl.plural(count, zero: '0 jour', one: '1 jour', other: '${count} jours')}"; + static String m65(endDate) => "Valable jusqu\'au ${endDate}"; + static String m60(email) => "Vérifier ${email}"; static String m61(email) => @@ -223,6 +228,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ajouter la localisation"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Ajouter"), "addMore": MessageLookupByLibrary.simpleMessage("Ajouter Plus"), + "addNew": MessageLookupByLibrary.simpleMessage("Ajouter un nouveau"), + "addOnPageSubtitle": MessageLookupByLibrary.simpleMessage( + "Détails des modules complémentaires"), + "addOns": + MessageLookupByLibrary.simpleMessage("Modules complémentaires"), "addPhotos": MessageLookupByLibrary.simpleMessage("Ajouter des photos"), "addSelected": MessageLookupByLibrary.simpleMessage("Ajouter la sélection"), @@ -233,6 +243,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ajouter à un album masqué"), "addViewer": MessageLookupByLibrary.simpleMessage("Ajouter un observateur"), + "addYourPhotosNow": MessageLookupByLibrary.simpleMessage( + "Ajoutez vos photos maintenant"), "addedAs": MessageLookupByLibrary.simpleMessage("Ajouté comme"), "addedBy": m1, "addedSuccessfullyTo": m2, @@ -356,6 +368,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Paramètres de la sauvegarde"), "backupVideos": MessageLookupByLibrary.simpleMessage("Sauvegarde des vidéos"), + "blackFridaySale": + MessageLookupByLibrary.simpleMessage("Offre Black Friday"), "blog": MessageLookupByLibrary.simpleMessage("Blog"), "cachedData": MessageLookupByLibrary.simpleMessage("Données mises en cache"), @@ -446,6 +460,8 @@ class MessageLookup extends MessageLookupByLibrary { "contactSupport": MessageLookupByLibrary.simpleMessage("Contacter l\'assistance"), "contactToManageSubscription": m10, + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), + "contents": MessageLookupByLibrary.simpleMessage("Contenus"), "continueLabel": MessageLookupByLibrary.simpleMessage("Continuer"), "continueOnFreeTrial": MessageLookupByLibrary.simpleMessage( "Poursuivre avec la version d\'essai gratuite"), @@ -510,7 +526,7 @@ class MessageLookup extends MessageLookupByLibrary { "Ceci supprimera tous les albums vides. Ceci est utile lorsque vous voulez réduire l\'encombrement dans votre liste d\'albums."), "deleteAll": MessageLookupByLibrary.simpleMessage("Tout Supprimer"), "deleteConfirmDialogBody": MessageLookupByLibrary.simpleMessage( - "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted."), + "Ce compte est lié à d\'autres applications ente, si vous en utilisez une.\\n\\nVos données téléchargées, dans toutes les applications ente, seront planifiées pour suppression, et votre compte sera définitivement supprimé."), "deleteEmailRequest": MessageLookupByLibrary.simpleMessage( "Veuillez envoyer un e-mail à account-deletion@ente.io à partir de votre adresse e-mail enregistrée."), "deleteEmptyAlbums": @@ -658,6 +674,7 @@ class MessageLookup extends MessageLookupByLibrary { "exportLogs": MessageLookupByLibrary.simpleMessage("Exporter les logs"), "exportYourData": MessageLookupByLibrary.simpleMessage("Exportez vos données"), + "faces": MessageLookupByLibrary.simpleMessage("Visages"), "failedToApplyCode": MessageLookupByLibrary.simpleMessage( "Impossible d\'appliquer le code"), "failedToCancel": @@ -689,7 +706,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ajouter une description..."), "fileSavedToGallery": MessageLookupByLibrary.simpleMessage( "Fichier enregistré dans la galerie"), - "fileTypes": MessageLookupByLibrary.simpleMessage("File types"), + "fileTypes": MessageLookupByLibrary.simpleMessage("Types de fichiers"), + "fileTypesAndNames": + MessageLookupByLibrary.simpleMessage("Types et noms de fichiers"), "filesBackedUpFromDevice": m19, "filesBackedUpInAlbum": m20, "filesDeleted": @@ -729,6 +748,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Accorder la permission"), "groupNearbyPhotos": MessageLookupByLibrary.simpleMessage( "Grouper les photos à proximité"), + "hearUsExplanation": MessageLookupByLibrary.simpleMessage( + "Nous ne suivons pas les installations d\'applications. Il serait utile que vous nous disiez comment vous nous avez trouvés !"), + "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( + "Comment avez-vous entendu parler de Ente? (facultatif)"), "hidden": MessageLookupByLibrary.simpleMessage("Masqué"), "hide": MessageLookupByLibrary.simpleMessage("Masquer"), "hiding": MessageLookupByLibrary.simpleMessage("Masquage en cours..."), @@ -810,6 +833,7 @@ class MessageLookup extends MessageLookupByLibrary { "linkHasExpired": MessageLookupByLibrary.simpleMessage("Le lien a expiré"), "linkNeverExpires": MessageLookupByLibrary.simpleMessage("Jamais"), + "livePhotos": MessageLookupByLibrary.simpleMessage("Photos en direct"), "loadMessage1": MessageLookupByLibrary.simpleMessage( "Vous pouvez partager votre abonnement avec votre famille"), "loadMessage2": MessageLookupByLibrary.simpleMessage( @@ -876,7 +900,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Sécurité moyenne"), "modifyYourQueryOrTrySearchingFor": MessageLookupByLibrary.simpleMessage( - "Modify your query, or try searching for"), + "Modifiez votre requête, ou essayez de rechercher"), + "moments": MessageLookupByLibrary.simpleMessage("Souvenirs"), "monthly": MessageLookupByLibrary.simpleMessage("Mensuel"), "moveItem": m30, "moveToAlbum": @@ -966,9 +991,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Supprimer définitivement"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage( "Supprimer définitivement de l\'appareil ?"), + "photoDescriptions": + MessageLookupByLibrary.simpleMessage("Descriptions de la photo"), "photoGridSize": MessageLookupByLibrary.simpleMessage("Taille de la grille photo"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("photo"), + "photos": MessageLookupByLibrary.simpleMessage("Photos"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage( "Les photos ajoutées par vous seront retirées de l\'album"), @@ -1136,12 +1164,36 @@ class MessageLookup extends MessageLookupByLibrary { "scanThisBarcodeWithnyourAuthenticatorApp": MessageLookupByLibrary.simpleMessage( "Scannez ce code-barres avec\nvotre application d\'authentification"), + "searchAlbumsEmptySection": + MessageLookupByLibrary.simpleMessage("Albums"), "searchByAlbumNameHint": MessageLookupByLibrary.simpleMessage("Nom de l\'album"), "searchByExamples": MessageLookupByLibrary.simpleMessage( "• Noms d\'albums (par exemple \"Caméra\")\n• Types de fichiers (par exemple \"Vidéos\", \".gif\")\n• Années et mois (par exemple \"2022\", \"Janvier\")\n• Vacances (par exemple \"Noël\")\n• Descriptions de photos (par exemple \"#fun\")"), + "searchCaptionEmptySection": MessageLookupByLibrary.simpleMessage( + "Ajoutez des descriptions comme \"#trip\" dans les infos photo pour les retrouver ici plus rapidement"), + "searchDatesEmptySection": MessageLookupByLibrary.simpleMessage( + "Recherche par date, mois ou année"), + "searchFaceEmptySection": MessageLookupByLibrary.simpleMessage( + "Trouver toutes les photos d\'une personne"), + "searchFileTypesAndNamesEmptySection": + MessageLookupByLibrary.simpleMessage("Types et noms de fichiers"), + "searchHint1": MessageLookupByLibrary.simpleMessage( + "Recherche rapide, sur l\'appareil"), + "searchHint2": MessageLookupByLibrary.simpleMessage( + "Dates des photos, descriptions"), + "searchHint3": MessageLookupByLibrary.simpleMessage( + "Albums, noms de fichiers et types"), + "searchHint4": MessageLookupByLibrary.simpleMessage("Emplacement"), + "searchHint5": MessageLookupByLibrary.simpleMessage( + "Bientôt: Visages & recherche magique ✨"), "searchHintText": MessageLookupByLibrary.simpleMessage( "Albums, mois, jours, années, ..."), + "searchLocationEmptySection": MessageLookupByLibrary.simpleMessage( + "Grouper les photos qui sont prises dans un certain angle d\'une photo"), + "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage( + "Invitez des gens, et vous verrez ici toutes les photos qu\'ils partagent"), + "searchResultCount": m64, "security": MessageLookupByLibrary.simpleMessage("Sécurité"), "selectAlbum": MessageLookupByLibrary.simpleMessage("Sélectionner album"), @@ -1400,6 +1452,8 @@ class MessageLookup extends MessageLookupByLibrary { "upgrade": MessageLookupByLibrary.simpleMessage("Améliorer"), "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Envoi des fichiers vers l\'album..."), + "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( + "Jusqu\'à 50% de réduction, jusqu\'au 4ème déc."), "usableReferralStorageInfo": MessageLookupByLibrary.simpleMessage( "Le stockage utilisable est limité par votre offre actuelle. Le stockage excédentaire deviendra automatiquement utilisable lorsque vous mettez à niveau votre offre."), "usePublicLinksForPeopleNotOnEnte": MessageLookupByLibrary.simpleMessage( @@ -1409,6 +1463,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage( "Utiliser la photo sélectionnée"), "usedSpace": MessageLookupByLibrary.simpleMessage("Mémoire utilisée"), + "validTill": m65, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "La vérification a échouée, veuillez réessayer"), @@ -1426,8 +1481,11 @@ class MessageLookup extends MessageLookupByLibrary { "verifyingRecoveryKey": MessageLookupByLibrary.simpleMessage( "Vérification de la clé de récupération..."), "videoSmallCase": MessageLookupByLibrary.simpleMessage("vidéo"), + "videos": MessageLookupByLibrary.simpleMessage("Vidéos"), "viewActiveSessions": MessageLookupByLibrary.simpleMessage( "Afficher les sessions actives"), + "viewAddOnButton": MessageLookupByLibrary.simpleMessage( + "Afficher les modules complémentaires"), "viewAll": MessageLookupByLibrary.simpleMessage("Tout afficher"), "viewAllExifData": MessageLookupByLibrary.simpleMessage( "Visualiser toutes les données EXIF"), @@ -1481,7 +1539,7 @@ class MessageLookup extends MessageLookupByLibrary { "youHaveSuccessfullyFreedUp": m63, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("Votre compte a été supprimé"), - "yourMap": MessageLookupByLibrary.simpleMessage("Your map"), + "yourMap": MessageLookupByLibrary.simpleMessage("Votre carte"), "yourPlanWasSuccessfullyDowngraded": MessageLookupByLibrary.simpleMessage( "Votre plan a été rétrogradé avec succès"), diff --git a/lib/generated/intl/messages_it.dart b/lib/generated/intl/messages_it.dart index 1659be2cbf37956c349ebb3cd03f81189058f10c..359f6d56901b9c5f7d7f20b9d942614b6996ad52 100644 --- a/lib/generated/intl/messages_it.dart +++ b/lib/generated/intl/messages_it.dart @@ -446,6 +446,7 @@ class MessageLookup extends MessageLookupByLibrary { "contactSupport": MessageLookupByLibrary.simpleMessage("Contatta il supporto"), "contactToManageSubscription": m10, + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "continueLabel": MessageLookupByLibrary.simpleMessage("Continua"), "continueOnFreeTrial": MessageLookupByLibrary.simpleMessage("Continua la prova gratuita"), diff --git a/lib/generated/intl/messages_ko.dart b/lib/generated/intl/messages_ko.dart index 653419baeb42d156d9958c0355eaacd2221aa6cd..7c52593426ef240c64a9e3236e08867e9047aae0 100644 --- a/lib/generated/intl/messages_ko.dart +++ b/lib/generated/intl/messages_ko.dart @@ -24,6 +24,7 @@ class MessageLookup extends MessageLookupByLibrary { static Map _notInlinedMessages(_) => { "addToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Add to hidden album"), + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "deleteConfirmDialogBody": MessageLookupByLibrary.simpleMessage( "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted."), "fileTypes": MessageLookupByLibrary.simpleMessage("File types"), diff --git a/lib/generated/intl/messages_nl.dart b/lib/generated/intl/messages_nl.dart index f2f316213f42291edf23c1967d909e28bade2f19..90ac6a2157bd7bc18f3f98cdbda3fb2f7a0cbd0a 100644 --- a/lib/generated/intl/messages_nl.dart +++ b/lib/generated/intl/messages_nl.dart @@ -441,6 +441,7 @@ class MessageLookup extends MessageLookupByLibrary { "contactSupport": MessageLookupByLibrary.simpleMessage("Contacteer klantenservice"), "contactToManageSubscription": m10, + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "continueLabel": MessageLookupByLibrary.simpleMessage("Doorgaan"), "continueOnFreeTrial": MessageLookupByLibrary.simpleMessage( "Doorgaan met gratis proefversie"), diff --git a/lib/generated/intl/messages_no.dart b/lib/generated/intl/messages_no.dart index 4de30a91b24e925acdc535e89bc0a4262d3bed98..d162c4550838a19bb08aca7b9610b388dd653abf 100644 --- a/lib/generated/intl/messages_no.dart +++ b/lib/generated/intl/messages_no.dart @@ -33,6 +33,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Bekreft sletting av konto"), "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( "Ja, jeg ønsker å slette denne kontoen og all dataen dens permanent."), + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "deleteAccount": MessageLookupByLibrary.simpleMessage("Slett konto"), "deleteAccountFeedbackPrompt": MessageLookupByLibrary.simpleMessage( "Vi er lei oss for at du forlater oss. Gi oss gjerne en tilbakemelding så vi kan forbedre oss."), diff --git a/lib/generated/intl/messages_pl.dart b/lib/generated/intl/messages_pl.dart index 6fb8aa6f0c8855c10e9f23010648407d2765929d..7a567715b304a7c5a93869ff5eb796240ee2ac66 100644 --- a/lib/generated/intl/messages_pl.dart +++ b/lib/generated/intl/messages_pl.dart @@ -50,6 +50,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Powtórz hasło"), "contactSupport": MessageLookupByLibrary.simpleMessage( "Skontaktuj się z pomocą techniczną"), + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "continueLabel": MessageLookupByLibrary.simpleMessage("Kontynuuj"), "createAccount": MessageLookupByLibrary.simpleMessage("Stwórz konto"), "createNewAccount": diff --git a/lib/generated/intl/messages_pt.dart b/lib/generated/intl/messages_pt.dart index a873f19d44ed6325558d133e5955a0b3fe82002e..9ddbbd8d933e9b15824825cb03cbc9ea17bed754 100644 --- a/lib/generated/intl/messages_pt.dart +++ b/lib/generated/intl/messages_pt.dart @@ -136,6 +136,7 @@ class MessageLookup extends MessageLookupByLibrary { "Confirme sua chave de recuperação"), "contactSupport": MessageLookupByLibrary.simpleMessage("Falar com o suporte"), + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "continueLabel": MessageLookupByLibrary.simpleMessage("Continuar"), "copypasteThisCodentoYourAuthenticatorApp": MessageLookupByLibrary.simpleMessage( diff --git a/lib/generated/intl/messages_zh.dart b/lib/generated/intl/messages_zh.dart index 1e62fea040fd1b558e6624f4d16bc8072844ab9c..9370da75e5a8326a5c8cd903844f31520bd85f99 100644 --- a/lib/generated/intl/messages_zh.dart +++ b/lib/generated/intl/messages_zh.dart @@ -127,6 +127,9 @@ class MessageLookup extends MessageLookupByLibrary { static String m41(endDate) => "在 ${endDate} 前续费"; + static String m64(count) => + "${Intl.plural(count, other: '已找到 ${count} 个结果')}"; + static String m42(count) => "已选择 ${count} 个"; static String m43(count, yourCount) => "选择了 ${count} 个 (您的 ${yourCount} 个)"; @@ -198,6 +201,7 @@ class MessageLookup extends MessageLookupByLibrary { "addLocation": MessageLookupByLibrary.simpleMessage("添加地点"), "addLocationButton": MessageLookupByLibrary.simpleMessage("添加"), "addMore": MessageLookupByLibrary.simpleMessage("添加更多"), + "addNew": MessageLookupByLibrary.simpleMessage("新建"), "addOnPageSubtitle": MessageLookupByLibrary.simpleMessage("附加组件详情"), "addOns": MessageLookupByLibrary.simpleMessage("附加组件"), "addPhotos": MessageLookupByLibrary.simpleMessage("添加照片"), @@ -206,6 +210,7 @@ class MessageLookup extends MessageLookupByLibrary { "addToEnte": MessageLookupByLibrary.simpleMessage("添加到 ente"), "addToHiddenAlbum": MessageLookupByLibrary.simpleMessage("添加到隐藏相册"), "addViewer": MessageLookupByLibrary.simpleMessage("添加查看者"), + "addYourPhotosNow": MessageLookupByLibrary.simpleMessage("立即添加您的照片"), "addedAs": MessageLookupByLibrary.simpleMessage("已添加为"), "addedBy": m1, "addedSuccessfullyTo": m2, @@ -308,6 +313,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("通过移动数据备份"), "backupSettings": MessageLookupByLibrary.simpleMessage("备份设置"), "backupVideos": MessageLookupByLibrary.simpleMessage("备份视频"), + "blackFridaySale": MessageLookupByLibrary.simpleMessage("黑色星期五特惠"), "blog": MessageLookupByLibrary.simpleMessage("博客"), "cachedData": MessageLookupByLibrary.simpleMessage("缓存数据"), "calculating": MessageLookupByLibrary.simpleMessage("正在计算..."), @@ -374,6 +380,8 @@ class MessageLookup extends MessageLookupByLibrary { "contactFamilyAdmin": m9, "contactSupport": MessageLookupByLibrary.simpleMessage("联系支持"), "contactToManageSubscription": m10, + "contacts": MessageLookupByLibrary.simpleMessage("联系人"), + "contents": MessageLookupByLibrary.simpleMessage("内容"), "continueLabel": MessageLookupByLibrary.simpleMessage("继续"), "continueOnFreeTrial": MessageLookupByLibrary.simpleMessage("继续免费试用"), "convertToAlbum": MessageLookupByLibrary.simpleMessage("转换为相册"), @@ -535,6 +543,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("此链接已过期。请选择新的过期时间或禁用链接过期。"), "exportLogs": MessageLookupByLibrary.simpleMessage("导出日志"), "exportYourData": MessageLookupByLibrary.simpleMessage("导出您的数据"), + "faces": MessageLookupByLibrary.simpleMessage("人脸"), "failedToApplyCode": MessageLookupByLibrary.simpleMessage("无法应用代码"), "failedToCancel": MessageLookupByLibrary.simpleMessage("取消失败"), "failedToDownloadVideo": MessageLookupByLibrary.simpleMessage("视频下载失败"), @@ -558,6 +567,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("无法将文件保存到相册"), "fileInfoAddDescHint": MessageLookupByLibrary.simpleMessage("添加说明..."), "fileSavedToGallery": MessageLookupByLibrary.simpleMessage("文件已保存到相册"), + "fileTypes": MessageLookupByLibrary.simpleMessage("文件类型"), + "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("文件类型和名称"), "filesBackedUpFromDevice": m19, "filesBackedUpInAlbum": m20, "filesDeleted": MessageLookupByLibrary.simpleMessage("文件已删除"), @@ -655,6 +666,7 @@ class MessageLookup extends MessageLookupByLibrary { "linkExpiry": MessageLookupByLibrary.simpleMessage("链接过期"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("链接已过期"), "linkNeverExpires": MessageLookupByLibrary.simpleMessage("永不"), + "livePhotos": MessageLookupByLibrary.simpleMessage("实况照片"), "loadMessage1": MessageLookupByLibrary.simpleMessage("您可以与家庭分享您的订阅"), "loadMessage2": MessageLookupByLibrary.simpleMessage("到目前为止,我们已经保存了1 000多万个回忆"), @@ -710,8 +722,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("移动端, 网页端, 桌面端"), "moderateStrength": MessageLookupByLibrary.simpleMessage("中等"), "modifyYourQueryOrTrySearchingFor": - MessageLookupByLibrary.simpleMessage( - "Modify your query, or try searching for"), + MessageLookupByLibrary.simpleMessage("修改您的查询,或尝试搜索"), + "moments": MessageLookupByLibrary.simpleMessage("瞬间"), "monthly": MessageLookupByLibrary.simpleMessage("每月"), "moveItem": m30, "moveToAlbum": MessageLookupByLibrary.simpleMessage("移动到相册"), @@ -784,8 +796,10 @@ class MessageLookup extends MessageLookupByLibrary { "permanentlyDelete": MessageLookupByLibrary.simpleMessage("永久删除"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage("要从设备中永久删除吗?"), + "photoDescriptions": MessageLookupByLibrary.simpleMessage("照片说明"), "photoGridSize": MessageLookupByLibrary.simpleMessage("照片网格大小"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("照片"), + "photos": MessageLookupByLibrary.simpleMessage("照片"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage("您添加的照片将从相册中移除"), "pickCenterPoint": MessageLookupByLibrary.simpleMessage("选择中心点"), @@ -908,10 +922,29 @@ class MessageLookup extends MessageLookupByLibrary { "scanCode": MessageLookupByLibrary.simpleMessage("扫描代码"), "scanThisBarcodeWithnyourAuthenticatorApp": MessageLookupByLibrary.simpleMessage("用您的身份验证器应用\n扫描此条码"), + "searchAlbumsEmptySection": MessageLookupByLibrary.simpleMessage("相册"), "searchByAlbumNameHint": MessageLookupByLibrary.simpleMessage("相册名称"), "searchByExamples": MessageLookupByLibrary.simpleMessage( "• 相册名称(例如“相机”)\n• 文件类型(例如“视频”、“.gif”)\n• 年份和月份(例如“2022”、“一月”)\n• 假期(例如“圣诞节”)\n• 照片说明(例如“#和女儿独居,好开心啊”)"), + "searchCaptionEmptySection": MessageLookupByLibrary.simpleMessage( + "在照片信息中添加“#旅游”等描述,以便在此处快速找到它们"), + "searchDatesEmptySection": + MessageLookupByLibrary.simpleMessage("按日期搜索,月份或年份"), + "searchFaceEmptySection": + MessageLookupByLibrary.simpleMessage("查找一个人的所有照片"), + "searchFileTypesAndNamesEmptySection": + MessageLookupByLibrary.simpleMessage("文件类型和名称"), + "searchHint1": MessageLookupByLibrary.simpleMessage("在设备上快速搜索"), + "searchHint2": MessageLookupByLibrary.simpleMessage("照片日期、描述"), + "searchHint3": MessageLookupByLibrary.simpleMessage("相册、文件名和类型"), + "searchHint4": MessageLookupByLibrary.simpleMessage("位置"), + "searchHint5": MessageLookupByLibrary.simpleMessage("即将到来:面部和魔法搜索✨"), "searchHintText": MessageLookupByLibrary.simpleMessage("相册,月,日,年,..."), + "searchLocationEmptySection": + MessageLookupByLibrary.simpleMessage("在照片的一定半径内拍摄的几组照片"), + "searchPeopleEmptySection": + MessageLookupByLibrary.simpleMessage("邀请他人,您将在此看到他们分享的所有照片"), + "searchResultCount": m64, "security": MessageLookupByLibrary.simpleMessage("安全"), "selectAlbum": MessageLookupByLibrary.simpleMessage("选择相册"), "selectAll": MessageLookupByLibrary.simpleMessage("全选"), @@ -1113,6 +1146,8 @@ class MessageLookup extends MessageLookupByLibrary { "upgrade": MessageLookupByLibrary.simpleMessage("升级"), "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage("正在将文件上传到相册..."), + "upto50OffUntil4thDec": + MessageLookupByLibrary.simpleMessage("最高五折优惠,直至12月4日。"), "usableReferralStorageInfo": MessageLookupByLibrary.simpleMessage( "可用存储空间受您当前计划的限制。 当您升级您的计划时,超出要求的存储空间将自动变为可用。"), "usePublicLinksForPeopleNotOnEnte": @@ -1133,6 +1168,7 @@ class MessageLookup extends MessageLookupByLibrary { "verifyingRecoveryKey": MessageLookupByLibrary.simpleMessage("正在验证恢复密钥..."), "videoSmallCase": MessageLookupByLibrary.simpleMessage("视频"), + "videos": MessageLookupByLibrary.simpleMessage("视频"), "viewActiveSessions": MessageLookupByLibrary.simpleMessage("查看活动会话"), "viewAddOnButton": MessageLookupByLibrary.simpleMessage("查看附加组件"), "viewAll": MessageLookupByLibrary.simpleMessage("查看全部"), @@ -1178,7 +1214,7 @@ class MessageLookup extends MessageLookupByLibrary { "youHaveSuccessfullyFreedUp": m63, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("您的账户已删除"), - "yourMap": MessageLookupByLibrary.simpleMessage("Your map"), + "yourMap": MessageLookupByLibrary.simpleMessage("您的地图"), "yourPlanWasSuccessfullyDowngraded": MessageLookupByLibrary.simpleMessage("您的计划已成功降级"), "yourPlanWasSuccessfullyUpgraded": diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index 523110e7056d6a21c0835911d7db16e73395878c..1c2421f776e69a09704153aaefaff0540d9d74e6 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -7995,10 +7995,10 @@ class S { ); } - /// `Coming soon: Photo contents, faces` + /// `Coming soon: Faces & magic search ✨` String get searchHint5 { return Intl.message( - 'Coming soon: Photo contents, faces', + 'Coming soon: Faces & magic search ✨', name: 'searchHint5', desc: '', args: [], @@ -8067,6 +8067,26 @@ class S { args: [], ); } + + /// `No internet connection` + String get noInternetConnection { + return Intl.message( + 'No internet connection', + name: 'noInternetConnection', + desc: '', + args: [], + ); + } + + /// `Please check your internet connection and try again.` + String get pleaseCheckYourInternetConnectionAndTryAgain { + return Intl.message( + 'Please check your internet connection and try again.', + name: 'pleaseCheckYourInternetConnectionAndTryAgain', + desc: '', + args: [], + ); + } } class AppLocalizationDelegate extends LocalizationsDelegate { diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index f3fca6a0c5ebe0f4df6cdc6e0ef261e57758269a..92b293cd9a07f13c549bd7efcc648590b7051889 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -1149,5 +1149,7 @@ "@addNew": { "description": "Text to add a new item (location tag, album, caption etc)" }, - "contacts": "Contacts" + "contacts": "Contacts", + "noInternetConnection": "No internet connection", + "pleaseCheckYourInternetConnectionAndTryAgain": "Please check your internet connection and try again." } \ No newline at end of file diff --git a/lib/services/user_service.dart b/lib/services/user_service.dart index 13d085ca2467f6a68b6d3fd7de60029617b91abd..e52a699846469eb930ac0c758374ef4e2d361c97 100644 --- a/lib/services/user_service.dart +++ b/lib/services/user_service.dart @@ -34,11 +34,10 @@ import "package:photos/ui/account/recovery_page.dart"; import 'package:photos/ui/account/two_factor_authentication_page.dart'; import 'package:photos/ui/account/two_factor_recovery_page.dart'; import 'package:photos/ui/account/two_factor_setup_page.dart'; -import "package:photos/ui/components/buttons/button_widget.dart"; +import "package:photos/ui/common/progress_dialog.dart"; import "package:photos/ui/tabs/home_widget.dart"; import 'package:photos/utils/crypto_util.dart'; import 'package:photos/utils/dialog_util.dart'; -import "package:photos/utils/email_util.dart"; import 'package:photos/utils/navigation_util.dart'; import 'package:photos/utils/toast_util.dart'; import "package:pointycastle/export.dart"; @@ -586,120 +585,92 @@ class UserService { BuildContext context, SrpAttributes srpAttributes, String userPassword, + ProgressDialog dialog, ) async { - final dialog = createProgressDialog( - context, - S.of(context).pleaseWait, - isDismissible: true, - ); - await dialog.show(); late Uint8List keyEncryptionKey; - try { - keyEncryptionKey = await CryptoUtil.deriveKey( - utf8.encode(userPassword) as Uint8List, - CryptoUtil.base642bin(srpAttributes.kekSalt), - srpAttributes.memLimit, - srpAttributes.opsLimit, - ); - final loginKey = await CryptoUtil.deriveLoginKey(keyEncryptionKey); - final Uint8List identity = Uint8List.fromList( - utf8.encode(srpAttributes.srpUserID), - ); - final Uint8List salt = base64Decode(srpAttributes.srpSalt); - final Uint8List password = loginKey; - final SecureRandom random = _getSecureRandom(); + _logger.finest('Start deriving key'); + keyEncryptionKey = await CryptoUtil.deriveKey( + utf8.encode(userPassword) as Uint8List, + CryptoUtil.base642bin(srpAttributes.kekSalt), + srpAttributes.memLimit, + srpAttributes.opsLimit, + ); + _logger.finest('keyDerivation done, derive LoginKey'); + final loginKey = await CryptoUtil.deriveLoginKey(keyEncryptionKey); + final Uint8List identity = Uint8List.fromList( + utf8.encode(srpAttributes.srpUserID), + ); + _logger.finest('longinKey derivation done'); + final Uint8List salt = base64Decode(srpAttributes.srpSalt); + final Uint8List password = loginKey; + final SecureRandom random = _getSecureRandom(); - final client = SRP6Client( - group: kDefaultSrpGroup, - digest: Digest('SHA-256'), - random: random, - ); + final client = SRP6Client( + group: kDefaultSrpGroup, + digest: Digest('SHA-256'), + random: random, + ); - final A = client.generateClientCredentials(salt, identity, password); - final createSessionResponse = await _dio.post( - _config.getHttpEndpoint() + "/users/srp/create-session", - data: { - "srpUserID": srpAttributes.srpUserID, - "srpA": base64Encode(SRP6Util.encodeBigInt(A!)), - }, - ); - final String sessionID = createSessionResponse.data["sessionID"]; - final String srpB = createSessionResponse.data["srpB"]; + final A = client.generateClientCredentials(salt, identity, password); + final createSessionResponse = await _dio.post( + _config.getHttpEndpoint() + "/users/srp/create-session", + data: { + "srpUserID": srpAttributes.srpUserID, + "srpA": base64Encode(SRP6Util.encodeBigInt(A!)), + }, + ); + final String sessionID = createSessionResponse.data["sessionID"]; + final String srpB = createSessionResponse.data["srpB"]; - final serverB = SRP6Util.decodeBigInt(base64Decode(srpB)); - // ignore: need to calculate secret to get M1, unused_local_variable - final clientS = client.calculateSecret(serverB); - final clientM = client.calculateClientEvidenceMessage(); - final response = await _dio.post( - _config.getHttpEndpoint() + "/users/srp/verify-session", - data: { - "sessionID": sessionID, - "srpUserID": srpAttributes.srpUserID, - "srpM1": base64Encode(SRP6Util.encodeBigInt(clientM!)), - }, - ); - if (response.statusCode == 200) { - Widget page; - final String twoFASessionID = response.data["twoFactorSessionID"]; - Configuration.instance.setVolatilePassword(userPassword); - if (twoFASessionID.isNotEmpty) { - setTwoFactor(value: true); - page = TwoFactorAuthenticationPage(twoFASessionID); - } else { - await _saveConfiguration(response); - if (Configuration.instance.getEncryptedToken() != null) { - await Configuration.instance.decryptSecretsAndGetKeyEncKey( - userPassword, - Configuration.instance.getKeyAttributes()!, - keyEncryptionKey: keyEncryptionKey, - ); - page = const HomeWidget(); - } else { - throw Exception("unexpected response during email verification"); - } - } - await dialog.hide(); - if (page is HomeWidget) { - Navigator.of(context).popUntil((route) => route.isFirst); - Bus.instance.fire(AccountConfiguredEvent()); - } else { - Navigator.of(context).pushAndRemoveUntil( - MaterialPageRoute( - builder: (BuildContext context) { - return page; - }, - ), - (route) => route.isFirst, + final serverB = SRP6Util.decodeBigInt(base64Decode(srpB)); + // ignore: need to calculate secret to get M1, unused_local_variable + final clientS = client.calculateSecret(serverB); + final clientM = client.calculateClientEvidenceMessage(); + final response = await _dio.post( + _config.getHttpEndpoint() + "/users/srp/verify-session", + data: { + "sessionID": sessionID, + "srpUserID": srpAttributes.srpUserID, + "srpM1": base64Encode(SRP6Util.encodeBigInt(clientM!)), + }, + ); + if (response.statusCode == 200) { + Widget page; + final String twoFASessionID = response.data["twoFactorSessionID"]; + Configuration.instance.setVolatilePassword(userPassword); + if (twoFASessionID.isNotEmpty) { + setTwoFactor(value: true); + page = TwoFactorAuthenticationPage(twoFASessionID); + } else { + await _saveConfiguration(response); + if (Configuration.instance.getEncryptedToken() != null) { + await Configuration.instance.decryptSecretsAndGetKeyEncKey( + userPassword, + Configuration.instance.getKeyAttributes()!, + keyEncryptionKey: keyEncryptionKey, ); + page = const HomeWidget(); + } else { + throw Exception("unexpected response during email verification"); } - } else { - // should never reach here - throw Exception("unexpected response during email verification"); } - } on DioError catch (e, s) { await dialog.hide(); - if (e.response != null && e.response!.statusCode == 401) { - await _showContactSupportDialog( - context, - S.of(context).incorrectPasswordTitle, - S.of(context).pleaseTryAgain, - ); + if (page is HomeWidget) { + Navigator.of(context).popUntil((route) => route.isFirst); + Bus.instance.fire(AccountConfiguredEvent()); } else { - _logger.severe('failed to verify password', e, s); - await _showContactSupportDialog( - context, - S.of(context).oops, - S.of(context).verificationFailedPleaseTryAgain, + Navigator.of(context).pushAndRemoveUntil( + MaterialPageRoute( + builder: (BuildContext context) { + return page; + }, + ), + (route) => route.isFirst, ); } - } catch (e, s) { - _logger.severe('failed to verify password', e, s); - await dialog.hide(); - await _showContactSupportDialog( - context, - S.of(context).oops, - S.of(context).verificationFailedPleaseTryAgain, - ); + } else { + // should never reach here + throw Exception("unexpected response during email verification"); } } @@ -1164,26 +1135,4 @@ class UserService { rethrow; } } - - Future _showContactSupportDialog( - BuildContext context, - String title, - String message, - ) async { - final dialogChoice = await showChoiceDialog( - context, - title: title, - body: message, - firstButtonLabel: S.of(context).contactSupport, - secondButtonLabel: S.of(context).ok, - ); - if (dialogChoice!.action == ButtonAction.first) { - await sendLogs( - context, - S.of(context).contactSupport, - "support@ente.io", - postShare: () {}, - ); - } - } } diff --git a/lib/ui/account/login_pwd_verification_page.dart b/lib/ui/account/login_pwd_verification_page.dart index f29827a31f070f7f0f8748f437a81b6f7941e0e7..e643b9b25e082b5af08024e2200345bb3a92f77c 100644 --- a/lib/ui/account/login_pwd_verification_page.dart +++ b/lib/ui/account/login_pwd_verification_page.dart @@ -1,12 +1,17 @@ +import "package:dio/dio.dart"; import "package:flutter/foundation.dart"; import 'package:flutter/material.dart'; +import "package:logging/logging.dart"; import 'package:photos/core/configuration.dart'; +import "package:photos/core/errors.dart"; import "package:photos/generated/l10n.dart"; import "package:photos/models/api/user/srp.dart"; import "package:photos/services/user_service.dart"; import "package:photos/theme/ente_theme.dart"; import 'package:photos/ui/common/dynamic_fab.dart'; +import "package:photos/ui/components/buttons/button_widget.dart"; import "package:photos/utils/dialog_util.dart"; +import "package:photos/utils/email_util.dart"; // LoginPasswordVerificationPage is a page that allows the user to enter their password to verify their identity. // If the password is correct, then the user is either directed to @@ -31,6 +36,7 @@ class _LoginPasswordVerificationPageState String? email; bool _passwordInFocus = false; bool _passwordVisible = false; + final Logger _logger = Logger("LoginPasswordVerificationPage"); @override void initState() { @@ -85,11 +91,7 @@ class _LoginPasswordVerificationPageState buttonText: S.of(context).logInLabel, onPressedFunction: () async { FocusScope.of(context).unfocus(); - await UserService.instance.verifyEmailViaPassword( - context, - widget.srpAttributes, - _passwordController.text, - ); + await verifyPassword(context, _passwordController.text); }, ), floatingActionButtonLocation: fabLocation(), @@ -97,6 +99,94 @@ class _LoginPasswordVerificationPageState ); } + Future verifyPassword(BuildContext context, String password) async { + final dialog = createProgressDialog( + context, + S.of(context).pleaseWait, + isDismissible: true, + ); + await dialog.show(); + try { + await UserService.instance.verifyEmailViaPassword( + context, + widget.srpAttributes, + password, + dialog, + ); + } on DioError catch (e, s) { + await dialog.hide(); + if (e.response != null && e.response!.statusCode == 401) { + _logger.severe('server reject, failed verify SRP login', e, s); + await _showContactSupportDialog( + context, + S.of(context).incorrectPasswordTitle, + S.of(context).pleaseTryAgain, + ); + } else { + _logger.severe('API failure during SRP login', e, s); + if (e.type == DioErrorType.other) { + await _showContactSupportDialog( + context, + S.of(context).noInternetConnection, + S.of(context).pleaseCheckYourInternetConnectionAndTryAgain, + ); + } else { + await _showContactSupportDialog( + context, + S.of(context).somethingWentWrong, + S.of(context).verificationFailedPleaseTryAgain, + ); + } + } + } catch (e, s) { + _logger.severe('error while verifying password', e, s); + await dialog.hide(); + if (e is KeyDerivationError || e is LoginKeyDerivationError) { + final dialogChoice = await showChoiceDialog( + context, + title: S.of(context).recreatePasswordTitle, + body: S.of(context).recreatePasswordBody, + firstButtonLabel: S.of(context).useRecoveryKey, + ); + if (dialogChoice!.action == ButtonAction.first) { + await UserService.instance.sendOtt( + context, + email!, + isResetPasswordScreen: true, + ); + } + return; + } + await _showContactSupportDialog( + context, + S.of(context).oops, + S.of(context).verificationFailedPleaseTryAgain, + ); + } + } + + Future _showContactSupportDialog( + BuildContext context, + String title, + String message, + ) async { + final dialogChoice = await showChoiceDialog( + context, + title: title, + body: message, + firstButtonLabel: S.of(context).contactSupport, + secondButtonLabel: S.of(context).ok, + ); + if (dialogChoice!.action == ButtonAction.first) { + await sendLogs( + context, + S.of(context).contactSupport, + "support@ente.io", + postShare: () {}, + ); + } + } + Widget _getBody() { return Column( children: [ diff --git a/lib/utils/crypto_util.dart b/lib/utils/crypto_util.dart index c2f02b59bfa202187a2a4bf5044bcb96394979ae..3c6be311b38a8c0c913836df2f80c0d8bc87d4ad 100644 --- a/lib/utils/crypto_util.dart +++ b/lib/utils/crypto_util.dart @@ -77,7 +77,7 @@ Future cryptoGenericHash(Map args) async { EncryptionResult chachaEncryptData(Map args) { final initPushResult = - Sodium.cryptoSecretstreamXchacha20poly1305InitPush(args["key"]); + Sodium.cryptoSecretstreamXchacha20poly1305InitPush(args["key"]); final encryptedData = Sodium.cryptoSecretstreamXchacha20poly1305Push( initPushResult.state, args["source"], @@ -102,7 +102,7 @@ Future chachaEncryptFile(Map args) async { final inputFile = sourceFile.openSync(mode: FileMode.read); final key = args["key"] ?? Sodium.cryptoSecretstreamXchacha20poly1305Keygen(); final initPushResult = - Sodium.cryptoSecretstreamXchacha20poly1305InitPush(key); + Sodium.cryptoSecretstreamXchacha20poly1305InitPush(key); var bytesRead = 0; var tag = Sodium.cryptoSecretstreamXchacha20poly1305TagMessage; while (tag != Sodium.cryptoSecretstreamXchacha20poly1305TagFinal) { @@ -156,7 +156,7 @@ Future chachaDecryptFile(Map args) async { final buffer = await inputFile.read(chunkSize); bytesRead += chunkSize; final pullResult = - Sodium.cryptoSecretstreamXchacha20poly1305Pull(pullState, buffer, null); + Sodium.cryptoSecretstreamXchacha20poly1305Pull(pullState, buffer, null); await destinationFile.writeAsBytes(pullResult.m, mode: FileMode.append); tag = pullResult.tag; } @@ -190,20 +190,22 @@ class CryptoUtil { Sodium.init(); } - static Uint8List base642bin(String b64, { + static Uint8List base642bin( + String b64, { String? ignore, int variant = Sodium.base64VariantOriginal, }) { return Sodium.base642bin(b64, ignore: ignore, variant: variant); } - static String bin2base64(Uint8List bin, { + static String bin2base64( + Uint8List bin, { bool urlSafe = false, }) { return Sodium.bin2base64( bin, variant: - urlSafe ? Sodium.base64VariantUrlsafe : Sodium.base64VariantOriginal, + urlSafe ? Sodium.base64VariantUrlsafe : Sodium.base64VariantOriginal, ); } @@ -237,9 +239,11 @@ class CryptoUtil { // Decrypts the given cipher, with the given key and nonce using XSalsa20 // (w Poly1305 MAC). - static Future decrypt(Uint8List cipher, - Uint8List key, - Uint8List nonce,) async { + static Future decrypt( + Uint8List cipher, + Uint8List key, + Uint8List nonce, + ) async { final args = {}; args["cipher"] = cipher; args["nonce"] = nonce; @@ -256,9 +260,11 @@ class CryptoUtil { // This function runs on the same thread as the caller, so should be used only // for small amounts of data where thread switching can result in a degraded // user experience - static Uint8List decryptSync(Uint8List cipher, - Uint8List key, - Uint8List nonce,) { + static Uint8List decryptSync( + Uint8List cipher, + Uint8List key, + Uint8List nonce, + ) { final args = {}; args["cipher"] = cipher; args["nonce"] = nonce; @@ -270,8 +276,10 @@ class CryptoUtil { // nonce, using XChaCha20 (w Poly1305 MAC). // This function runs on the isolate pool held by `_computer`. // TODO: Remove "ChaCha", an implementation detail from the function name - static Future encryptChaCha(Uint8List source, - Uint8List key,) async { + static Future encryptChaCha( + Uint8List source, + Uint8List key, + ) async { final args = {}; args["source"] = source; args["key"] = key; @@ -285,9 +293,11 @@ class CryptoUtil { // Decrypts the given source, with the given key and header using XChaCha20 // (w Poly1305 MAC). // TODO: Remove "ChaCha", an implementation detail from the function name - static Future decryptChaCha(Uint8List source, - Uint8List key, - Uint8List header,) async { + static Future decryptChaCha( + Uint8List source, + Uint8List key, + Uint8List header, + ) async { final args = {}; args["source"] = source; args["key"] = key; @@ -304,10 +314,10 @@ class CryptoUtil { // to the destinationFilePath. // If a key is not provided, one is generated and returned. static Future encryptFile( - String sourceFilePath, - String destinationFilePath, { - Uint8List? key, - }) { + String sourceFilePath, + String destinationFilePath, { + Uint8List? key, + }) { final args = {}; args["sourceFilePath"] = sourceFilePath; args["destinationFilePath"] = destinationFilePath; @@ -322,10 +332,11 @@ class CryptoUtil { // Decrypts the file at sourceFilePath, with the given key and header using // XChaCha20 (w Poly1305 MAC), and writes it to the destinationFilePath. static Future decryptFile( - String sourceFilePath, - String destinationFilePath, - Uint8List header, - Uint8List key,) { + String sourceFilePath, + String destinationFilePath, + Uint8List header, + Uint8List key, + ) { final args = {}; args["sourceFilePath"] = sourceFilePath; args["destinationFilePath"] = destinationFilePath; @@ -356,10 +367,10 @@ class CryptoUtil { // Decrypts the input using the given publicKey-secretKey pair static Uint8List openSealSync( - Uint8List input, - Uint8List publicKey, - Uint8List secretKey, - ) { + Uint8List input, + Uint8List publicKey, + Uint8List secretKey, + ) { return Sodium.cryptoBoxSealOpen(input, publicKey, secretKey); } @@ -377,9 +388,9 @@ class CryptoUtil { // At all points, we ensure that the product of these two variables (the area // under the graph that determines the amount of work required) is a constant. static Future deriveSensitiveKey( - Uint8List password, - Uint8List salt, - ) async { + Uint8List password, + Uint8List salt, + ) async { final logger = Logger("pwhash"); int memLimit = Sodium.cryptoPwhashMemlimitSensitive; int opsLimit = Sodium.cryptoPwhashOpslimitSensitive; @@ -407,7 +418,10 @@ class CryptoUtil { return DerivedKeyResult(key, memLimit, opsLimit); } catch (e, s) { logger.warning( - "failed to deriveKey mem: $memLimit, ops: $opsLimit", e, s,); + "failed to deriveKey mem: $memLimit, ops: $opsLimit", + e, + s, + ); } memLimit = (memLimit / 2).round(); opsLimit = opsLimit * 2; @@ -421,9 +435,9 @@ class CryptoUtil { // extra layer of authentication (atop the access token and collection key). // More details @ https://ente.io/blog/building-shareable-links/ static Future deriveInteractiveKey( - Uint8List password, - Uint8List salt, - ) async { + Uint8List password, + Uint8List salt, + ) async { final int memLimit = Sodium.cryptoPwhashMemlimitInteractive; final int opsLimit = Sodium.cryptoPwhashOpslimitInteractive; final key = await deriveKey(password, salt, memLimit, opsLimit); @@ -433,23 +447,23 @@ class CryptoUtil { // Derives a key for a given password, salt, memLimit and opsLimit using // Argon2id, v1.3. static Future deriveKey( - Uint8List password, - Uint8List salt, - int memLimit, - int opsLimit, - ) { + Uint8List password, + Uint8List salt, + int memLimit, + int opsLimit, + ) { try { - return _computer.compute( - cryptoPwHash, - param: { - "password": password, - "salt": salt, - "memLimit": memLimit, - "opsLimit": opsLimit, - }, - taskName: "deriveKey", - ); - } catch(e,s) { + return _computer.compute( + cryptoPwHash, + param: { + "password": password, + "salt": salt, + "memLimit": memLimit, + "opsLimit": opsLimit, + }, + taskName: "deriveKey", + ); + } catch (e, s) { final String errMessage = 'failed to deriveKey memLimit: $memLimit and ' 'opsLimit: $opsLimit'; Logger("CryptoUtilDeriveKey").warning(errMessage, e, s); @@ -461,20 +475,25 @@ class CryptoUtil { // (Key Derivation Function) with the `loginSubKeyId` and // `loginSubKeyLen` and `loginSubKeyContext` as context static Future deriveLoginKey( - Uint8List key, - ) async { - final Uint8List derivedKey = await _computer.compute( - cryptoKdfDeriveFromKey, - param: { - "key": key, - "subkeyId": loginSubKeyId, - "subkeyLen": loginSubKeyLen, - "context": utf8.encode(loginSubKeyContext), - }, - taskName: "deriveLoginKey", - ); - // return the first 16 bytes of the derived key - return derivedKey.sublist(0, 16); + Uint8List key, + ) async { + try { + final Uint8List derivedKey = await _computer.compute( + cryptoKdfDeriveFromKey, + param: { + "key": key, + "subkeyId": loginSubKeyId, + "subkeyLen": loginSubKeyLen, + "context": utf8.encode(loginSubKeyContext), + }, + taskName: "deriveLoginKey", + ); + // return the first 16 bytes of the derived key + return derivedKey.sublist(0, 16); + } catch (e, s) { + Logger("deriveLoginKey").severe("loginKeyDerivation failed", e, s); + throw LoginKeyDerivationError(); + } } // Computes and returns the hash of the source file From 1da9cd6f355f30ee3b4d971e2c730a437e61a61e Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Mon, 20 Nov 2023 13:50:25 +0530 Subject: [PATCH 02/10] Trigger regular login when loginKey derivation fails --- .../account/login_pwd_verification_page.dart | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/lib/ui/account/login_pwd_verification_page.dart b/lib/ui/account/login_pwd_verification_page.dart index e643b9b25e082b5af08024e2200345bb3a92f77c..a253b1585a37f3f016118fd33a6d6015f18f7cbe 100644 --- a/lib/ui/account/login_pwd_verification_page.dart +++ b/lib/ui/account/login_pwd_verification_page.dart @@ -139,9 +139,19 @@ class _LoginPasswordVerificationPageState } } } catch (e, s) { - _logger.severe('error while verifying password', e, s); + _logger.info('error during loginViaPassword', e); await dialog.hide(); - if (e is KeyDerivationError || e is LoginKeyDerivationError) { + if (e is LoginKeyDerivationError) { + _logger.severe('loginKey derivation error', e, s); + // LoginKey err, perform regular login via ott verification + await UserService.instance.sendOtt( + context, + email!, + isCreateAccountScreen: true, + ); + return; + } else if (e is KeyDerivationError) { + // device is not powerful enough to perform derive key final dialogChoice = await showChoiceDialog( context, title: S.of(context).recreatePasswordTitle, @@ -156,12 +166,14 @@ class _LoginPasswordVerificationPageState ); } return; + } else { + _logger.severe('unexpected error while verifying password', e, s); + await _showContactSupportDialog( + context, + S.of(context).oops, + S.of(context).verificationFailedPleaseTryAgain, + ); } - await _showContactSupportDialog( - context, - S.of(context).oops, - S.of(context).verificationFailedPleaseTryAgain, - ); } } From f25a4e59b4a9a210407e8a169283c001cb2d3c44 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Mon, 20 Nov 2023 14:27:01 +0530 Subject: [PATCH 03/10] fix: archived files which are not part of an archived album were coming up in moments --- lib/db/files_db.dart | 3 +++ lib/services/memories_service.dart | 2 ++ 2 files changed, 5 insertions(+) diff --git a/lib/db/files_db.dart b/lib/db/files_db.dart index 8f6c7a6b7db225bb493208bf9413bac3bc60d0ec..bf5b5991c2a77af9ce922aa50ba52a40978629c7 100644 --- a/lib/db/files_db.dart +++ b/lib/db/files_db.dart @@ -699,6 +699,7 @@ class FilesDB { Future> getFilesCreatedWithinDurations( List> durations, Set ignoredCollectionIDs, { + int? visibility, String order = 'ASC', }) async { if (durations.isEmpty) { @@ -714,6 +715,8 @@ class FilesDB { ")"; if (index != durations.length - 1) { whereClause += " OR "; + } else if (visibility != null) { + whereClause += ' AND $columnMMdVisibility = $visibility'; } } whereClause += ")"; diff --git a/lib/services/memories_service.dart b/lib/services/memories_service.dart index 1b6cbf47629525b22965f1abf0d530d51263bbd3..2bfefcb2f86a1a70425a77548bf7b709cf53db7e 100644 --- a/lib/services/memories_service.dart +++ b/lib/services/memories_service.dart @@ -8,6 +8,7 @@ import "package:photos/events/files_updated_event.dart"; import "package:photos/events/memories_setting_changed.dart"; import 'package:photos/models/filters/important_items_filter.dart'; import 'package:photos/models/memory.dart'; +import "package:photos/models/metadata/common_keys.dart"; import 'package:photos/services/collections_service.dart'; import "package:shared_preferences/shared_preferences.dart"; @@ -108,6 +109,7 @@ class MemoriesService extends ChangeNotifier { final files = await _filesDB.getFilesCreatedWithinDurations( durations, ignoredCollections, + visibility: visibleVisibility, ); final seenTimes = await _memoriesDB.getSeenTimes(); final List memories = []; From 6af7140be55124a3800e65540036572681f8f508 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Mon, 20 Nov 2023 17:06:11 +0530 Subject: [PATCH 04/10] Port lock screen fixes from auth --- lib/ui/tools/lock_screen.dart | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/lib/ui/tools/lock_screen.dart b/lib/ui/tools/lock_screen.dart index 781700b62d00736b71ba3e84734838c12cec7f09..6b34fda4f578a50135c3e18f9994526fe68bf18c 100644 --- a/lib/ui/tools/lock_screen.dart +++ b/lib/ui/tools/lock_screen.dart @@ -1,6 +1,8 @@ +import "dart:io"; + import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; -import "package:photos/generated/l10n.dart"; +import "package:photos/l10n/l10n.dart"; import 'package:photos/ui/common/gradient_button.dart'; import 'package:photos/ui/tools/app_lock.dart'; import 'package:photos/utils/auth_util.dart'; @@ -21,10 +23,16 @@ class _LockScreenState extends State with WidgetsBindingObserver { @override void initState() { - _logger.info("initState"); + _logger.info("initiatingState"); super.initState(); - _showLockScreen(source: "initState"); WidgetsBinding.instance.addObserver(this); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + if (isNonMobileIOSDevice()) { + _logger.info('ignore init for non mobile iOS device'); + return; + } + _showLockScreen(source: "postFrameInit"); + }); } @override @@ -45,7 +53,7 @@ class _LockScreenState extends State with WidgetsBindingObserver { SizedBox( width: 180, child: GradientButton( - text: S.of(context).unlock, + text: context.l10n.unlock, iconData: Icons.lock_open_outlined, onTap: () async { _showLockScreen(source: "tapUnlock"); @@ -60,6 +68,14 @@ class _LockScreenState extends State with WidgetsBindingObserver { ); } + bool isNonMobileIOSDevice() { + if (Platform.isAndroid) { + return false; + } + var shortestSide = MediaQuery.of(context).size.shortestSide; + return shortestSide > 600 ? true : false; + } + @override void didChangeAppLifecycleState(AppLifecycleState state) { _logger.info(state.toString()); @@ -73,7 +89,10 @@ class _LockScreenState extends State with WidgetsBindingObserver { if (!_hasAuthenticationFailed && !didAuthInLast5Seconds) { // Show the lock screen again only if the app is resuming from the // background, and not when the lock screen was explicitly dismissed - _showLockScreen(source: "lifeCycle"); + Future.delayed( + Duration.zero, + () => _showLockScreen(source: "lifeCycle"), + ); } else { _hasAuthenticationFailed = false; // Reset failure state } @@ -90,6 +109,7 @@ class _LockScreenState extends State with WidgetsBindingObserver { @override void dispose() { + _logger.info('disposing'); WidgetsBinding.instance.removeObserver(this); super.dispose(); } @@ -101,7 +121,7 @@ class _LockScreenState extends State with WidgetsBindingObserver { _isShowingLockScreen = true; final result = await requestAuthentication( context, - S.of(context).authToViewYourMemories, + context.l10n.authToViewYourMemories, ); _logger.finest("LockScreen Result $result $id"); _isShowingLockScreen = false; @@ -117,6 +137,7 @@ class _LockScreenState extends State with WidgetsBindingObserver { } } } catch (e, s) { + _isShowingLockScreen = false; _logger.severe(e, s); } } From 48400bc4e7306c6fef8c5088bdaa0553885c67c8 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Mon, 20 Nov 2023 12:20:24 +0000 Subject: [PATCH 05/10] New Crowdin translations by GitHub Action --- lib/l10n/intl_zh.arb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index 5478e9c8b063c0af1d41bedd7f6f52fdff1e7201..948b143c322361f6c9727fa873f26655e283584b 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -1149,5 +1149,7 @@ "@addNew": { "description": "Text to add a new item (location tag, album, caption etc)" }, - "contacts": "联系人" + "contacts": "联系人", + "noInternetConnection": "无互联网连接", + "pleaseCheckYourInternetConnectionAndTryAgain": "请检查您的互联网连接,然后重试。" } \ No newline at end of file From 81079ac7dcb3b87c1547014597ed93843881cce4 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Mon, 20 Nov 2023 18:40:57 +0530 Subject: [PATCH 06/10] Show add-on validity on sub page --- lib/generated/intl/messages_cs.dart | 1 + lib/generated/intl/messages_de.dart | 1 + lib/generated/intl/messages_en.dart | 16 +++-- lib/generated/intl/messages_es.dart | 1 + lib/generated/intl/messages_fr.dart | 66 +++++++++++++++++-- lib/generated/intl/messages_it.dart | 5 +- lib/generated/intl/messages_ko.dart | 1 + lib/generated/intl/messages_nl.dart | 1 + lib/generated/intl/messages_no.dart | 1 + lib/generated/intl/messages_pl.dart | 1 + lib/generated/intl/messages_pt.dart | 1 + lib/generated/intl/messages_zh.dart | 46 +++++++++++-- lib/generated/l10n.dart | 14 +++- lib/l10n/intl_en.arb | 1 + lib/ui/payment/store_subscription_page.dart | 2 +- lib/ui/payment/stripe_subscription_page.dart | 2 +- .../payment/subscription_common_widgets.dart | 47 +++++++++++-- 17 files changed, 182 insertions(+), 25 deletions(-) diff --git a/lib/generated/intl/messages_cs.dart b/lib/generated/intl/messages_cs.dart index 815bedb4acdeddc6fc43d2db938c2c0cfdb54e33..a0b3b9f7d94395163d0ad789e17517d3b288b4a9 100644 --- a/lib/generated/intl/messages_cs.dart +++ b/lib/generated/intl/messages_cs.dart @@ -24,6 +24,7 @@ class MessageLookup extends MessageLookupByLibrary { static Map _notInlinedMessages(_) => { "addToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Add to hidden album"), + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "deleteConfirmDialogBody": MessageLookupByLibrary.simpleMessage( "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted."), "fileTypes": MessageLookupByLibrary.simpleMessage("File types"), diff --git a/lib/generated/intl/messages_de.dart b/lib/generated/intl/messages_de.dart index 1c31ebad29150c417ded9dd25404196fd42a5983..1b935485f22a99fd8c899c8d823015af61edd5fd 100644 --- a/lib/generated/intl/messages_de.dart +++ b/lib/generated/intl/messages_de.dart @@ -442,6 +442,7 @@ class MessageLookup extends MessageLookupByLibrary { "contactSupport": MessageLookupByLibrary.simpleMessage("Support kontaktieren"), "contactToManageSubscription": m10, + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "continueLabel": MessageLookupByLibrary.simpleMessage("Weiter"), "continueOnFreeTrial": MessageLookupByLibrary.simpleMessage( "Mit kostenloser Testversion fortfahren"), diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index 5cbdf629e98ab2bbcff844887a0978fd965a8816..726f34076907cc9e875fef102c5ec4806b91b7dc 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -23,6 +23,9 @@ class MessageLookup extends MessageLookupByLibrary { static String m0(count) => "${Intl.plural(count, one: 'Add item', other: 'Add items')}"; + static String m64(storageAmount, endDate) => + "Your ${storageAmount} add-on is valid till ${endDate}"; + static String m1(emailOrName) => "Added by ${emailOrName}"; static String m2(albumName) => "Added successfully to ${albumName}"; @@ -137,7 +140,7 @@ class MessageLookup extends MessageLookupByLibrary { static String m41(endDate) => "Renews on ${endDate}"; - static String m64(count) => + static String m65(count) => "${Intl.plural(count, one: '${count} result found', other: '${count} results found')}"; static String m42(count) => "${count} selected"; @@ -190,7 +193,7 @@ class MessageLookup extends MessageLookupByLibrary { static String m59(count) => "${Intl.plural(count, zero: '', one: '1 day', other: '${count} days')}"; - static String m65(endDate) => "Valid till ${endDate}"; + static String m66(endDate) => "Valid till ${endDate}"; static String m60(email) => "Verify ${email}"; @@ -226,6 +229,7 @@ class MessageLookup extends MessageLookupByLibrary { "addNew": MessageLookupByLibrary.simpleMessage("Add new"), "addOnPageSubtitle": MessageLookupByLibrary.simpleMessage("Details of add-ons"), + "addOnValidTill": m64, "addOns": MessageLookupByLibrary.simpleMessage("Add-ons"), "addPhotos": MessageLookupByLibrary.simpleMessage("Add photos"), "addSelected": MessageLookupByLibrary.simpleMessage("Add selected"), @@ -441,6 +445,7 @@ class MessageLookup extends MessageLookupByLibrary { "contactSupport": MessageLookupByLibrary.simpleMessage("Contact support"), "contactToManageSubscription": m10, + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "contents": MessageLookupByLibrary.simpleMessage("Contents"), "continueLabel": MessageLookupByLibrary.simpleMessage("Continue"), "continueOnFreeTrial": @@ -926,7 +931,6 @@ class MessageLookup extends MessageLookupByLibrary { "paymentFailedTalkToProvider": m33, "paymentFailedWithReason": m34, "pendingSync": MessageLookupByLibrary.simpleMessage("Pending sync"), - "people": MessageLookupByLibrary.simpleMessage("People"), "peopleUsingYourCode": MessageLookupByLibrary.simpleMessage("People using your code"), "permDeleteWarning": MessageLookupByLibrary.simpleMessage( @@ -1120,14 +1124,14 @@ class MessageLookup extends MessageLookupByLibrary { "Albums, file names, and types"), "searchHint4": MessageLookupByLibrary.simpleMessage("Location"), "searchHint5": MessageLookupByLibrary.simpleMessage( - "Coming soon: Photo contents, faces"), + "Coming soon: Faces & magic search ✨"), "searchHintText": MessageLookupByLibrary.simpleMessage( "Albums, months, days, years, ..."), "searchLocationEmptySection": MessageLookupByLibrary.simpleMessage( "Group photos that are taken within some radius of a photo"), "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage( "Invite people, and you\'ll see all photos shared by them here"), - "searchResultCount": m64, + "searchResultCount": m65, "security": MessageLookupByLibrary.simpleMessage("Security"), "selectAlbum": MessageLookupByLibrary.simpleMessage("Select album"), "selectAll": MessageLookupByLibrary.simpleMessage("Select all"), @@ -1376,7 +1380,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("Use selected photo"), "usedSpace": MessageLookupByLibrary.simpleMessage("Used space"), - "validTill": m65, + "validTill": m66, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Verification failed, please try again"), diff --git a/lib/generated/intl/messages_es.dart b/lib/generated/intl/messages_es.dart index 9d6829d71d8e49e4bb84118354e0a257c28b8d00..49927717532088d93f29383350013d3cbb4bf616 100644 --- a/lib/generated/intl/messages_es.dart +++ b/lib/generated/intl/messages_es.dart @@ -398,6 +398,7 @@ class MessageLookup extends MessageLookupByLibrary { "contactSupport": MessageLookupByLibrary.simpleMessage("Contactar con soporte"), "contactToManageSubscription": m10, + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "continueLabel": MessageLookupByLibrary.simpleMessage("Continuar"), "continueOnFreeTrial": MessageLookupByLibrary.simpleMessage( "Continuar con el plan gratuito"), diff --git a/lib/generated/intl/messages_fr.dart b/lib/generated/intl/messages_fr.dart index 264b5dd967358354d98ce97ac6abcf5759801075..4a76e7b4ec0ebbb60c53dba851f56cb958a9ede3 100644 --- a/lib/generated/intl/messages_fr.dart +++ b/lib/generated/intl/messages_fr.dart @@ -140,6 +140,9 @@ class MessageLookup extends MessageLookupByLibrary { static String m41(endDate) => "Renouvellement le ${endDate}"; + static String m65(count) => + "${Intl.plural(count, one: '${count} résultat trouvé', other: '${count} résultats trouvés')}"; + static String m42(count) => "${count} sélectionné(s)"; static String m43(count, yourCount) => @@ -189,6 +192,8 @@ class MessageLookup extends MessageLookupByLibrary { static String m59(count) => "${Intl.plural(count, zero: '0 jour', one: '1 jour', other: '${count} jours')}"; + static String m66(endDate) => "Valable jusqu\'au ${endDate}"; + static String m60(email) => "Vérifier ${email}"; static String m61(email) => @@ -223,6 +228,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ajouter la localisation"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Ajouter"), "addMore": MessageLookupByLibrary.simpleMessage("Ajouter Plus"), + "addNew": MessageLookupByLibrary.simpleMessage("Ajouter un nouveau"), + "addOnPageSubtitle": MessageLookupByLibrary.simpleMessage( + "Détails des modules complémentaires"), + "addOns": + MessageLookupByLibrary.simpleMessage("Modules complémentaires"), "addPhotos": MessageLookupByLibrary.simpleMessage("Ajouter des photos"), "addSelected": MessageLookupByLibrary.simpleMessage("Ajouter la sélection"), @@ -233,6 +243,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ajouter à un album masqué"), "addViewer": MessageLookupByLibrary.simpleMessage("Ajouter un observateur"), + "addYourPhotosNow": MessageLookupByLibrary.simpleMessage( + "Ajoutez vos photos maintenant"), "addedAs": MessageLookupByLibrary.simpleMessage("Ajouté comme"), "addedBy": m1, "addedSuccessfullyTo": m2, @@ -356,6 +368,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Paramètres de la sauvegarde"), "backupVideos": MessageLookupByLibrary.simpleMessage("Sauvegarde des vidéos"), + "blackFridaySale": + MessageLookupByLibrary.simpleMessage("Offre Black Friday"), "blog": MessageLookupByLibrary.simpleMessage("Blog"), "cachedData": MessageLookupByLibrary.simpleMessage("Données mises en cache"), @@ -446,6 +460,8 @@ class MessageLookup extends MessageLookupByLibrary { "contactSupport": MessageLookupByLibrary.simpleMessage("Contacter l\'assistance"), "contactToManageSubscription": m10, + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), + "contents": MessageLookupByLibrary.simpleMessage("Contenus"), "continueLabel": MessageLookupByLibrary.simpleMessage("Continuer"), "continueOnFreeTrial": MessageLookupByLibrary.simpleMessage( "Poursuivre avec la version d\'essai gratuite"), @@ -510,7 +526,7 @@ class MessageLookup extends MessageLookupByLibrary { "Ceci supprimera tous les albums vides. Ceci est utile lorsque vous voulez réduire l\'encombrement dans votre liste d\'albums."), "deleteAll": MessageLookupByLibrary.simpleMessage("Tout Supprimer"), "deleteConfirmDialogBody": MessageLookupByLibrary.simpleMessage( - "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted."), + "Ce compte est lié à d\'autres applications ente, si vous en utilisez une.\\n\\nVos données téléchargées, dans toutes les applications ente, seront planifiées pour suppression, et votre compte sera définitivement supprimé."), "deleteEmailRequest": MessageLookupByLibrary.simpleMessage( "Veuillez envoyer un e-mail à account-deletion@ente.io à partir de votre adresse e-mail enregistrée."), "deleteEmptyAlbums": @@ -658,6 +674,7 @@ class MessageLookup extends MessageLookupByLibrary { "exportLogs": MessageLookupByLibrary.simpleMessage("Exporter les logs"), "exportYourData": MessageLookupByLibrary.simpleMessage("Exportez vos données"), + "faces": MessageLookupByLibrary.simpleMessage("Visages"), "failedToApplyCode": MessageLookupByLibrary.simpleMessage( "Impossible d\'appliquer le code"), "failedToCancel": @@ -689,7 +706,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ajouter une description..."), "fileSavedToGallery": MessageLookupByLibrary.simpleMessage( "Fichier enregistré dans la galerie"), - "fileTypes": MessageLookupByLibrary.simpleMessage("File types"), + "fileTypes": MessageLookupByLibrary.simpleMessage("Types de fichiers"), + "fileTypesAndNames": + MessageLookupByLibrary.simpleMessage("Types et noms de fichiers"), "filesBackedUpFromDevice": m19, "filesBackedUpInAlbum": m20, "filesDeleted": @@ -729,6 +748,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Accorder la permission"), "groupNearbyPhotos": MessageLookupByLibrary.simpleMessage( "Grouper les photos à proximité"), + "hearUsExplanation": MessageLookupByLibrary.simpleMessage( + "Nous ne suivons pas les installations d\'applications. Il serait utile que vous nous disiez comment vous nous avez trouvés !"), + "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( + "Comment avez-vous entendu parler de Ente? (facultatif)"), "hidden": MessageLookupByLibrary.simpleMessage("Masqué"), "hide": MessageLookupByLibrary.simpleMessage("Masquer"), "hiding": MessageLookupByLibrary.simpleMessage("Masquage en cours..."), @@ -810,6 +833,7 @@ class MessageLookup extends MessageLookupByLibrary { "linkHasExpired": MessageLookupByLibrary.simpleMessage("Le lien a expiré"), "linkNeverExpires": MessageLookupByLibrary.simpleMessage("Jamais"), + "livePhotos": MessageLookupByLibrary.simpleMessage("Photos en direct"), "loadMessage1": MessageLookupByLibrary.simpleMessage( "Vous pouvez partager votre abonnement avec votre famille"), "loadMessage2": MessageLookupByLibrary.simpleMessage( @@ -876,7 +900,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Sécurité moyenne"), "modifyYourQueryOrTrySearchingFor": MessageLookupByLibrary.simpleMessage( - "Modify your query, or try searching for"), + "Modifiez votre requête, ou essayez de rechercher"), + "moments": MessageLookupByLibrary.simpleMessage("Souvenirs"), "monthly": MessageLookupByLibrary.simpleMessage("Mensuel"), "moveItem": m30, "moveToAlbum": @@ -966,9 +991,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Supprimer définitivement"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage( "Supprimer définitivement de l\'appareil ?"), + "photoDescriptions": + MessageLookupByLibrary.simpleMessage("Descriptions de la photo"), "photoGridSize": MessageLookupByLibrary.simpleMessage("Taille de la grille photo"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("photo"), + "photos": MessageLookupByLibrary.simpleMessage("Photos"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage( "Les photos ajoutées par vous seront retirées de l\'album"), @@ -1136,12 +1164,36 @@ class MessageLookup extends MessageLookupByLibrary { "scanThisBarcodeWithnyourAuthenticatorApp": MessageLookupByLibrary.simpleMessage( "Scannez ce code-barres avec\nvotre application d\'authentification"), + "searchAlbumsEmptySection": + MessageLookupByLibrary.simpleMessage("Albums"), "searchByAlbumNameHint": MessageLookupByLibrary.simpleMessage("Nom de l\'album"), "searchByExamples": MessageLookupByLibrary.simpleMessage( "• Noms d\'albums (par exemple \"Caméra\")\n• Types de fichiers (par exemple \"Vidéos\", \".gif\")\n• Années et mois (par exemple \"2022\", \"Janvier\")\n• Vacances (par exemple \"Noël\")\n• Descriptions de photos (par exemple \"#fun\")"), + "searchCaptionEmptySection": MessageLookupByLibrary.simpleMessage( + "Ajoutez des descriptions comme \"#trip\" dans les infos photo pour les retrouver ici plus rapidement"), + "searchDatesEmptySection": MessageLookupByLibrary.simpleMessage( + "Recherche par date, mois ou année"), + "searchFaceEmptySection": MessageLookupByLibrary.simpleMessage( + "Trouver toutes les photos d\'une personne"), + "searchFileTypesAndNamesEmptySection": + MessageLookupByLibrary.simpleMessage("Types et noms de fichiers"), + "searchHint1": MessageLookupByLibrary.simpleMessage( + "Recherche rapide, sur l\'appareil"), + "searchHint2": MessageLookupByLibrary.simpleMessage( + "Dates des photos, descriptions"), + "searchHint3": MessageLookupByLibrary.simpleMessage( + "Albums, noms de fichiers et types"), + "searchHint4": MessageLookupByLibrary.simpleMessage("Emplacement"), + "searchHint5": MessageLookupByLibrary.simpleMessage( + "Bientôt: Visages & recherche magique ✨"), "searchHintText": MessageLookupByLibrary.simpleMessage( "Albums, mois, jours, années, ..."), + "searchLocationEmptySection": MessageLookupByLibrary.simpleMessage( + "Grouper les photos qui sont prises dans un certain angle d\'une photo"), + "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage( + "Invitez des gens, et vous verrez ici toutes les photos qu\'ils partagent"), + "searchResultCount": m65, "security": MessageLookupByLibrary.simpleMessage("Sécurité"), "selectAlbum": MessageLookupByLibrary.simpleMessage("Sélectionner album"), @@ -1400,6 +1452,8 @@ class MessageLookup extends MessageLookupByLibrary { "upgrade": MessageLookupByLibrary.simpleMessage("Améliorer"), "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Envoi des fichiers vers l\'album..."), + "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( + "Jusqu\'à 50% de réduction, jusqu\'au 4ème déc."), "usableReferralStorageInfo": MessageLookupByLibrary.simpleMessage( "Le stockage utilisable est limité par votre offre actuelle. Le stockage excédentaire deviendra automatiquement utilisable lorsque vous mettez à niveau votre offre."), "usePublicLinksForPeopleNotOnEnte": MessageLookupByLibrary.simpleMessage( @@ -1409,6 +1463,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage( "Utiliser la photo sélectionnée"), "usedSpace": MessageLookupByLibrary.simpleMessage("Mémoire utilisée"), + "validTill": m66, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "La vérification a échouée, veuillez réessayer"), @@ -1426,8 +1481,11 @@ class MessageLookup extends MessageLookupByLibrary { "verifyingRecoveryKey": MessageLookupByLibrary.simpleMessage( "Vérification de la clé de récupération..."), "videoSmallCase": MessageLookupByLibrary.simpleMessage("vidéo"), + "videos": MessageLookupByLibrary.simpleMessage("Vidéos"), "viewActiveSessions": MessageLookupByLibrary.simpleMessage( "Afficher les sessions actives"), + "viewAddOnButton": MessageLookupByLibrary.simpleMessage( + "Afficher les modules complémentaires"), "viewAll": MessageLookupByLibrary.simpleMessage("Tout afficher"), "viewAllExifData": MessageLookupByLibrary.simpleMessage( "Visualiser toutes les données EXIF"), @@ -1481,7 +1539,7 @@ class MessageLookup extends MessageLookupByLibrary { "youHaveSuccessfullyFreedUp": m63, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("Votre compte a été supprimé"), - "yourMap": MessageLookupByLibrary.simpleMessage("Your map"), + "yourMap": MessageLookupByLibrary.simpleMessage("Votre carte"), "yourPlanWasSuccessfullyDowngraded": MessageLookupByLibrary.simpleMessage( "Votre plan a été rétrogradé avec succès"), diff --git a/lib/generated/intl/messages_it.dart b/lib/generated/intl/messages_it.dart index 1659be2cbf37956c349ebb3cd03f81189058f10c..eaabb326be593aecaffb0b2d7acc42ea56f6b81e 100644 --- a/lib/generated/intl/messages_it.dart +++ b/lib/generated/intl/messages_it.dart @@ -187,7 +187,7 @@ class MessageLookup extends MessageLookupByLibrary { static String m59(count) => "${Intl.plural(count, zero: '', one: '1 giorno', other: '${count} giorni')}"; - static String m65(endDate) => "Valido fino al ${endDate}"; + static String m66(endDate) => "Valido fino al ${endDate}"; static String m60(email) => "Verifica ${email}"; @@ -446,6 +446,7 @@ class MessageLookup extends MessageLookupByLibrary { "contactSupport": MessageLookupByLibrary.simpleMessage("Contatta il supporto"), "contactToManageSubscription": m10, + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "continueLabel": MessageLookupByLibrary.simpleMessage("Continua"), "continueOnFreeTrial": MessageLookupByLibrary.simpleMessage("Continua la prova gratuita"), @@ -1390,7 +1391,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("Usa la foto selezionata"), "usedSpace": MessageLookupByLibrary.simpleMessage("Spazio utilizzato"), - "validTill": m65, + "validTill": m66, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Verifica fallita, per favore prova di nuovo"), diff --git a/lib/generated/intl/messages_ko.dart b/lib/generated/intl/messages_ko.dart index 653419baeb42d156d9958c0355eaacd2221aa6cd..7c52593426ef240c64a9e3236e08867e9047aae0 100644 --- a/lib/generated/intl/messages_ko.dart +++ b/lib/generated/intl/messages_ko.dart @@ -24,6 +24,7 @@ class MessageLookup extends MessageLookupByLibrary { static Map _notInlinedMessages(_) => { "addToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Add to hidden album"), + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "deleteConfirmDialogBody": MessageLookupByLibrary.simpleMessage( "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted."), "fileTypes": MessageLookupByLibrary.simpleMessage("File types"), diff --git a/lib/generated/intl/messages_nl.dart b/lib/generated/intl/messages_nl.dart index f2f316213f42291edf23c1967d909e28bade2f19..90ac6a2157bd7bc18f3f98cdbda3fb2f7a0cbd0a 100644 --- a/lib/generated/intl/messages_nl.dart +++ b/lib/generated/intl/messages_nl.dart @@ -441,6 +441,7 @@ class MessageLookup extends MessageLookupByLibrary { "contactSupport": MessageLookupByLibrary.simpleMessage("Contacteer klantenservice"), "contactToManageSubscription": m10, + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "continueLabel": MessageLookupByLibrary.simpleMessage("Doorgaan"), "continueOnFreeTrial": MessageLookupByLibrary.simpleMessage( "Doorgaan met gratis proefversie"), diff --git a/lib/generated/intl/messages_no.dart b/lib/generated/intl/messages_no.dart index 4de30a91b24e925acdc535e89bc0a4262d3bed98..d162c4550838a19bb08aca7b9610b388dd653abf 100644 --- a/lib/generated/intl/messages_no.dart +++ b/lib/generated/intl/messages_no.dart @@ -33,6 +33,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Bekreft sletting av konto"), "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( "Ja, jeg ønsker å slette denne kontoen og all dataen dens permanent."), + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "deleteAccount": MessageLookupByLibrary.simpleMessage("Slett konto"), "deleteAccountFeedbackPrompt": MessageLookupByLibrary.simpleMessage( "Vi er lei oss for at du forlater oss. Gi oss gjerne en tilbakemelding så vi kan forbedre oss."), diff --git a/lib/generated/intl/messages_pl.dart b/lib/generated/intl/messages_pl.dart index 6fb8aa6f0c8855c10e9f23010648407d2765929d..7a567715b304a7c5a93869ff5eb796240ee2ac66 100644 --- a/lib/generated/intl/messages_pl.dart +++ b/lib/generated/intl/messages_pl.dart @@ -50,6 +50,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Powtórz hasło"), "contactSupport": MessageLookupByLibrary.simpleMessage( "Skontaktuj się z pomocą techniczną"), + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "continueLabel": MessageLookupByLibrary.simpleMessage("Kontynuuj"), "createAccount": MessageLookupByLibrary.simpleMessage("Stwórz konto"), "createNewAccount": diff --git a/lib/generated/intl/messages_pt.dart b/lib/generated/intl/messages_pt.dart index a873f19d44ed6325558d133e5955a0b3fe82002e..9ddbbd8d933e9b15824825cb03cbc9ea17bed754 100644 --- a/lib/generated/intl/messages_pt.dart +++ b/lib/generated/intl/messages_pt.dart @@ -136,6 +136,7 @@ class MessageLookup extends MessageLookupByLibrary { "Confirme sua chave de recuperação"), "contactSupport": MessageLookupByLibrary.simpleMessage("Falar com o suporte"), + "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "continueLabel": MessageLookupByLibrary.simpleMessage("Continuar"), "copypasteThisCodentoYourAuthenticatorApp": MessageLookupByLibrary.simpleMessage( diff --git a/lib/generated/intl/messages_zh.dart b/lib/generated/intl/messages_zh.dart index 1e62fea040fd1b558e6624f4d16bc8072844ab9c..b90353d477f8de66c3c251930961c248ca9b169e 100644 --- a/lib/generated/intl/messages_zh.dart +++ b/lib/generated/intl/messages_zh.dart @@ -127,6 +127,9 @@ class MessageLookup extends MessageLookupByLibrary { static String m41(endDate) => "在 ${endDate} 前续费"; + static String m65(count) => + "${Intl.plural(count, other: '已找到 ${count} 个结果')}"; + static String m42(count) => "已选择 ${count} 个"; static String m43(count, yourCount) => "选择了 ${count} 个 (您的 ${yourCount} 个)"; @@ -170,7 +173,7 @@ class MessageLookup extends MessageLookupByLibrary { static String m59(count) => "${Intl.plural(count, zero: '', one: '1天', other: '${count} 天')}"; - static String m65(endDate) => "有效期至 ${endDate}"; + static String m66(endDate) => "有效期至 ${endDate}"; static String m60(email) => "验证 ${email}"; @@ -198,6 +201,7 @@ class MessageLookup extends MessageLookupByLibrary { "addLocation": MessageLookupByLibrary.simpleMessage("添加地点"), "addLocationButton": MessageLookupByLibrary.simpleMessage("添加"), "addMore": MessageLookupByLibrary.simpleMessage("添加更多"), + "addNew": MessageLookupByLibrary.simpleMessage("新建"), "addOnPageSubtitle": MessageLookupByLibrary.simpleMessage("附加组件详情"), "addOns": MessageLookupByLibrary.simpleMessage("附加组件"), "addPhotos": MessageLookupByLibrary.simpleMessage("添加照片"), @@ -206,6 +210,7 @@ class MessageLookup extends MessageLookupByLibrary { "addToEnte": MessageLookupByLibrary.simpleMessage("添加到 ente"), "addToHiddenAlbum": MessageLookupByLibrary.simpleMessage("添加到隐藏相册"), "addViewer": MessageLookupByLibrary.simpleMessage("添加查看者"), + "addYourPhotosNow": MessageLookupByLibrary.simpleMessage("立即添加您的照片"), "addedAs": MessageLookupByLibrary.simpleMessage("已添加为"), "addedBy": m1, "addedSuccessfullyTo": m2, @@ -308,6 +313,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("通过移动数据备份"), "backupSettings": MessageLookupByLibrary.simpleMessage("备份设置"), "backupVideos": MessageLookupByLibrary.simpleMessage("备份视频"), + "blackFridaySale": MessageLookupByLibrary.simpleMessage("黑色星期五特惠"), "blog": MessageLookupByLibrary.simpleMessage("博客"), "cachedData": MessageLookupByLibrary.simpleMessage("缓存数据"), "calculating": MessageLookupByLibrary.simpleMessage("正在计算..."), @@ -374,6 +380,8 @@ class MessageLookup extends MessageLookupByLibrary { "contactFamilyAdmin": m9, "contactSupport": MessageLookupByLibrary.simpleMessage("联系支持"), "contactToManageSubscription": m10, + "contacts": MessageLookupByLibrary.simpleMessage("联系人"), + "contents": MessageLookupByLibrary.simpleMessage("内容"), "continueLabel": MessageLookupByLibrary.simpleMessage("继续"), "continueOnFreeTrial": MessageLookupByLibrary.simpleMessage("继续免费试用"), "convertToAlbum": MessageLookupByLibrary.simpleMessage("转换为相册"), @@ -535,6 +543,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("此链接已过期。请选择新的过期时间或禁用链接过期。"), "exportLogs": MessageLookupByLibrary.simpleMessage("导出日志"), "exportYourData": MessageLookupByLibrary.simpleMessage("导出您的数据"), + "faces": MessageLookupByLibrary.simpleMessage("人脸"), "failedToApplyCode": MessageLookupByLibrary.simpleMessage("无法应用代码"), "failedToCancel": MessageLookupByLibrary.simpleMessage("取消失败"), "failedToDownloadVideo": MessageLookupByLibrary.simpleMessage("视频下载失败"), @@ -558,6 +567,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("无法将文件保存到相册"), "fileInfoAddDescHint": MessageLookupByLibrary.simpleMessage("添加说明..."), "fileSavedToGallery": MessageLookupByLibrary.simpleMessage("文件已保存到相册"), + "fileTypes": MessageLookupByLibrary.simpleMessage("文件类型"), + "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("文件类型和名称"), "filesBackedUpFromDevice": m19, "filesBackedUpInAlbum": m20, "filesDeleted": MessageLookupByLibrary.simpleMessage("文件已删除"), @@ -655,6 +666,7 @@ class MessageLookup extends MessageLookupByLibrary { "linkExpiry": MessageLookupByLibrary.simpleMessage("链接过期"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("链接已过期"), "linkNeverExpires": MessageLookupByLibrary.simpleMessage("永不"), + "livePhotos": MessageLookupByLibrary.simpleMessage("实况照片"), "loadMessage1": MessageLookupByLibrary.simpleMessage("您可以与家庭分享您的订阅"), "loadMessage2": MessageLookupByLibrary.simpleMessage("到目前为止,我们已经保存了1 000多万个回忆"), @@ -710,8 +722,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("移动端, 网页端, 桌面端"), "moderateStrength": MessageLookupByLibrary.simpleMessage("中等"), "modifyYourQueryOrTrySearchingFor": - MessageLookupByLibrary.simpleMessage( - "Modify your query, or try searching for"), + MessageLookupByLibrary.simpleMessage("修改您的查询,或尝试搜索"), + "moments": MessageLookupByLibrary.simpleMessage("瞬间"), "monthly": MessageLookupByLibrary.simpleMessage("每月"), "moveItem": m30, "moveToAlbum": MessageLookupByLibrary.simpleMessage("移动到相册"), @@ -784,8 +796,10 @@ class MessageLookup extends MessageLookupByLibrary { "permanentlyDelete": MessageLookupByLibrary.simpleMessage("永久删除"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage("要从设备中永久删除吗?"), + "photoDescriptions": MessageLookupByLibrary.simpleMessage("照片说明"), "photoGridSize": MessageLookupByLibrary.simpleMessage("照片网格大小"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("照片"), + "photos": MessageLookupByLibrary.simpleMessage("照片"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage("您添加的照片将从相册中移除"), "pickCenterPoint": MessageLookupByLibrary.simpleMessage("选择中心点"), @@ -908,10 +922,29 @@ class MessageLookup extends MessageLookupByLibrary { "scanCode": MessageLookupByLibrary.simpleMessage("扫描代码"), "scanThisBarcodeWithnyourAuthenticatorApp": MessageLookupByLibrary.simpleMessage("用您的身份验证器应用\n扫描此条码"), + "searchAlbumsEmptySection": MessageLookupByLibrary.simpleMessage("相册"), "searchByAlbumNameHint": MessageLookupByLibrary.simpleMessage("相册名称"), "searchByExamples": MessageLookupByLibrary.simpleMessage( "• 相册名称(例如“相机”)\n• 文件类型(例如“视频”、“.gif”)\n• 年份和月份(例如“2022”、“一月”)\n• 假期(例如“圣诞节”)\n• 照片说明(例如“#和女儿独居,好开心啊”)"), + "searchCaptionEmptySection": MessageLookupByLibrary.simpleMessage( + "在照片信息中添加“#旅游”等描述,以便在此处快速找到它们"), + "searchDatesEmptySection": + MessageLookupByLibrary.simpleMessage("按日期搜索,月份或年份"), + "searchFaceEmptySection": + MessageLookupByLibrary.simpleMessage("查找一个人的所有照片"), + "searchFileTypesAndNamesEmptySection": + MessageLookupByLibrary.simpleMessage("文件类型和名称"), + "searchHint1": MessageLookupByLibrary.simpleMessage("在设备上快速搜索"), + "searchHint2": MessageLookupByLibrary.simpleMessage("照片日期、描述"), + "searchHint3": MessageLookupByLibrary.simpleMessage("相册、文件名和类型"), + "searchHint4": MessageLookupByLibrary.simpleMessage("位置"), + "searchHint5": MessageLookupByLibrary.simpleMessage("即将到来:面部和魔法搜索✨"), "searchHintText": MessageLookupByLibrary.simpleMessage("相册,月,日,年,..."), + "searchLocationEmptySection": + MessageLookupByLibrary.simpleMessage("在照片的一定半径内拍摄的几组照片"), + "searchPeopleEmptySection": + MessageLookupByLibrary.simpleMessage("邀请他人,您将在此看到他们分享的所有照片"), + "searchResultCount": m65, "security": MessageLookupByLibrary.simpleMessage("安全"), "selectAlbum": MessageLookupByLibrary.simpleMessage("选择相册"), "selectAll": MessageLookupByLibrary.simpleMessage("全选"), @@ -1113,6 +1146,8 @@ class MessageLookup extends MessageLookupByLibrary { "upgrade": MessageLookupByLibrary.simpleMessage("升级"), "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage("正在将文件上传到相册..."), + "upto50OffUntil4thDec": + MessageLookupByLibrary.simpleMessage("最高五折优惠,直至12月4日。"), "usableReferralStorageInfo": MessageLookupByLibrary.simpleMessage( "可用存储空间受您当前计划的限制。 当您升级您的计划时,超出要求的存储空间将自动变为可用。"), "usePublicLinksForPeopleNotOnEnte": @@ -1120,7 +1155,7 @@ class MessageLookup extends MessageLookupByLibrary { "useRecoveryKey": MessageLookupByLibrary.simpleMessage("使用恢复密钥"), "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("使用所选照片"), "usedSpace": MessageLookupByLibrary.simpleMessage("已用空间"), - "validTill": m65, + "validTill": m66, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage("验证失败,请重试"), "verificationId": MessageLookupByLibrary.simpleMessage("验证 ID"), @@ -1133,6 +1168,7 @@ class MessageLookup extends MessageLookupByLibrary { "verifyingRecoveryKey": MessageLookupByLibrary.simpleMessage("正在验证恢复密钥..."), "videoSmallCase": MessageLookupByLibrary.simpleMessage("视频"), + "videos": MessageLookupByLibrary.simpleMessage("视频"), "viewActiveSessions": MessageLookupByLibrary.simpleMessage("查看活动会话"), "viewAddOnButton": MessageLookupByLibrary.simpleMessage("查看附加组件"), "viewAll": MessageLookupByLibrary.simpleMessage("查看全部"), @@ -1178,7 +1214,7 @@ class MessageLookup extends MessageLookupByLibrary { "youHaveSuccessfullyFreedUp": m63, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("您的账户已删除"), - "yourMap": MessageLookupByLibrary.simpleMessage("Your map"), + "yourMap": MessageLookupByLibrary.simpleMessage("您的地图"), "yourPlanWasSuccessfullyDowngraded": MessageLookupByLibrary.simpleMessage("您的计划已成功降级"), "yourPlanWasSuccessfullyUpgraded": diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index 523110e7056d6a21c0835911d7db16e73395878c..8e3ae83b75b021a3d224eaea7e5d683d872d4987 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -3924,6 +3924,16 @@ class S { ); } + /// `Your {storageAmount} add-on is valid till {endDate}` + String addOnValidTill(Object storageAmount, Object endDate) { + return Intl.message( + 'Your $storageAmount add-on is valid till $endDate', + name: 'addOnValidTill', + desc: '', + args: [storageAmount, endDate], + ); + } + /// `Free trial valid till {endDate}.\nYou can choose a paid plan afterwards.` String playStoreFreeTrialValidTill(Object endDate) { return Intl.message( @@ -7995,10 +8005,10 @@ class S { ); } - /// `Coming soon: Photo contents, faces` + /// `Coming soon: Faces & magic search ✨` String get searchHint5 { return Intl.message( - 'Coming soon: Photo contents, faces', + 'Coming soon: Faces & magic search ✨', name: 'searchHint5', desc: '', args: [], diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index f3fca6a0c5ebe0f4df6cdc6e0ef261e57758269a..1325d1b2e4eb88af7af05e3671a482d3db0cf66f 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -558,6 +558,7 @@ "renewsOn": "Renews on {endDate}", "freeTrialValidTill": "Free trial valid till {endDate}", "validTill": "Valid till {endDate}", + "addOnValidTill": "Your {storageAmount} add-on is valid till {endDate}", "playStoreFreeTrialValidTill": "Free trial valid till {endDate}.\nYou can choose a paid plan afterwards.", "subWillBeCancelledOn": "Your subscription will be cancelled on {endDate}", "subscription": "Subscription", diff --git a/lib/ui/payment/store_subscription_page.dart b/lib/ui/payment/store_subscription_page.dart index d9a95f684c5ffe572cbb0b56e76ffa6d5ad9ac85..e544ca702947837a0ea88d963a56ebc43200dd17 100644 --- a/lib/ui/payment/store_subscription_page.dart +++ b/lib/ui/payment/store_subscription_page.dart @@ -239,7 +239,7 @@ class _StoreSubscriptionPageState extends State { widgets.add(_showSubscriptionToggle()); } - if (_hasActiveSubscription) { + if (_currentSubscription != null) { widgets.add( ValidityWidget( currentSubscription: _currentSubscription, diff --git a/lib/ui/payment/stripe_subscription_page.dart b/lib/ui/payment/stripe_subscription_page.dart index 54a551b7d7e4380ce8f5fe33466b813ec01ec836..b48e59f75fa1e53e923e54fac42a802252af6571 100644 --- a/lib/ui/payment/stripe_subscription_page.dart +++ b/lib/ui/payment/stripe_subscription_page.dart @@ -210,7 +210,7 @@ class _StripeSubscriptionPageState extends State { widgets.add(_showSubscriptionToggle()); - if (_hasActiveSubscription) { + if (_currentSubscription != null) { widgets.add( ValidityWidget( currentSubscription: _currentSubscription, diff --git a/lib/ui/payment/subscription_common_widgets.dart b/lib/ui/payment/subscription_common_widgets.dart index f2b8fe23fec116cf78ed7aa4cd75946bdc3dee3a..6efdf56d7c67d0559e745baec0da919355032599 100644 --- a/lib/ui/payment/subscription_common_widgets.dart +++ b/lib/ui/payment/subscription_common_widgets.dart @@ -98,9 +98,14 @@ class ValidityWidget extends StatelessWidget { if (currentSubscription == null) { return const SizedBox.shrink(); } + final List addOnBonus = bonusData?.getAddOnBonuses() ?? []; final bool isFreeTrialSub = currentSubscription!.productID == freeProductID; - if (isFreeTrialSub && (bonusData?.getAddOnBonuses().isNotEmpty ?? false)) { - return const SizedBox.shrink(); + bool hideSubValidityView = false; + if (isFreeTrialSub && addOnBonus.isNotEmpty) { + hideSubValidityView = true; + } + if (!currentSubscription!.isValid()) { + hideSubValidityView = true; } final endDate = DateFormat.yMMMd(Localizations.localeOf(context).languageCode).format( @@ -114,11 +119,45 @@ class ValidityWidget extends StatelessWidget { : S.of(context).freeTrialValidTill(endDate); } else if (currentSubscription!.attributes?.isCancelled ?? false) { message = S.of(context).subWillBeCancelledOn(endDate); + if (addOnBonus.isNotEmpty) { + hideSubValidityView = true; + } } + + return Padding( + padding: const EdgeInsets.only(top: 0), + child: Column( + children: [ + if (!hideSubValidityView) + Text( + message, + style: Theme.of(context).textTheme.bodySmall, + textAlign: TextAlign.center, + ), + if (addOnBonus.isNotEmpty) + ...addOnBonus.map((bonus) => AddOnBonusValidity(bonus)).toList(), + ], + ), + ); + } +} + +class AddOnBonusValidity extends StatelessWidget { + final Bonus bonus; + + const AddOnBonusValidity(this.bonus, {super.key}); + + @override + Widget build(BuildContext context) { + final endDate = + DateFormat.yMMMd(Localizations.localeOf(context).languageCode).format( + DateTime.fromMicrosecondsSinceEpoch(bonus.validTill), + ); + final String storage = formatBytes(bonus.storage); return Padding( - padding: const EdgeInsets.only(top: 8), + padding: const EdgeInsets.only(top: 8, bottom: 8), child: Text( - message, + S.of(context).addOnValidTill(storage, endDate), style: Theme.of(context).textTheme.bodySmall, textAlign: TextAlign.center, ), From 3fbf7be3ab0b8482e7e8917f65b48490d51b93bb Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Mon, 20 Nov 2023 19:23:39 +0530 Subject: [PATCH 07/10] Toggle current sub active flag based on add-on Signed-off-by: Neeraj Gupta <254676+ua741@users.noreply.github.com> --- lib/ui/payment/store_subscription_page.dart | 6 +++++- lib/ui/payment/stripe_subscription_page.dart | 12 ++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/ui/payment/store_subscription_page.dart b/lib/ui/payment/store_subscription_page.dart index e544ca702947837a0ea88d963a56ebc43200dd17..722d6d5d22dccc6ecebeb00c961620aeb4b61591 100644 --- a/lib/ui/payment/store_subscription_page.dart +++ b/lib/ui/payment/store_subscription_page.dart @@ -52,6 +52,7 @@ class _StoreSubscriptionPageState extends State { late ProgressDialog _dialog; late UserDetails _userDetails; late bool _hasActiveSubscription; + bool _hideCurrentPlanSelection = false; late FreePlan _freePlan; late List _plans; bool _hasLoadedData = false; @@ -177,7 +178,10 @@ class _StoreSubscriptionPageState extends State { _userService.getUserDetailsV2(memoryCount: false).then((userDetails) async { _userDetails = userDetails; _currentSubscription = userDetails.subscription; + _hasActiveSubscription = _currentSubscription!.isValid(); + _hideCurrentPlanSelection = + _currentSubscription?.attributes?.isCancelled ?? false; showYearlyPlan = _currentSubscription!.isYearlyPlan(); final billingPlans = await _billingService.getBillingPlans(); _isActiveStripeSubscriber = @@ -458,7 +462,7 @@ class _StoreSubscriptionPageState extends State { storage: plan.storage, price: plan.price, period: plan.period, - isActive: isActive, + isActive: isActive && !_hideCurrentPlanSelection, ), ), ), diff --git a/lib/ui/payment/stripe_subscription_page.dart b/lib/ui/payment/stripe_subscription_page.dart index b48e59f75fa1e53e923e54fac42a802252af6571..e205fb062b6ed3e3e0f9d0b3d58a0f78812b80b6 100644 --- a/lib/ui/payment/stripe_subscription_page.dart +++ b/lib/ui/payment/stripe_subscription_page.dart @@ -53,6 +53,7 @@ class _StripeSubscriptionPageState extends State { // indicates if user's subscription plan is still active late bool _hasActiveSubscription; + bool _hideCurrentPlanSelection = false; late FreePlan _freePlan; List _plans = []; bool _hasLoadedData = false; @@ -73,7 +74,11 @@ class _StripeSubscriptionPageState extends State { .then((userDetails) async { _userDetails = userDetails; _currentSubscription = userDetails.subscription; + _showYearlyPlan = _currentSubscription!.isYearlyPlan(); + _hideCurrentPlanSelection = + (_currentSubscription?.attributes?.isCancelled ?? false) && + userDetails.hasPaidAddon(); _hasActiveSubscription = _currentSubscription!.isValid(); _isStripeSubscriber = _currentSubscription!.paymentProvider == stripe; return _filterStripeForUI().then((value) { @@ -340,6 +345,9 @@ class _StripeSubscriptionPageState extends State { Widget _stripeRenewOrCancelButton() { final bool isRenewCancelled = _currentSubscription!.attributes?.isCancelled ?? false; + if (isRenewCancelled && _userDetails.hasPaidAddon()) { + return const SizedBox.shrink(); + } final String title = isRenewCancelled ? S.of(context).renewSubscription : S.of(context).cancelSubscription; @@ -503,7 +511,7 @@ class _StripeSubscriptionPageState extends State { storage: plan.storage, price: plan.price, period: plan.period, - isActive: isActive, + isActive: isActive && !_hideCurrentPlanSelection, ), ), ), @@ -594,7 +602,7 @@ class _StripeSubscriptionPageState extends State { storage: _currentSubscription!.storage, price: _currentSubscription!.price, period: _currentSubscription!.period, - isActive: true, + isActive: !_hasActiveSubscription, ), ), ), From 7c4b389ef4e1ec99f09574af2a7a515f94199e05 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Mon, 20 Nov 2023 19:24:41 +0530 Subject: [PATCH 08/10] Update copy Signed-off-by: Neeraj Gupta <254676+ua741@users.noreply.github.com> --- lib/generated/intl/messages_en.dart | 2 +- lib/generated/l10n.dart | 5 +++-- lib/l10n/intl_en.arb | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index 726f34076907cc9e875fef102c5ec4806b91b7dc..f7425cb811e1c638f82f75a2acb3e37378affffc 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -138,7 +138,7 @@ class MessageLookup extends MessageLookupByLibrary { static String m40(userEmail) => "${userEmail} will be removed from this shared album\n\nAny photos added by them will also be removed from the album"; - static String m41(endDate) => "Renews on ${endDate}"; + static String m41(endDate) => "Subscription renews on ${endDate}"; static String m65(count) => "${Intl.plural(count, one: '${count} result found', other: '${count} results found')}"; diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index 8e3ae83b75b021a3d224eaea7e5d683d872d4987..17dea8919b4fb0eda0e537a1c8a67fa285dc7686 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -1,6 +1,7 @@ // GENERATED CODE - DO NOT MODIFY BY HAND import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; + import 'intl/messages_all.dart'; // ************************************************************************** @@ -3894,10 +3895,10 @@ class S { ); } - /// `Renews on {endDate}` + /// `Subscription renews on {endDate}` String renewsOn(Object endDate) { return Intl.message( - 'Renews on $endDate', + 'Subscription renews on $endDate', name: 'renewsOn', desc: '', args: [endDate], diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 1325d1b2e4eb88af7af05e3671a482d3db0cf66f..bd14aa9c6fb00de1c3fedabbf9b4d6dd1afb1838 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -555,7 +555,7 @@ "type": "text" }, "faqs": "FAQs", - "renewsOn": "Renews on {endDate}", + "renewsOn": "Subscription renews on {endDate}", "freeTrialValidTill": "Free trial valid till {endDate}", "validTill": "Valid till {endDate}", "addOnValidTill": "Your {storageAmount} add-on is valid till {endDate}", From 6b15e214f71a36901129539f8fc3229f07ef5043 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Mon, 20 Nov 2023 19:26:00 +0530 Subject: [PATCH 09/10] Switch to different formatter for stroage Signed-off-by: Neeraj Gupta <254676+ua741@users.noreply.github.com> --- lib/ui/payment/subscription_common_widgets.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/payment/subscription_common_widgets.dart b/lib/ui/payment/subscription_common_widgets.dart index 6efdf56d7c67d0559e745baec0da919355032599..c33f26d793498e95c2ac17e771e39a88ebac04a3 100644 --- a/lib/ui/payment/subscription_common_widgets.dart +++ b/lib/ui/payment/subscription_common_widgets.dart @@ -153,7 +153,7 @@ class AddOnBonusValidity extends StatelessWidget { DateFormat.yMMMd(Localizations.localeOf(context).languageCode).format( DateTime.fromMicrosecondsSinceEpoch(bonus.validTill), ); - final String storage = formatBytes(bonus.storage); + final String storage = convertBytesToReadableFormat(bonus.storage); return Padding( padding: const EdgeInsets.only(top: 8, bottom: 8), child: Text( From e1314c1b9829743e0fb63e82732f99f06124d5a1 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Mon, 20 Nov 2023 19:35:43 +0530 Subject: [PATCH 10/10] Bump version: 0.8.1+521 --- lib/generated/intl/messages_fr.dart | 8 ++++---- lib/generated/intl/messages_zh.dart | 11 +++++++---- pubspec.yaml | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/generated/intl/messages_fr.dart b/lib/generated/intl/messages_fr.dart index 79391df748efab504c5f8f5aa4816f2e4049ff7e..4a76e7b4ec0ebbb60c53dba851f56cb958a9ede3 100644 --- a/lib/generated/intl/messages_fr.dart +++ b/lib/generated/intl/messages_fr.dart @@ -140,7 +140,7 @@ class MessageLookup extends MessageLookupByLibrary { static String m41(endDate) => "Renouvellement le ${endDate}"; - static String m64(count) => + static String m65(count) => "${Intl.plural(count, one: '${count} résultat trouvé', other: '${count} résultats trouvés')}"; static String m42(count) => "${count} sélectionné(s)"; @@ -192,7 +192,7 @@ class MessageLookup extends MessageLookupByLibrary { static String m59(count) => "${Intl.plural(count, zero: '0 jour', one: '1 jour', other: '${count} jours')}"; - static String m65(endDate) => "Valable jusqu\'au ${endDate}"; + static String m66(endDate) => "Valable jusqu\'au ${endDate}"; static String m60(email) => "Vérifier ${email}"; @@ -1193,7 +1193,7 @@ class MessageLookup extends MessageLookupByLibrary { "Grouper les photos qui sont prises dans un certain angle d\'une photo"), "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage( "Invitez des gens, et vous verrez ici toutes les photos qu\'ils partagent"), - "searchResultCount": m64, + "searchResultCount": m65, "security": MessageLookupByLibrary.simpleMessage("Sécurité"), "selectAlbum": MessageLookupByLibrary.simpleMessage("Sélectionner album"), @@ -1463,7 +1463,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage( "Utiliser la photo sélectionnée"), "usedSpace": MessageLookupByLibrary.simpleMessage("Mémoire utilisée"), - "validTill": m65, + "validTill": m66, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "La vérification a échouée, veuillez réessayer"), diff --git a/lib/generated/intl/messages_zh.dart b/lib/generated/intl/messages_zh.dart index 9370da75e5a8326a5c8cd903844f31520bd85f99..674da416c21defd70c1efed6fc959fc4915bf5d2 100644 --- a/lib/generated/intl/messages_zh.dart +++ b/lib/generated/intl/messages_zh.dart @@ -127,7 +127,7 @@ class MessageLookup extends MessageLookupByLibrary { static String m41(endDate) => "在 ${endDate} 前续费"; - static String m64(count) => + static String m65(count) => "${Intl.plural(count, other: '已找到 ${count} 个结果')}"; static String m42(count) => "已选择 ${count} 个"; @@ -173,7 +173,7 @@ class MessageLookup extends MessageLookupByLibrary { static String m59(count) => "${Intl.plural(count, zero: '', one: '1天', other: '${count} 天')}"; - static String m65(endDate) => "有效期至 ${endDate}"; + static String m66(endDate) => "有效期至 ${endDate}"; static String m60(email) => "验证 ${email}"; @@ -749,6 +749,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("没有隐藏的照片或视频"), "noImagesWithLocation": MessageLookupByLibrary.simpleMessage("没有带有位置的图像"), + "noInternetConnection": MessageLookupByLibrary.simpleMessage("无互联网连接"), "noPhotosAreBeingBackedUpRightNow": MessageLookupByLibrary.simpleMessage("目前没有照片正在备份"), "noPhotosFoundHere": MessageLookupByLibrary.simpleMessage("这里没有找到照片"), @@ -807,6 +808,8 @@ class MessageLookup extends MessageLookupByLibrary { "playStoreFreeTrialValidTill": m35, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("PlayStore 订阅"), + "pleaseCheckYourInternetConnectionAndTryAgain": + MessageLookupByLibrary.simpleMessage("请检查您的互联网连接,然后重试。"), "pleaseContactSupportAndWeWillBeHappyToHelp": MessageLookupByLibrary.simpleMessage( "请用英语联系 support@ente.io ,我们将乐意提供帮助!"), @@ -944,7 +947,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("在照片的一定半径内拍摄的几组照片"), "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage("邀请他人,您将在此看到他们分享的所有照片"), - "searchResultCount": m64, + "searchResultCount": m65, "security": MessageLookupByLibrary.simpleMessage("安全"), "selectAlbum": MessageLookupByLibrary.simpleMessage("选择相册"), "selectAll": MessageLookupByLibrary.simpleMessage("全选"), @@ -1155,7 +1158,7 @@ class MessageLookup extends MessageLookupByLibrary { "useRecoveryKey": MessageLookupByLibrary.simpleMessage("使用恢复密钥"), "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("使用所选照片"), "usedSpace": MessageLookupByLibrary.simpleMessage("已用空间"), - "validTill": m65, + "validTill": m66, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage("验证失败,请重试"), "verificationId": MessageLookupByLibrary.simpleMessage("验证 ID"), diff --git a/pubspec.yaml b/pubspec.yaml index e5ca90dd62b360709d691aad967f404edf9a2f2f..769948d6cb8513179f56ad6870376b01c5e34200 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,7 +12,7 @@ description: ente photos application # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 0.8.0+520 +version: 0.8.1+521 environment: sdk: ">=3.0.0 <4.0.0"