diff --git a/analysis_options.yaml b/analysis_options.yaml index cc6de6a00..cebeb1391 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -61,7 +61,7 @@ analyzer: cancel_subscriptions: error - unawaited_futures: ignore # convert to warning after fixing existing issues + unawaited_futures: warning # convert to warning after fixing existing issues invalid_dependency: info use_build_context_synchronously: ignore # experimental lint, requires many changes prefer_interpolation_to_compose_strings: ignore # later too many warnings diff --git a/lib/core/configuration.dart b/lib/core/configuration.dart index e00549930..785fab08f 100644 --- a/lib/core/configuration.dart +++ b/lib/core/configuration.dart @@ -171,7 +171,7 @@ class Configuration { SearchService.instance.clearCache(); Bus.instance.fire(UserLoggedOutEvent()); } else { - _preferences.setBool("auto_logout", true); + await _preferences.setBool("auto_logout", true); } } diff --git a/lib/core/error-reporting/super_logging.dart b/lib/core/error-reporting/super_logging.dart index a92decfb6..cc9c3122c 100644 --- a/lib/core/error-reporting/super_logging.dart +++ b/lib/core/error-reporting/super_logging.dart @@ -171,7 +171,7 @@ class SuperLogging { await setupLogDir(); } if (sentryIsEnabled) { - setupSentry(); + setupSentry().ignore(); } Logger.root.level = Level.ALL; @@ -266,7 +266,7 @@ class SuperLogging { // add error to sentry queue if (sentryIsEnabled && rec.error != null) { - _sendErrorToSentry(rec.error!, null); + _sendErrorToSentry(rec.error!, null).ignore(); } } @@ -303,7 +303,7 @@ class SuperLogging { static Future setupSentry() async { await for (final error in sentryQueueControl.stream.asBroadcastStream()) { try { - Sentry.captureException( + await Sentry.captureException( error, ); } catch (e) { diff --git a/lib/db/file_updation_db.dart b/lib/db/file_updation_db.dart index 22f317924..656f8ed17 100644 --- a/lib/db/file_updation_db.dart +++ b/lib/db/file_updation_db.dart @@ -14,6 +14,7 @@ class FileUpdationDB { static const tableName = 're_upload_tracker'; static const columnLocalID = 'local_id'; static const columnReason = 'reason'; + static const livePhotoSize = 'livePhotoSize'; static const modificationTimeUpdated = 'modificationTimeUpdated'; diff --git a/lib/db/files_db.dart b/lib/db/files_db.dart index bf5b5991c..0bb1f99e3 100644 --- a/lib/db/files_db.dart +++ b/lib/db/files_db.dart @@ -789,7 +789,7 @@ class FilesDB { return uploadedFileIDs; } - Future getUploadedLocalFileInAnyCollection( + Future> getFilesInAllCollection( int uploadedFileID, int userID, ) async { @@ -802,12 +802,11 @@ class FilesDB { userID, uploadedFileID, ], - limit: 1, ); if (results.isEmpty) { - return null; + return []; } - return convertToFiles(results)[0]; + return convertToFiles(results); } Future> getExistingLocalFileIDs(int ownerID) async { @@ -1450,6 +1449,28 @@ class FilesDB { return result; } + // For a given userID, return unique uploadedFileId for the given userID + Future> getLivePhotosWithBadSize( + int userId, + int sizeInBytes, + ) async { + final db = await instance.database; + final rows = await db.query( + filesTable, + columns: [columnLocalID], + distinct: true, + where: '$columnOwnerID = ? AND ' + '($columnFileSize IS NULL OR $columnFileSize = ?) AND ' + '$columnFileType = ? AND $columnLocalID IS NOT NULL', + whereArgs: [userId, sizeInBytes, getInt(FileType.livePhoto)], + ); + final result = []; + for (final row in rows) { + result.add(row[columnLocalID] as String); + } + return result; + } + // updateSizeForUploadIDs takes a map of upploadedFileID and fileSize and // update the fileSize for the given uploadedFileID Future updateSizeForUploadIDs( diff --git a/lib/generated/intl/messages_nl.dart b/lib/generated/intl/messages_nl.dart index 90ac6a215..a114c1bd0 100644 --- a/lib/generated/intl/messages_nl.dart +++ b/lib/generated/intl/messages_nl.dart @@ -23,6 +23,9 @@ class MessageLookup extends MessageLookupByLibrary { static String m0(count) => "${Intl.plural(count, one: 'Bestand toevoegen', other: 'Bestanden toevoegen')}"; + static String m64(storageAmount, endDate) => + "Jouw ${storageAmount} add-on is geldig tot ${endDate}"; + static String m1(emailOrName) => "Toegevoegd door ${emailOrName}"; static String m2(albumName) => "Succesvol toegevoegd aan ${albumName}"; @@ -140,6 +143,9 @@ class MessageLookup extends MessageLookupByLibrary { static String m41(endDate) => "Wordt verlengd op ${endDate}"; + static String m65(count) => + "${Intl.plural(count, one: '${count} resultaat gevonden', other: '${count} resultaten gevonden')}"; + static String m42(count) => "${count} geselecteerd"; static String m43(count, yourCount) => @@ -190,6 +196,8 @@ class MessageLookup extends MessageLookupByLibrary { static String m59(count) => "${Intl.plural(count, zero: '', one: '1 dag', other: '${count} dagen')}"; + static String m66(endDate) => "Geldig tot ${endDate}"; + static String m60(email) => "Verifieer ${email}"; static String m61(email) => @@ -224,6 +232,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Locatie toevoegen"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Toevoegen"), "addMore": MessageLookupByLibrary.simpleMessage("Meer toevoegen"), + "addNew": MessageLookupByLibrary.simpleMessage("Nieuwe toevoegen"), + "addOnPageSubtitle": + MessageLookupByLibrary.simpleMessage("Details van add-ons"), + "addOnValidTill": m64, + "addOns": MessageLookupByLibrary.simpleMessage("Add-ons"), "addPhotos": MessageLookupByLibrary.simpleMessage("Foto\'s toevoegen"), "addSelected": MessageLookupByLibrary.simpleMessage("Voeg geselecteerde toe"), @@ -233,6 +246,8 @@ class MessageLookup extends MessageLookupByLibrary { "addToHiddenAlbum": MessageLookupByLibrary.simpleMessage( "Toevoegen aan verborgen album"), "addViewer": MessageLookupByLibrary.simpleMessage("Voeg kijker toe"), + "addYourPhotosNow": + MessageLookupByLibrary.simpleMessage("Voeg nu je foto\'s toe"), "addedAs": MessageLookupByLibrary.simpleMessage("Toegevoegd als"), "addedBy": m1, "addedSuccessfullyTo": m2, @@ -354,6 +369,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Back-up instellingen"), "backupVideos": MessageLookupByLibrary.simpleMessage("Back-up video\'s"), + "blackFridaySale": + MessageLookupByLibrary.simpleMessage("Black Friday-aanbieding"), "blog": MessageLookupByLibrary.simpleMessage("Blog"), "cachedData": MessageLookupByLibrary.simpleMessage("Cachegegevens"), "calculating": MessageLookupByLibrary.simpleMessage("Berekenen..."), @@ -441,7 +458,8 @@ class MessageLookup extends MessageLookupByLibrary { "contactSupport": MessageLookupByLibrary.simpleMessage("Contacteer klantenservice"), "contactToManageSubscription": m10, - "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), + "contacts": MessageLookupByLibrary.simpleMessage("Contacten"), + "contents": MessageLookupByLibrary.simpleMessage("Inhoud"), "continueLabel": MessageLookupByLibrary.simpleMessage("Doorgaan"), "continueOnFreeTrial": MessageLookupByLibrary.simpleMessage( "Doorgaan met gratis proefversie"), @@ -563,6 +581,7 @@ class MessageLookup extends MessageLookupByLibrary { "discord": MessageLookupByLibrary.simpleMessage("Discord"), "dismiss": MessageLookupByLibrary.simpleMessage("Afwijzen"), "distanceInKMUnit": MessageLookupByLibrary.simpleMessage("km"), + "doNotSignOut": MessageLookupByLibrary.simpleMessage("Niet uitloggen"), "doThisLater": MessageLookupByLibrary.simpleMessage("Doe dit later"), "doYouWantToDiscardTheEditsYouHaveMade": MessageLookupByLibrary.simpleMessage( @@ -652,6 +671,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Logboek exporteren"), "exportYourData": MessageLookupByLibrary.simpleMessage("Exporteer je gegevens"), + "faces": MessageLookupByLibrary.simpleMessage("Gezichten"), "failedToApplyCode": MessageLookupByLibrary.simpleMessage("Code toepassen mislukt"), "failedToCancel": @@ -685,7 +705,9 @@ class MessageLookup extends MessageLookupByLibrary { "Voeg een beschrijving toe..."), "fileSavedToGallery": MessageLookupByLibrary.simpleMessage( "Bestand opgeslagen in galerij"), - "fileTypes": MessageLookupByLibrary.simpleMessage("File types"), + "fileTypes": MessageLookupByLibrary.simpleMessage("Bestandstype"), + "fileTypesAndNames": + MessageLookupByLibrary.simpleMessage("Bestandstypen en namen"), "filesBackedUpFromDevice": m19, "filesBackedUpInAlbum": m20, "filesDeleted": @@ -723,6 +745,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Toestemming verlenen"), "groupNearbyPhotos": MessageLookupByLibrary.simpleMessage("Groep foto\'s in de buurt"), + "hearUsExplanation": MessageLookupByLibrary.simpleMessage( + "Wij gebruiken geen tracking. Het zou helpen als je ons vertelt waar je ons gevonden hebt!"), + "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( + "Hoe hoorde je over Ente? (optioneel)"), "hidden": MessageLookupByLibrary.simpleMessage("Verborgen"), "hide": MessageLookupByLibrary.simpleMessage("Verbergen"), "hiding": MessageLookupByLibrary.simpleMessage("Verbergen..."), @@ -799,6 +825,7 @@ class MessageLookup extends MessageLookupByLibrary { "linkHasExpired": MessageLookupByLibrary.simpleMessage("Link is vervallen"), "linkNeverExpires": MessageLookupByLibrary.simpleMessage("Nooit"), + "livePhotos": MessageLookupByLibrary.simpleMessage("Live foto"), "loadMessage1": MessageLookupByLibrary.simpleMessage( "U kunt uw abonnement met uw familie delen"), "loadMessage2": MessageLookupByLibrary.simpleMessage( @@ -863,7 +890,8 @@ class MessageLookup extends MessageLookupByLibrary { "moderateStrength": MessageLookupByLibrary.simpleMessage("Matig"), "modifyYourQueryOrTrySearchingFor": MessageLookupByLibrary.simpleMessage( - "Modify your query, or try searching for"), + "Pas je zoekopdracht aan of zoek naar"), + "moments": MessageLookupByLibrary.simpleMessage("Momenten"), "monthly": MessageLookupByLibrary.simpleMessage("Maandelijks"), "moveItem": m30, "moveToAlbum": @@ -876,6 +904,10 @@ class MessageLookup extends MessageLookupByLibrary { "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Bestanden verplaatsen naar album..."), "name": MessageLookupByLibrary.simpleMessage("Naam"), + "networkConnectionRefusedErr": MessageLookupByLibrary.simpleMessage( + "Kan geen verbinding maken met Ente, probeer het later opnieuw. Als de fout zich blijft voordoen, neem dan contact op met support."), + "networkHostLookUpErr": MessageLookupByLibrary.simpleMessage( + "Kan geen verbinding maken met Ente, controleer uw netwerkinstellingen en neem contact op met ondersteuning als de fout zich blijft voordoen."), "never": MessageLookupByLibrary.simpleMessage("Nooit"), "newAlbum": MessageLookupByLibrary.simpleMessage("Nieuw album"), "newToEnte": MessageLookupByLibrary.simpleMessage("Nieuw bij ente"), @@ -894,6 +926,8 @@ class MessageLookup extends MessageLookupByLibrary { "Geen verborgen foto\'s of video\'s"), "noImagesWithLocation": MessageLookupByLibrary.simpleMessage( "Geen afbeeldingen met locatie"), + "noInternetConnection": + MessageLookupByLibrary.simpleMessage("Geen internetverbinding"), "noPhotosAreBeingBackedUpRightNow": MessageLookupByLibrary.simpleMessage( "Er worden momenteel geen foto\'s geback-upt"), @@ -952,9 +986,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Permanent verwijderen"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage( "Permanent verwijderen van apparaat?"), + "photoDescriptions": + MessageLookupByLibrary.simpleMessage("Foto beschrijvingen"), "photoGridSize": MessageLookupByLibrary.simpleMessage("Foto raster grootte"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("foto"), + "photos": MessageLookupByLibrary.simpleMessage("Foto\'s"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage( "Foto\'s toegevoegd door u zullen worden verwijderd uit het album"), @@ -965,6 +1002,9 @@ class MessageLookup extends MessageLookupByLibrary { "playStoreFreeTrialValidTill": m35, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("PlayStore abonnement"), + "pleaseCheckYourInternetConnectionAndTryAgain": + MessageLookupByLibrary.simpleMessage( + "Controleer je internetverbinding en probeer het opnieuw."), "pleaseContactSupportAndWeWillBeHappyToHelp": MessageLookupByLibrary.simpleMessage( "Neem alstublieft contact op met support@ente.io en we helpen u graag!"), @@ -1119,12 +1159,36 @@ class MessageLookup extends MessageLookupByLibrary { "scanThisBarcodeWithnyourAuthenticatorApp": MessageLookupByLibrary.simpleMessage( "Scan deze barcode met\nje authenticator app"), + "searchAlbumsEmptySection": + MessageLookupByLibrary.simpleMessage("Albums"), "searchByAlbumNameHint": MessageLookupByLibrary.simpleMessage("Albumnaam"), "searchByExamples": MessageLookupByLibrary.simpleMessage( "• Albumnamen (bijv. \"Camera\")\n• Types van bestanden (bijv. \"Video\'s\", \".gif\")\n• Jaren en maanden (bijv. \"2022\", \"januari\")\n• Feestdagen (bijv. \"Kerstmis\")\n• Fotobeschrijvingen (bijv. \"#fun\")"), + "searchCaptionEmptySection": MessageLookupByLibrary.simpleMessage( + "Voeg beschrijvingen zoals \"#weekendje weg\" toe in foto-info om ze snel hier te vinden"), + "searchDatesEmptySection": MessageLookupByLibrary.simpleMessage( + "Zoeken op een datum, maand of jaar"), + "searchFaceEmptySection": MessageLookupByLibrary.simpleMessage( + "Vind alle foto\'s van een persoon"), + "searchFileTypesAndNamesEmptySection": + MessageLookupByLibrary.simpleMessage("Bestandstypen en namen"), + "searchHint1": + MessageLookupByLibrary.simpleMessage("Snelle, lokale zoekfunctie"), + "searchHint2": + MessageLookupByLibrary.simpleMessage("Foto datums, beschrijvingen"), + "searchHint3": MessageLookupByLibrary.simpleMessage( + "Albums, bestandsnamen en typen"), + "searchHint4": MessageLookupByLibrary.simpleMessage("Locatie"), + "searchHint5": MessageLookupByLibrary.simpleMessage( + "Binnenkort beschikbaar: Gezichten & magische zoekopdrachten ✨"), "searchHintText": MessageLookupByLibrary.simpleMessage( "Albums, maanden, dagen, jaren, ..."), + "searchLocationEmptySection": MessageLookupByLibrary.simpleMessage( + "Foto\'s groeperen die in een bepaalde straal van een foto worden genomen"), + "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage( + "Nodig mensen uit, en je ziet alle foto\'s die door hen worden gedeeld hier"), + "searchResultCount": m65, "security": MessageLookupByLibrary.simpleMessage("Beveiliging"), "selectAlbum": MessageLookupByLibrary.simpleMessage("Album selecteren"), "selectAll": MessageLookupByLibrary.simpleMessage("Selecteer alles"), @@ -1199,6 +1263,12 @@ class MessageLookup extends MessageLookupByLibrary { "sharing": MessageLookupByLibrary.simpleMessage("Delen..."), "showMemories": MessageLookupByLibrary.simpleMessage("Toon herinneringen"), + "signOutFromOtherDevices": + MessageLookupByLibrary.simpleMessage("Log uit op andere apparaten"), + "signOutOtherBody": MessageLookupByLibrary.simpleMessage( + "Als je denkt dat iemand je wachtwoord zou kunnen kennen, kun je alle andere apparaten die je account gebruiken dwingen om uit te loggen."), + "signOutOtherDevices": + MessageLookupByLibrary.simpleMessage("Log uit op andere apparaten"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Ik ga akkoord met de gebruiksvoorwaarden en privacybeleid"), "singleFileDeleteFromDevice": m49, @@ -1371,6 +1441,8 @@ class MessageLookup extends MessageLookupByLibrary { "upgrade": MessageLookupByLibrary.simpleMessage("Upgraden"), "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Bestanden worden geüpload naar album..."), + "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( + "Tot 50% korting, tot 4 december."), "usableReferralStorageInfo": MessageLookupByLibrary.simpleMessage( "Bruikbare opslag is beperkt door je huidige abonnement. Buitensporige geclaimde opslag zal automatisch bruikbaar worden wanneer je je abonnement upgrade."), "usePublicLinksForPeopleNotOnEnte": @@ -1381,6 +1453,7 @@ class MessageLookup extends MessageLookupByLibrary { "useSelectedPhoto": MessageLookupByLibrary.simpleMessage("Gebruik geselecteerde foto"), "usedSpace": MessageLookupByLibrary.simpleMessage("Gebruikte ruimte"), + "validTill": m66, "verificationFailedPleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Verificatie mislukt, probeer het opnieuw"), @@ -1396,8 +1469,11 @@ class MessageLookup extends MessageLookupByLibrary { "verifyingRecoveryKey": MessageLookupByLibrary.simpleMessage( "Herstelsleutel verifiëren..."), "videoSmallCase": MessageLookupByLibrary.simpleMessage("video"), + "videos": MessageLookupByLibrary.simpleMessage("Video\'s"), "viewActiveSessions": MessageLookupByLibrary.simpleMessage("Actieve sessies bekijken"), + "viewAddOnButton": + MessageLookupByLibrary.simpleMessage("Add-ons bekijken"), "viewAll": MessageLookupByLibrary.simpleMessage("Alles weergeven"), "viewAllExifData": MessageLookupByLibrary.simpleMessage("Bekijk alle EXIF gegevens"), @@ -1449,7 +1525,7 @@ class MessageLookup extends MessageLookupByLibrary { "youHaveSuccessfullyFreedUp": m63, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("Je account is verwijderd"), - "yourMap": MessageLookupByLibrary.simpleMessage("Your map"), + "yourMap": MessageLookupByLibrary.simpleMessage("Jouw kaart"), "yourPlanWasSuccessfullyDowngraded": MessageLookupByLibrary.simpleMessage( "Uw abonnement is succesvol gedegradeerd"), diff --git a/lib/generated/intl/messages_zh.dart b/lib/generated/intl/messages_zh.dart index ea6653363..e87e6a5cc 100644 --- a/lib/generated/intl/messages_zh.dart +++ b/lib/generated/intl/messages_zh.dart @@ -738,6 +738,10 @@ class MessageLookup extends MessageLookupByLibrary { "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage("正在将文件移动到相册..."), "name": MessageLookupByLibrary.simpleMessage("名称"), + "networkConnectionRefusedErr": MessageLookupByLibrary.simpleMessage( + "无法连接到 Ente,请稍后重试。如果错误仍然存在,请联系支持人员。"), + "networkHostLookUpErr": MessageLookupByLibrary.simpleMessage( + "无法连接到 Ente,请检查您的网络设置,如果错误仍然存在,请联系支持人员。"), "never": MessageLookupByLibrary.simpleMessage("永不"), "newAlbum": MessageLookupByLibrary.simpleMessage("新建相册"), "newToEnte": MessageLookupByLibrary.simpleMessage("刚来到ente"), diff --git a/lib/l10n/intl_nl.arb b/lib/l10n/intl_nl.arb index 83a113847..970a33c12 100644 --- a/lib/l10n/intl_nl.arb +++ b/lib/l10n/intl_nl.arb @@ -557,6 +557,8 @@ "faqs": "Veelgestelde vragen", "renewsOn": "Wordt verlengd op {endDate}", "freeTrialValidTill": "Gratis proefversie geldig tot {endDate}", + "validTill": "Geldig tot {endDate}", + "addOnValidTill": "Jouw {storageAmount} add-on is geldig tot {endDate}", "playStoreFreeTrialValidTill": "Gratis proefperiode geldig tot {endDate}.\nU kunt naderhand een betaald abonnement kiezen.", "subWillBeCancelledOn": "Uw abonnement loopt af op {endDate}", "subscription": "Abonnement", @@ -927,6 +929,8 @@ "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Het lijkt erop dat er iets fout is gegaan. Probeer het later opnieuw. Als de fout zich blijft voordoen, neem dan contact op met ons supportteam.", "error": "Foutmelding", "tempErrorContactSupportIfPersists": "Het lijkt erop dat er iets fout is gegaan. Probeer het later opnieuw. Als de fout zich blijft voordoen, neem dan contact op met ons supportteam.", + "networkHostLookUpErr": "Kan geen verbinding maken met Ente, controleer uw netwerkinstellingen en neem contact op met ondersteuning als de fout zich blijft voordoen.", + "networkConnectionRefusedErr": "Kan geen verbinding maken met Ente, probeer het later opnieuw. Als de fout zich blijft voordoen, neem dan contact op met support.", "cachedData": "Cachegegevens", "clearCaches": "Cache legen", "remoteImages": "Externe afbeeldingen", @@ -955,12 +959,22 @@ "loadMessage7": "Onze mobiele apps draaien op de achtergrond om alle nieuwe foto's die je maakt te versleutelen en te back-uppen", "loadMessage8": "web.ente.io heeft een vlotte uploader", "loadMessage9": "We gebruiken Xchacha20Poly1305 om uw gegevens veilig te versleutelen", + "photoDescriptions": "Foto beschrijvingen", + "fileTypesAndNames": "Bestandstypen en namen", + "location": "Locatie", + "moments": "Momenten", + "searchFaceEmptySection": "Vind alle foto's van een persoon", + "searchDatesEmptySection": "Zoeken op een datum, maand of jaar", + "searchLocationEmptySection": "Foto's groeperen die in een bepaalde straal van een foto worden genomen", + "searchPeopleEmptySection": "Nodig mensen uit, en je ziet alle foto's die door hen worden gedeeld hier", + "searchAlbumsEmptySection": "Albums", + "searchFileTypesAndNamesEmptySection": "Bestandstypen en namen", + "searchCaptionEmptySection": "Voeg beschrijvingen zoals \"#weekendje weg\" toe in foto-info om ze snel hier te vinden", "language": "Taal", "selectLanguage": "Taal selecteren", "locationName": "Locatie naam", "addLocation": "Locatie toevoegen", "groupNearbyPhotos": "Groep foto's in de buurt", - "location": "Locatie", "kiloMeterUnit": "km", "addLocationButton": "Toevoegen", "radius": "Straal", @@ -1102,9 +1116,47 @@ "crashReporting": "Crash rapportering", "addToHiddenAlbum": "Toevoegen aan verborgen album", "moveToHiddenAlbum": "Verplaatsen naar verborgen album", - "fileTypes": "File types", + "fileTypes": "Bestandstype", "deleteConfirmDialogBody": "Dit account is gekoppeld aan andere ente apps, als je er gebruik van maakt.\\n\\nJe geüploade gegevens worden in alle ente apps gepland voor verwijdering, en je account wordt permanent verwijderd voor alle ente diensten.", - "yourMap": "Your map", - "modifyYourQueryOrTrySearchingFor": "Modify your query, or try searching for", - "contacts": "Contacts" + "hearUsWhereTitle": "Hoe hoorde je over Ente? (optioneel)", + "hearUsExplanation": "Wij gebruiken geen tracking. Het zou helpen als je ons vertelt waar je ons gevonden hebt!", + "viewAddOnButton": "Add-ons bekijken", + "addOns": "Add-ons", + "addOnPageSubtitle": "Details van add-ons", + "yourMap": "Jouw kaart", + "modifyYourQueryOrTrySearchingFor": "Pas je zoekopdracht aan of zoek naar", + "blackFridaySale": "Black Friday-aanbieding", + "upto50OffUntil4thDec": "Tot 50% korting, tot 4 december.", + "photos": "Foto's", + "videos": "Video's", + "livePhotos": "Live foto", + "searchHint1": "Snelle, lokale zoekfunctie", + "searchHint2": "Foto datums, beschrijvingen", + "searchHint3": "Albums, bestandsnamen en typen", + "searchHint4": "Locatie", + "searchHint5": "Binnenkort beschikbaar: Gezichten & magische zoekopdrachten ✨", + "addYourPhotosNow": "Voeg nu je foto's toe", + "searchResultCount": "{count, plural, one{{count} resultaat gevonden} other{{count} resultaten gevonden}}", + "@searchResultCount": { + "description": "Text to tell user how many results were found for their search query", + "placeholders": { + "count": { + "example": "1|2|3", + "type": "int" + } + } + }, + "faces": "Gezichten", + "contents": "Inhoud", + "addNew": "Nieuwe toevoegen", + "@addNew": { + "description": "Text to add a new item (location tag, album, caption etc)" + }, + "contacts": "Contacten", + "noInternetConnection": "Geen internetverbinding", + "pleaseCheckYourInternetConnectionAndTryAgain": "Controleer je internetverbinding en probeer het opnieuw.", + "signOutFromOtherDevices": "Log uit op andere apparaten", + "signOutOtherBody": "Als je denkt dat iemand je wachtwoord zou kunnen kennen, kun je alle andere apparaten die je account gebruiken dwingen om uit te loggen.", + "signOutOtherDevices": "Log uit op andere apparaten", + "doNotSignOut": "Niet uitloggen" } \ No newline at end of file diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index 1b11dafad..f43ff8e25 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -929,6 +929,8 @@ "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "看起来出了点问题。 请稍后重试。 如果错误仍然存在,请联系我们的支持团队。", "error": "错误", "tempErrorContactSupportIfPersists": "看起来出了点问题。 请稍后重试。 如果错误仍然存在,请联系我们的支持团队。", + "networkHostLookUpErr": "无法连接到 Ente,请检查您的网络设置,如果错误仍然存在,请联系支持人员。", + "networkConnectionRefusedErr": "无法连接到 Ente,请稍后重试。如果错误仍然存在,请联系支持人员。", "cachedData": "缓存数据", "clearCaches": "清除缓存", "remoteImages": "远程图像", diff --git a/lib/main.dart b/lib/main.dart index ef1870783..1415ac4e9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -65,8 +65,8 @@ void main() async { MediaKit.ensureInitialized(); final savedThemeMode = await AdaptiveTheme.getThemeMode(); await _runInForeground(savedThemeMode); - BackgroundFetch.registerHeadlessTask(_headlessTaskHandler); - FlutterDisplayMode.setHighRefreshRate(); + unawaited(BackgroundFetch.registerHeadlessTask(_headlessTaskHandler)); + FlutterDisplayMode.setHighRefreshRate().ignore(); } Future _runInForeground(AdaptiveThemeMode? savedThemeMode) async { @@ -129,7 +129,7 @@ Future _runInBackground(String taskId) async { _scheduleSuicide(kBGTaskTimeout, taskId); // To prevent OS from punishing us } await _init(true, via: 'runViaBackgroundTask'); - UpdateService.instance.showUpdateNotification(); + UpdateService.instance.showUpdateNotification().ignore(); await _sync('bgSync'); BackgroundFetch.finish(taskId); } @@ -158,7 +158,7 @@ Future _init(bool isBackground, {String via = ''}) async { AppLifecycleService.instance.onAppInForeground('init via: $via'); } // Start workers asynchronously. No need to wait for them to start - Computer.shared().turnOn(workersCount: 4, verbose: kDebugMode); + Computer.shared().turnOn(workersCount: 4, verbose: kDebugMode).ignore(); CryptoUtil.init(); await NetworkClient.instance.init(); await Configuration.instance.init(); diff --git a/lib/models/file/extensions/file_props.dart b/lib/models/file/extensions/file_props.dart index 2ecffd1ab..b3f5ae672 100644 --- a/lib/models/file/extensions/file_props.dart +++ b/lib/models/file/extensions/file_props.dart @@ -2,6 +2,7 @@ import "package:photos/core/configuration.dart"; import "package:photos/models/file/file.dart"; import "package:photos/models/file/file_type.dart"; import "package:photos/models/file/trash_file.dart"; +import "package:photos/services/collections_service.dart"; extension FilePropsExtn on EnteFile { bool get isLivePhoto => fileType == FileType.livePhoto; @@ -21,4 +22,14 @@ extension FilePropsExtn on EnteFile { bool get isCollect => uploaderName != null; String? get uploaderName => pubMagicMetadata?.uploaderName; + + bool canReUpload(int userID) => + localID != null && + localID!.isNotEmpty && + isOwner && + collectionID != null && + (CollectionsService.instance + .getCollectionByID(collectionID!) + ?.isOwner(userID) ?? + false); } diff --git a/lib/models/search/search_types.dart b/lib/models/search/search_types.dart index 189569e2e..a8d00ee74 100644 --- a/lib/models/search/search_types.dart +++ b/lib/models/search/search_types.dart @@ -181,7 +181,7 @@ extension SectionTypeExtensions on SectionType { switch (this) { case SectionType.contacts: return () async { - shareText( + await shareText( S.of(context).shareTextRecommendUsingEnte, ); }; @@ -210,7 +210,7 @@ extension SectionTypeExtensions on SectionType { try { final Collection c = await CollectionsService.instance.createAlbum(text); - routeToPage( + await routeToPage( context, CollectionPage(CollectionWithThumbnail(c, null)), ); @@ -222,7 +222,7 @@ extension SectionTypeExtensions on SectionType { }, ); if (result is Exception) { - showGenericErrorDialog(context: context, error: result); + await showGenericErrorDialog(context: context, error: result); } }; default: diff --git a/lib/services/billing_service.dart b/lib/services/billing_service.dart index 5b5c57258..d565149fc 100644 --- a/lib/services/billing_service.dart +++ b/lib/services/billing_service.dart @@ -184,7 +184,7 @@ class BillingService { try { final String jwtToken = await UserService.instance.getFamiliesToken(); final bool familyExist = userDetails.isPartOfFamily(); - Navigator.of(context).push( + await Navigator.of(context).push( MaterialPageRoute( builder: (BuildContext context) { return WebPage( @@ -196,7 +196,7 @@ class BillingService { ); } catch (e) { await dialog.hide(); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); } await dialog.hide(); } diff --git a/lib/services/entity_service.dart b/lib/services/entity_service.dart index a89b44f58..bc9d10b64 100644 --- a/lib/services/entity_service.dart +++ b/lib/services/entity_service.dart @@ -163,7 +163,7 @@ class EntityService { encryptedKey = response.encryptedKey; header = response.header; await _prefs.setString(_getEntityKeyPrefix(type), encryptedKey); - _prefs.setString(_getEntityHeaderPrefix(type), header); + await _prefs.setString(_getEntityHeaderPrefix(type), header); } final entityKey = CryptoUtil.decryptSync( Sodium.base642bin(encryptedKey), diff --git a/lib/services/files_service.dart b/lib/services/files_service.dart index 8d50fa9f2..d97b8a25e 100644 --- a/lib/services/files_service.dart +++ b/lib/services/files_service.dart @@ -49,11 +49,7 @@ class FilesService { if (uploadIDsWithMissingSize.isEmpty) { return Future.value(true); } - final batchedFiles = uploadIDsWithMissingSize.chunks(1000); - for (final batch in batchedFiles) { - final Map uploadIdToSize = await getFilesSizeFromInfo(batch); - await _filesDB.updateSizeForUploadIDs(uploadIdToSize); - } + await backFillSizes(uploadIDsWithMissingSize); return Future.value(true); } catch (e, s) { _logger.severe("error during has migrated sizes", e, s); @@ -61,6 +57,14 @@ class FilesService { } } + Future backFillSizes(List uploadIDsWithMissingSize) async { + final batchedFiles = uploadIDsWithMissingSize.chunks(1000); + for (final batch in batchedFiles) { + final Map uploadIdToSize = await getFilesSizeFromInfo(batch); + await _filesDB.updateSizeForUploadIDs(uploadIdToSize); + } + } + Future> getFilesSizeFromInfo(List uploadedFileID) async { try { final response = await _enteDio.post( diff --git a/lib/services/hidden_service.dart b/lib/services/hidden_service.dart index a90dbc037..711b3af18 100644 --- a/lib/services/hidden_service.dart +++ b/lib/services/hidden_service.dart @@ -154,7 +154,7 @@ extension HiddenService on CollectionsService { } catch (e, s) { _logger.severe("Could not hide", e, s); await dialog.hide(); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); return false; } finally { await dialog.hide(); diff --git a/lib/services/local_authentication_service.dart b/lib/services/local_authentication_service.dart index 9544fb442..98c029d0b 100644 --- a/lib/services/local_authentication_service.dart +++ b/lib/services/local_authentication_service.dart @@ -1,3 +1,5 @@ +import "dart:async"; + import 'package:flutter/material.dart'; import 'package:local_auth/local_auth.dart'; import 'package:photos/core/configuration.dart'; @@ -22,7 +24,7 @@ class LocalAuthenticationService { Configuration.instance.shouldShowLockScreen(), ); if (!result) { - showToast(context, infoMessage); + unawaited(showToast(context, infoMessage)); return false; } else { return true; @@ -54,10 +56,12 @@ class LocalAuthenticationService { .setEnabled(Configuration.instance.shouldShowLockScreen()); } } else { - showErrorDialog( - context, - errorDialogTitle, - errorDialogContent, + unawaited( + showErrorDialog( + context, + errorDialogTitle, + errorDialogContent, + ), ); } return false; diff --git a/lib/services/local_file_update_service.dart b/lib/services/local_file_update_service.dart index 52ba069fb..d77e0c12b 100644 --- a/lib/services/local_file_update_service.dart +++ b/lib/services/local_file_update_service.dart @@ -7,8 +7,10 @@ import "package:photos/core/configuration.dart"; import 'package:photos/core/errors.dart'; import 'package:photos/db/file_updation_db.dart'; import 'package:photos/db/files_db.dart'; +import "package:photos/extensions/stop_watch.dart"; import 'package:photos/models/file/file.dart'; import 'package:photos/models/file/file_type.dart'; +import "package:photos/services/files_service.dart"; import 'package:photos/utils/file_uploader_util.dart'; import 'package:photos/utils/file_util.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -19,6 +21,9 @@ class LocalFileUpdateService { late FileUpdationDB _fileUpdationDB; late SharedPreferences _prefs; late Logger _logger; + final String _iosLivePhotoSizeMigrationDone = 'fm_ios_live_photo_size'; + final String _doneLivePhotoImport = 'fm_import_ios_live_photo_size'; + static int fourMBWithChunkSize = 4194338; final List _oldMigrationKeys = [ 'fm_badCreationTime', 'fm_badCreationTimeCompleted', @@ -52,6 +57,8 @@ class LocalFileUpdateService { await _markFilesWhichAreActuallyUpdated(); if (Platform.isAndroid) { _cleanUpOlderMigration().ignore(); + } else { + await _handleLivePhotosSizedCheck(); } } catch (e, s) { _logger.severe('failed to perform migration', e, s); @@ -199,6 +206,146 @@ class LocalFileUpdateService { ); } + Future _handleLivePhotosSizedCheck() async { + try { + if (_prefs.containsKey(_iosLivePhotoSizeMigrationDone)) { + return; + } + await _importLivePhotoReUploadCandidates(); + final sTime = DateTime.now().microsecondsSinceEpoch; + // singleRunLimit indicates number of files to check during single + // invocation of this method. The limit act as a crude way to limit the + // resource consumed by the method + const int singleRunLimit = 50; + final localIDsToProcess = + await _fileUpdationDB.getLocalIDsForPotentialReUpload( + singleRunLimit, + FileUpdationDB.livePhotoSize, + ); + if (localIDsToProcess.isNotEmpty) { + await _checkLivePhotoWithLowOrUnknownSize( + localIDsToProcess, + ); + final eTime = DateTime.now().microsecondsSinceEpoch; + final d = Duration(microseconds: eTime - sTime); + _logger.info( + 'Performed hashCheck for ${localIDsToProcess.length} livePhoto files ' + 'completed in ${d.inSeconds.toString()} secs', + ); + } else { + _prefs.setBool(_iosLivePhotoSizeMigrationDone, true); + } + } catch (e, s) { + _logger.severe('error while checking livePhotoSize check', e, s); + } + } + + Future _checkLivePhotoWithLowOrUnknownSize( + List localIDsToProcess, + ) async { + final int userID = Configuration.instance.getUserID()!; + final List result = + await FilesDB.instance.getLocalFiles(localIDsToProcess); + final List localFilesForUser = []; + final Set localIDsWithFile = {}; + final Set missingSizeIDs = {}; + for (EnteFile file in result) { + if (file.ownerID == null || file.ownerID == userID) { + localFilesForUser.add(file); + localIDsWithFile.add(file.localID!); + if (file.isUploaded && file.fileSize == null) { + missingSizeIDs.add(file.uploadedFileID!); + } + } + } + if (missingSizeIDs.isNotEmpty) { + await FilesService.instance.backFillSizes(missingSizeIDs.toList()); + _logger.info('sizes back fill for ${missingSizeIDs.length} files'); + // return early, let the check run in the next batch + return; + } + + final Set processedIDs = {}; + // if a file for localID doesn't exist, then mark it as processed + // otherwise the app will be stuck in retrying same set of ids + + for (String localID in localIDsToProcess) { + if (!localIDsWithFile.contains(localID)) { + processedIDs.add(localID); + } + } + _logger.info(" check ${localIDsToProcess.length} files for livePhotoSize, " + "missing file cnt ${processedIDs.length}"); + + for (EnteFile file in localFilesForUser) { + if (file.fileSize == null) { + _logger.info('fileSize still null, skip this file'); + continue; + } else if (file.fileType != FileType.livePhoto) { + _logger.severe('fileType is not livePhoto, skip this file'); + continue; + } else if (file.fileSize! != fourMBWithChunkSize) { + // back-filled size is not of our interest + processedIDs.add(file.localID!); + continue; + } + if (processedIDs.contains(file.localID)) { + continue; + } + try { + final MediaUploadData uploadData = await getUploadData(file); + _logger.info( + 'Found livePhoto on local with hash ${uploadData.hashData?.fileHash ?? "null"} and existing hash ${file.hash ?? "null"}'); + await clearCache(file); + await FilesDB.instance.markFilesForReUpload( + userID, + file.localID!, + file.title, + file.location, + file.creationTime!, + file.modificationTime!, + file.fileType, + ); + processedIDs.add(file.localID!); + } on InvalidFileError catch (e) { + if (e.reason == InvalidReason.livePhotoToImageTypeChanged || + e.reason == InvalidReason.imageToLivePhotoTypeChanged) { + // let existing file update check handle this case + _fileUpdationDB.insertMultiple( + [file.localID!], + FileUpdationDB.modificationTimeUpdated, + ).ignore(); + } else { + _logger.severe("livePhoto check failed: invalid file ${file.tag}", e); + } + processedIDs.add(file.localID!); + } catch (e) { + _logger.severe("livePhoto check failed", e); + } finally {} + } + await _fileUpdationDB.deleteByLocalIDs( + processedIDs.toList(), + FileUpdationDB.livePhotoSize, + ); + } + + Future _importLivePhotoReUploadCandidates() async { + if (_prefs.containsKey(_doneLivePhotoImport)) { + return; + } + _logger.info('_importLivePhotoReUploadCandidates'); + final EnteWatch watch = EnteWatch("_importLivePhotoReUploadCandidates"); + final int ownerID = Configuration.instance.getUserID()!; + final List localIDs = await FilesDB.instance + .getLivePhotosWithBadSize(ownerID, fourMBWithChunkSize); + await _fileUpdationDB.insertMultiple( + localIDs, + FileUpdationDB.livePhotoSize, + ); + watch.log("imported ${localIDs.length} files"); + await _prefs.setBool(_doneLivePhotoImport, true); + } + Future getUploadData(EnteFile file) async { final mediaUploadData = await getUploadDataFromEnteFile(file); // delete the file from app's internal cache if it was copied to app diff --git a/lib/services/remote_sync_service.dart b/lib/services/remote_sync_service.dart index 7270ab52d..b54b1e108 100644 --- a/lib/services/remote_sync_service.dart +++ b/lib/services/remote_sync_service.dart @@ -552,12 +552,27 @@ class RemoteSyncService { .info("Skipping some updated files as we are throttling uploads"); break; } - final file = await _db.getUploadedLocalFileInAnyCollection( + final allFiles = await _db.getFilesInAllCollection( uploadedFileID, ownerID, ); - if (file != null) { - _uploadFile(file, file.collectionID!, futures); + if (allFiles.isEmpty) { + _logger.warning("No files found for uploadedFileID $uploadedFileID"); + continue; + } + EnteFile? fileInCollectionOwnedByUser; + for (final file in allFiles) { + if (file.canReUpload(ownerID)) { + fileInCollectionOwnedByUser = file; + break; + } + } + if (fileInCollectionOwnedByUser != null) { + _uploadFile( + fileInCollectionOwnedByUser, + fileInCollectionOwnedByUser.collectionID!, + futures, + ); } } diff --git a/lib/services/user_service.dart b/lib/services/user_service.dart index 954891fd3..f6810759d 100644 --- a/lib/services/user_service.dart +++ b/lib/services/user_service.dart @@ -338,7 +338,7 @@ class UserService { Widget page; final String twoFASessionID = response.data["twoFactorSessionID"]; if (twoFASessionID.isNotEmpty) { - setTwoFactor(value: true); + await setTwoFactor(value: true); page = TwoFactorAuthenticationPage(twoFASessionID); } else { await _saveConfiguration(response); @@ -354,7 +354,7 @@ class UserService { ); } } - Navigator.of(context).pushAndRemoveUntil( + await Navigator.of(context).pushAndRemoveUntil( MaterialPageRoute( builder: (BuildContext context) { return page; @@ -740,9 +740,10 @@ class UserService { ); await dialog.hide(); if (response.statusCode == 200) { - showShortToast(context, S.of(context).authenticationSuccessful); + showShortToast(context, S.of(context).authenticationSuccessful) + .ignore(); await _saveConfiguration(response); - Navigator.of(context).pushAndRemoveUntil( + await Navigator.of(context).pushAndRemoveUntil( MaterialPageRoute( builder: (BuildContext context) { return const PasswordReentryPage(); @@ -755,8 +756,8 @@ class UserService { await dialog.hide(); _logger.severe(e); if (e.response != null && e.response!.statusCode == 404) { - showToast(context, "Session expired"); - Navigator.of(context).pushAndRemoveUntil( + showToast(context, "Session expired").ignore(); + await Navigator.of(context).pushAndRemoveUntil( MaterialPageRoute( builder: (BuildContext context) { return const LoginPage(); @@ -809,7 +810,7 @@ class UserService { } on DioError catch (e) { _logger.severe(e); if (e.response != null && e.response!.statusCode == 404) { - showToast(context, S.of(context).sessionExpired); + showToast(context, S.of(context).sessionExpired).ignore(); Navigator.of(context).pushAndRemoveUntil( MaterialPageRoute( builder: (BuildContext context) { @@ -959,7 +960,7 @@ class UserService { try { recoveryKey = await getOrCreateRecoveryKey(context); } catch (e) { - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); return false; } final dialog = createProgressDialog(context, S.of(context).verifying); diff --git a/lib/states/all_sections_examples_state.dart b/lib/states/all_sections_examples_state.dart index 2cb24063c..c6215c621 100644 --- a/lib/states/all_sections_examples_state.dart +++ b/lib/states/all_sections_examples_state.dart @@ -37,8 +37,8 @@ class _AllSectionsExamplesProviderState final _logger = Logger("AllSectionsExamplesProvider"); final _debouncer = Debouncer( - const Duration(seconds: 4), - executionIntervalInMilliSeconds: 15000, + const Duration(seconds: 3), + executionInterval: const Duration(seconds: 12), ); @override diff --git a/lib/ui/account/delete_account_page.dart b/lib/ui/account/delete_account_page.dart index 8d031deed..f623df8b5 100644 --- a/lib/ui/account/delete_account_page.dart +++ b/lib/ui/account/delete_account_page.dart @@ -289,7 +289,7 @@ class _DeleteAccountPageState extends State { showShortToast(context, S.of(context).yourAccountHasBeenDeleted); } catch (e, s) { Logger("DeleteAccount").severe("failed to delete", e, s); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); } } diff --git a/lib/ui/account/password_entry_page.dart b/lib/ui/account/password_entry_page.dart index 5da5cd03a..48505da47 100644 --- a/lib/ui/account/password_entry_page.dart +++ b/lib/ui/account/password_entry_page.dart @@ -404,7 +404,7 @@ class _PasswordEntryPageState extends State { } catch (e, s) { _logger.severe(e, s); await dialog.hide(); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); } } @@ -456,7 +456,7 @@ class _PasswordEntryPageState extends State { } catch (e, s) { _logger.severe(e, s); await dialog.hide(); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); } } @@ -481,7 +481,7 @@ class _PasswordEntryPageState extends State { S.of(context).sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease, ); } else { - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); } } } diff --git a/lib/ui/account/verify_recovery_page.dart b/lib/ui/account/verify_recovery_page.dart index c22aee355..619a9e090 100644 --- a/lib/ui/account/verify_recovery_page.dart +++ b/lib/ui/account/verify_recovery_page.dart @@ -109,7 +109,7 @@ class _VerifyRecoveryPageState extends State { ), ); } catch (e) { - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); return; } } diff --git a/lib/ui/actions/collection/collection_file_actions.dart b/lib/ui/actions/collection/collection_file_actions.dart index c46003b20..c91394375 100644 --- a/lib/ui/actions/collection/collection_file_actions.dart +++ b/lib/ui/actions/collection/collection_file_actions.dart @@ -73,7 +73,10 @@ extension CollectionFileActions on CollectionActions { ); if (actionResult?.action != null && actionResult!.action == ButtonAction.error) { - showGenericErrorDialog(context: bContext, error: actionResult.exception); + await showGenericErrorDialog( + context: bContext, + error: actionResult.exception, + ); } else { selectedFiles.clearAll(); } @@ -187,7 +190,7 @@ extension CollectionFileActions on CollectionActions { } catch (e, s) { logger.severe("Failed to add to album", e, s); await dialog?.hide(); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); rethrow; } } diff --git a/lib/ui/actions/collection/collection_sharing_actions.dart b/lib/ui/actions/collection/collection_sharing_actions.dart index f4656fe15..9428c56da 100644 --- a/lib/ui/actions/collection/collection_sharing_actions.dart +++ b/lib/ui/actions/collection/collection_sharing_actions.dart @@ -52,7 +52,7 @@ class CollectionActions { _showUnSupportedAlert(context); } else { logger.severe("Failed to update shareUrl collection", e); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); } return false; } @@ -93,7 +93,10 @@ class CollectionActions { ); if (actionResult?.action != null) { if (actionResult!.action == ButtonAction.error) { - showGenericErrorDialog(context: context, error: actionResult.exception); + await showGenericErrorDialog( + context: context, + error: actionResult.exception, + ); } return actionResult.action == ButtonAction.first; } else { @@ -142,7 +145,7 @@ class CollectionActions { return collection; } catch (e, s) { dialog.hide(); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); logger.severe("Failing to create link for selected files", e, s); } return null; @@ -183,7 +186,10 @@ class CollectionActions { ); if (actionResult?.action != null) { if (actionResult!.action == ButtonAction.error) { - showGenericErrorDialog(context: context, error: actionResult.exception); + await showGenericErrorDialog( + context: context, + error: actionResult.exception, + ); } return actionResult.action == ButtonAction.first; } @@ -230,7 +236,7 @@ class CollectionActions { } catch (e) { await dialog?.hide(); logger.severe("Failed to get public key", e); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); return false; } // getPublicKey can return null when no user is associated with given @@ -272,7 +278,7 @@ class CollectionActions { _showUnSupportedAlert(context); } else { logger.severe("failed to share collection", e); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); } return false; } @@ -353,7 +359,10 @@ class CollectionActions { ); if (actionResult?.action != null && actionResult!.action == ButtonAction.error) { - showGenericErrorDialog(context: bContext, error: actionResult.exception); + await showGenericErrorDialog( + context: bContext, + error: actionResult.exception, + ); return false; } if ((actionResult?.action != null) && diff --git a/lib/ui/actions/file/file_actions.dart b/lib/ui/actions/file/file_actions.dart index 695c53406..f8a0bcad9 100644 --- a/lib/ui/actions/file/file_actions.dart +++ b/lib/ui/actions/file/file_actions.dart @@ -125,7 +125,10 @@ Future showSingleFileDeleteSheet( ); if (actionResult?.action != null && actionResult!.action == ButtonAction.error) { - showGenericErrorDialog(context: context, error: actionResult.exception); + await showGenericErrorDialog( + context: context, + error: actionResult.exception, + ); } } diff --git a/lib/ui/collections/album/vertical_list.dart b/lib/ui/collections/album/vertical_list.dart index c926c8b66..8891cd76b 100644 --- a/lib/ui/collections/album/vertical_list.dart +++ b/lib/ui/collections/album/vertical_list.dart @@ -109,7 +109,7 @@ class AlbumVerticalListWidget extends StatelessWidget { textCapitalization: TextCapitalization.words, ); if (result is Exception) { - showGenericErrorDialog( + await showGenericErrorDialog( context: context, error: result, ); @@ -311,7 +311,7 @@ class AlbumVerticalListWidget extends StatelessWidget { ); return true; } catch (e) { - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); return false; } } @@ -334,7 +334,7 @@ class AlbumVerticalListWidget extends StatelessWidget { ), ); } else { - showGenericErrorDialog(context: context, error: result); + await showGenericErrorDialog(context: context, error: result); _logger.severe("Cannot share collections owned by others"); } } @@ -356,7 +356,7 @@ class AlbumVerticalListWidget extends StatelessWidget { showGenericErrorDialog( context: context, error: Exception("Can not share collection owned by others"), - ); + ).ignore(); _logger.severe("Cannot share collections owned by others"); } return Future.value(true); @@ -413,7 +413,7 @@ class AlbumVerticalListWidget extends StatelessWidget { } catch (e, s) { _logger.severe("Could not move to album", e, s); await dialog.hide(); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); return false; } } @@ -442,7 +442,7 @@ class AlbumVerticalListWidget extends StatelessWidget { } catch (e, s) { _logger.severe("Could not move to album", e, s); await dialog.hide(); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); return false; } } diff --git a/lib/ui/collections/device/device_folders_grid_view.dart b/lib/ui/collections/device/device_folders_grid_view.dart index 671f87635..cd3ee47dc 100644 --- a/lib/ui/collections/device/device_folders_grid_view.dart +++ b/lib/ui/collections/device/device_folders_grid_view.dart @@ -12,6 +12,7 @@ import 'package:photos/models/device_collection.dart'; import "package:photos/ui/collections/device/device_folder_item.dart"; import 'package:photos/ui/common/loading_widget.dart'; import 'package:photos/ui/viewer/gallery/empty_state.dart'; +import "package:photos/utils/debouncer.dart"; class DeviceFoldersGridView extends StatefulWidget { const DeviceFoldersGridView({ @@ -27,6 +28,10 @@ class _DeviceFoldersGridViewState extends State { StreamSubscription? _localFilesSubscription; String _loadReason = "init"; final _logger = Logger((_DeviceFoldersGridViewState).toString()); + final _debouncer = Debouncer( + const Duration(seconds: 2), + executionInterval: const Duration(seconds: 5), + ); @override void initState() { @@ -39,8 +44,12 @@ class _DeviceFoldersGridViewState extends State { }); _localFilesSubscription = Bus.instance.on().listen((event) { - _loadReason = event.reason; - setState(() {}); + _debouncer.run(() async { + if (mounted) { + _loadReason = event.reason; + setState(() {}); + } + }); }); super.initState(); @@ -93,6 +102,7 @@ class _DeviceFoldersGridViewState extends State { void dispose() { _backupFoldersUpdatedEvent?.cancel(); _localFilesSubscription?.cancel(); + _debouncer.cancelDebounce(); super.dispose(); } } diff --git a/lib/ui/collections/device/device_folders_vertical_grid_view.dart b/lib/ui/collections/device/device_folders_vertical_grid_view.dart index ad7706bd7..7b417c3d6 100644 --- a/lib/ui/collections/device/device_folders_vertical_grid_view.dart +++ b/lib/ui/collections/device/device_folders_vertical_grid_view.dart @@ -13,6 +13,7 @@ import 'package:photos/models/device_collection.dart'; import "package:photos/ui/collections/device/device_folder_item.dart"; import 'package:photos/ui/common/loading_widget.dart'; import 'package:photos/ui/viewer/gallery/empty_state.dart'; +import "package:photos/utils/debouncer.dart"; class DeviceFolderVerticalGridView extends StatelessWidget { final Widget? appTitle; @@ -58,6 +59,10 @@ class _DeviceFolderVerticalGridViewBodyState StreamSubscription? _localFilesSubscription; String _loadReason = "init"; final logger = Logger((_DeviceFolderVerticalGridViewBodyState).toString()); + final _debouncer = Debouncer( + const Duration(milliseconds: 1500), + executionInterval: const Duration(seconds: 4), + ); /* Aspect ratio 1:1 Max width 224 Fixed gap 8 Width changes dynamically with screen width such that we can fit 2 in one row. @@ -78,8 +83,12 @@ class _DeviceFolderVerticalGridViewBodyState }); _localFilesSubscription = Bus.instance.on().listen((event) { - _loadReason = event.reason; - setState(() {}); + _debouncer.run(() async { + if (mounted) { + _loadReason = event.reason; + setState(() {}); + } + }); }); super.initState(); } @@ -149,6 +158,7 @@ class _DeviceFolderVerticalGridViewBodyState void dispose() { _backupFoldersUpdatedEvent?.cancel(); _localFilesSubscription?.cancel(); + _debouncer.cancelDebounce(); super.dispose(); } } diff --git a/lib/ui/collections/new_album_icon.dart b/lib/ui/collections/new_album_icon.dart index 966685cd1..9ec818143 100644 --- a/lib/ui/collections/new_album_icon.dart +++ b/lib/ui/collections/new_album_icon.dart @@ -55,7 +55,7 @@ class NewAlbumIcon extends StatelessWidget { }, ); if (result is Exception) { - showGenericErrorDialog(context: context, error: result); + await showGenericErrorDialog(context: context, error: result); } }, ); diff --git a/lib/ui/components/bottom_action_bar/bottom_action_bar_widget.dart b/lib/ui/components/bottom_action_bar/bottom_action_bar_widget.dart index b562ada81..b896e0f1f 100644 --- a/lib/ui/components/bottom_action_bar/bottom_action_bar_widget.dart +++ b/lib/ui/components/bottom_action_bar/bottom_action_bar_widget.dart @@ -49,13 +49,12 @@ class BottomActionBarWidget extends StatelessWidget { child: Column( mainAxisSize: MainAxisSize.min, children: [ - const SizedBox(height: 12), + const SizedBox(height: 8), FileSelectionActionsWidget( galleryType, selectedFiles, collection: collection, ), - const SizedBox(height: 20), const DividerWidget(dividerType: DividerType.bottomBar), ActionBarWidget( selectedFiles: selectedFiles, diff --git a/lib/ui/components/buttons/button_widget.dart b/lib/ui/components/buttons/button_widget.dart index ed6e53165..2d1b170fe 100644 --- a/lib/ui/components/buttons/button_widget.dart +++ b/lib/ui/components/buttons/button_widget.dart @@ -498,7 +498,7 @@ class _ButtonChildWidgetState extends State { } else if (exception != null) { //This is to show the execution was unsuccessful if the dialog is manually //closed before the execution completes. - showGenericErrorDialog(context: context, error: exception); + showGenericErrorDialog(context: context, error: exception).ignore(); } } } diff --git a/lib/ui/home/home_gallery_widget.dart b/lib/ui/home/home_gallery_widget.dart index 47f6c2ff1..66556213b 100644 --- a/lib/ui/home/home_gallery_widget.dart +++ b/lib/ui/home/home_gallery_widget.dart @@ -28,7 +28,7 @@ class HomeGalleryWidget extends StatelessWidget { @override Widget build(BuildContext context) { - final double bottomSafeArea = MediaQuery.of(context).padding.bottom; + final double bottomSafeArea = MediaQuery.paddingOf(context).bottom; final gallery = Gallery( asyncLoader: (creationStartTime, creationEndTime, {limit, asc}) async { final ownerID = Configuration.instance.getUserID(); @@ -81,6 +81,8 @@ class HomeGalleryWidget extends StatelessWidget { footer: footer, // scrollSafe area -> SafeArea + Preserver more + Nav Bar buttons scrollBottomSafeArea: bottomSafeArea + 180, + reloadDebounceTime: const Duration(seconds: 2), + reloadDebounceExecutionInterval: const Duration(seconds: 5), ); return Stack( alignment: Alignment.bottomCenter, diff --git a/lib/ui/map/map_view.dart b/lib/ui/map/map_view.dart index ce3c1839a..471ca7098 100644 --- a/lib/ui/map/map_view.dart +++ b/lib/ui/map/map_view.dart @@ -42,7 +42,7 @@ class _MapViewState extends State { late List _markers; final _debouncer = Debouncer( const Duration(milliseconds: 300), - executionIntervalInMilliSeconds: 750, + executionInterval: const Duration(milliseconds: 750), ); @override diff --git a/lib/ui/payment/payment_web_page.dart b/lib/ui/payment/payment_web_page.dart index 5bba834d5..e619bc0d8 100644 --- a/lib/ui/payment/payment_web_page.dart +++ b/lib/ui/payment/payment_web_page.dart @@ -190,7 +190,7 @@ class _PaymentWebPageState extends State { } else { // should never reach here _logger.severe("unexpected status", uri.toString()); - showGenericErrorDialog( + await showGenericErrorDialog( context: context, error: Exception("expected payment status $paymentStatus"), ); diff --git a/lib/ui/payment/store_subscription_page.dart b/lib/ui/payment/store_subscription_page.dart index abeeb8b12..d0eca6c93 100644 --- a/lib/ui/payment/store_subscription_page.dart +++ b/lib/ui/payment/store_subscription_page.dart @@ -528,7 +528,7 @@ class _StoreSubscriptionPageState extends State { response.notFoundIDs.toString(); _logger.severe(errMsg); await _dialog.hide(); - showGenericErrorDialog( + await showGenericErrorDialog( context: context, error: Exception(errMsg), ); diff --git a/lib/ui/payment/stripe_subscription_page.dart b/lib/ui/payment/stripe_subscription_page.dart index d7354ba22..81b172bc4 100644 --- a/lib/ui/payment/stripe_subscription_page.dart +++ b/lib/ui/payment/stripe_subscription_page.dart @@ -303,20 +303,22 @@ class _StripeSubscriptionPageState extends State { await _launchStripePortal(); break; case playStore: - launchUrlString( - "https://play.google.com/store/account/subscriptions?sku=" + - _currentSubscription!.productID + - "&package=io.ente.photos", + unawaited( + launchUrlString( + "https://play.google.com/store/account/subscriptions?sku=" + + _currentSubscription!.productID + + "&package=io.ente.photos", + ), ); break; case appStore: - launchUrlString("https://apps.apple.com/account/billing"); + unawaited(launchUrlString("https://apps.apple.com/account/billing")); break; default: final String capitalizedWord = paymentProvider.isNotEmpty ? '${paymentProvider[0].toUpperCase()}${paymentProvider.substring(1).toLowerCase()}' : ''; - showErrorDialog( + await showErrorDialog( context, S.of(context).sorry, S.of(context).contactToManageSubscription(capitalizedWord), @@ -328,7 +330,7 @@ class _StripeSubscriptionPageState extends State { await _dialog.show(); try { final String url = await _billingService.getStripeCustomerPortalUrl(); - Navigator.of(context).push( + await Navigator.of(context).push( MaterialPageRoute( builder: (BuildContext context) { return WebPage(S.of(context).paymentDetails, url); @@ -337,7 +339,7 @@ class _StripeSubscriptionPageState extends State { ).then((value) => onWebPaymentGoBack); } catch (e) { await _dialog.hide(); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); } await _dialog.hide(); } @@ -382,7 +384,7 @@ class _StripeSubscriptionPageState extends State { confirmAction = choice!.action == ButtonAction.first; } if (confirmAction) { - toggleStripeSubscription(isRenewCancelled); + await toggleStripeSubscription(isRenewCancelled); } }, ); @@ -398,11 +400,13 @@ class _StripeSubscriptionPageState extends State { : await _billingService.cancelStripeSubscription(); await _fetchSub(); } catch (e) { - showShortToast( - context, - isAutoRenewDisabled - ? S.of(context).failedToRenew - : S.of(context).failedToCancel, + unawaited( + showShortToast( + context, + isAutoRenewDisabled + ? S.of(context).failedToRenew + : S.of(context).failedToCancel, + ), ); } await _dialog.hide(); @@ -454,7 +458,7 @@ class _StripeSubscriptionPageState extends State { if (!_isStripeSubscriber && _hasActiveSubscription && _currentSubscription!.productID != freeProductID) { - showErrorDialog( + await showErrorDialog( context, S.of(context).sorry, S.of(context).cancelOtherSubscription( @@ -473,7 +477,7 @@ class _StripeSubscriptionPageState extends State { "addOnBonus ${convertBytesToReadableFormat(addOnBonus)}," "overshooting by ${convertBytesToReadableFormat(_userDetails.getFamilyOrPersonalUsage() - (plan.storage + addOnBonus))}", ); - showErrorDialog( + await showErrorDialog( context, S.of(context).sorry, S.of(context).youCannotDowngradeToThisPlan, @@ -495,7 +499,7 @@ class _StripeSubscriptionPageState extends State { return; } } - Navigator.push( + await Navigator.push( context, MaterialPageRoute( builder: (BuildContext context) { diff --git a/lib/ui/payment/view_add_on_widget.dart b/lib/ui/payment/view_add_on_widget.dart index 5da9e7107..18c5c10d9 100644 --- a/lib/ui/payment/view_add_on_widget.dart +++ b/lib/ui/payment/view_add_on_widget.dart @@ -33,7 +33,7 @@ class ViewAddOnButton extends StatelessWidget { singleBorderRadius: 4, alignCaptionedTextToLeft: true, onTap: () async { - routeToPage(context, AddOnPage(bonusData!)); + await routeToPage(context, AddOnPage(bonusData!)); }, ), ); diff --git a/lib/ui/settings/advanced_settings_screen.dart b/lib/ui/settings/advanced_settings_screen.dart index e5cc0f761..30b80c981 100644 --- a/lib/ui/settings/advanced_settings_screen.dart +++ b/lib/ui/settings/advanced_settings_screen.dart @@ -1,3 +1,5 @@ +import "dart:async"; + import 'package:flutter/material.dart'; import "package:photos/core/error-reporting/super_logging.dart"; import "package:photos/generated/l10n.dart"; @@ -106,8 +108,10 @@ class _AdvancedSettingsScreenState extends State { value: () => MemoriesService.instance.showMemories, onChanged: () async { - MemoriesService.instance.setShowMemories( - !MemoriesService.instance.showMemories, + unawaited( + MemoriesService.instance.setShowMemories( + !MemoriesService.instance.showMemories, + ), ); }, ), diff --git a/lib/ui/settings/backup/backup_folder_selection_page.dart b/lib/ui/settings/backup/backup_folder_selection_page.dart index 810e1ee13..e55ab9a5b 100644 --- a/lib/ui/settings/backup/backup_folder_selection_page.dart +++ b/lib/ui/settings/backup/backup_folder_selection_page.dart @@ -232,7 +232,7 @@ class _BackupFolderSelectionPageState extends State { } catch (e, s) { _logger.severe("Failed to updated backup folder", e, s); await dialog.hide(); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); } } diff --git a/lib/ui/settings/backup/backup_section_widget.dart b/lib/ui/settings/backup/backup_section_widget.dart index 7b05da8bc..60d144f99 100644 --- a/lib/ui/settings/backup/backup_section_widget.dart +++ b/lib/ui/settings/backup/backup_section_widget.dart @@ -94,7 +94,7 @@ class BackupSectionWidgetState extends State { try { status = await SyncService.instance.getBackupStatus(); } catch (e) { - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); return; } @@ -128,7 +128,7 @@ class BackupSectionWidgetState extends State { duplicates = await DeduplicationService.instance.getDuplicateFiles(); } catch (e) { - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); return; } @@ -217,7 +217,7 @@ class BackupSectionWidgetState extends State { ), firstButtonLabel: S.of(context).rateUs, firstButtonOnTap: () async { - UpdateService.instance.launchReviewUrl(); + await UpdateService.instance.launchReviewUrl(); }, firstButtonType: ButtonType.primary, secondButtonLabel: S.of(context).ok, @@ -225,7 +225,7 @@ class BackupSectionWidgetState extends State { showShortToast( context, S.of(context).remindToEmptyEnteTrash, - ); + ).ignore(); }, ); } diff --git a/lib/ui/settings/debug_section_widget.dart b/lib/ui/settings/debug_section_widget.dart index 7eb75baf5..944a37120 100644 --- a/lib/ui/settings/debug_section_widget.dart +++ b/lib/ui/settings/debug_section_widget.dart @@ -50,7 +50,7 @@ class DebugSectionWidget extends StatelessWidget { trailingIconIsMuted: true, onTap: () async { await LocalSyncService.instance.resetLocalSync(); - showShortToast(context, "Done"); + showShortToast(context, "Done").ignore(); }, ), sectionOptionSpacing, @@ -63,8 +63,8 @@ class DebugSectionWidget extends StatelessWidget { trailingIconIsMuted: true, onTap: () async { await IgnoredFilesService.instance.reset(); - SyncService.instance.sync(); - showShortToast(context, "Done"); + SyncService.instance.sync().ignore(); + showShortToast(context, "Done").ignore(); }, ), sectionOptionSpacing, diff --git a/lib/ui/settings/general_section_widget.dart b/lib/ui/settings/general_section_widget.dart index 79bc755a5..5094d2628 100644 --- a/lib/ui/settings/general_section_widget.dart +++ b/lib/ui/settings/general_section_widget.dart @@ -68,7 +68,7 @@ class GeneralSectionWidget extends StatelessWidget { trailingIconIsMuted: true, onTap: () async { final locale = await getLocale(); - routeToPage( + await routeToPage( context, LanguageSelectorPage( appSupportedLocales, diff --git a/lib/ui/settings/security_section_widget.dart b/lib/ui/settings/security_section_widget.dart index 7805167f9..1d2b9e916 100644 --- a/lib/ui/settings/security_section_widget.dart +++ b/lib/ui/settings/security_section_widget.dart @@ -279,7 +279,7 @@ class _SecuritySectionWidgetState extends State { } await UserService.instance.updateEmailMFA(isEnabled); } catch (e) { - showToast(context, S.of(context).somethingWentWrong); + showToast(context, S.of(context).somethingWentWrong).ignore(); } } } diff --git a/lib/ui/sharing/manage_album_participant.dart b/lib/ui/sharing/manage_album_participant.dart index 7c6f33d56..16b6bd070 100644 --- a/lib/ui/sharing/manage_album_participant.dart +++ b/lib/ui/sharing/manage_album_participant.dart @@ -132,7 +132,10 @@ class _ManageIndividualParticipantState CollectionParticipantRole.viewer, ); } catch (e) { - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog( + context: context, + error: e, + ); } if (isConvertToViewSuccess && mounted) { // reset value diff --git a/lib/ui/sharing/pickers/device_limit_picker_page.dart b/lib/ui/sharing/pickers/device_limit_picker_page.dart index de409ad39..66c08bde7 100644 --- a/lib/ui/sharing/pickers/device_limit_picker_page.dart +++ b/lib/ui/sharing/pickers/device_limit_picker_page.dart @@ -137,7 +137,7 @@ class _ItemsWidgetState extends State { try { await CollectionsService.instance.updateShareUrl(widget.collection, prop); } catch (e) { - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); rethrow; } } diff --git a/lib/ui/sharing/pickers/link_expiry_picker_page.dart b/lib/ui/sharing/pickers/link_expiry_picker_page.dart index 0e04e1a7f..544684023 100644 --- a/lib/ui/sharing/pickers/link_expiry_picker_page.dart +++ b/lib/ui/sharing/pickers/link_expiry_picker_page.dart @@ -180,7 +180,7 @@ class _ItemsWidgetState extends State { try { await CollectionsService.instance.updateShareUrl(widget.collection, prop); } catch (e) { - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); rethrow; } } diff --git a/lib/ui/tabs/shared_collections_tab.dart b/lib/ui/tabs/shared_collections_tab.dart index 665bb8623..d937fa716 100644 --- a/lib/ui/tabs/shared_collections_tab.dart +++ b/lib/ui/tabs/shared_collections_tab.dart @@ -19,6 +19,7 @@ import "package:photos/ui/components/models/button_type.dart"; import 'package:photos/ui/tabs/section_title.dart'; import "package:photos/ui/tabs/shared/empty_state.dart"; import "package:photos/ui/tabs/shared/quick_link_album_item.dart"; +import "package:photos/utils/debouncer.dart"; import "package:photos/utils/navigation_util.dart"; import "package:photos/utils/share_util.dart"; @@ -36,18 +37,31 @@ class _SharedCollectionsTabState extends State late StreamSubscription _collectionUpdatesSubscription; late StreamSubscription _loggedOutEvent; + final _debouncer = Debouncer( + const Duration(seconds: 2), + executionInterval: const Duration(seconds: 5), + ); @override void initState() { super.initState(); _localFilesSubscription = Bus.instance.on().listen((event) { - debugPrint("SetState Shared Collections on ${event.reason}"); - setState(() {}); + _debouncer.run(() async { + if (mounted) { + debugPrint("SetState Shared Collections on ${event.reason}"); + setState(() {}); + } + }); }); _collectionUpdatesSubscription = Bus.instance.on().listen((event) { - setState(() {}); + _debouncer.run(() async { + if (mounted) { + debugPrint("SetState Shared Collections on ${event.reason}"); + setState(() {}); + } + }); }); _loggedOutEvent = Bus.instance.on().listen((event) { setState(() {}); @@ -262,6 +276,7 @@ class _SharedCollectionsTabState extends State _localFilesSubscription.cancel(); _collectionUpdatesSubscription.cancel(); _loggedOutEvent.cancel(); + _debouncer.cancelDebounce(); super.dispose(); } diff --git a/lib/ui/tabs/user_collections_tab.dart b/lib/ui/tabs/user_collections_tab.dart index 7c49f976f..e5eab8317 100644 --- a/lib/ui/tabs/user_collections_tab.dart +++ b/lib/ui/tabs/user_collections_tab.dart @@ -24,6 +24,7 @@ import 'package:photos/ui/components/buttons/icon_button_widget.dart'; import "package:photos/ui/tabs/section_title.dart"; import "package:photos/ui/viewer/actions/delete_empty_albums.dart"; import "package:photos/ui/viewer/gallery/empty_state.dart"; +import "package:photos/utils/debouncer.dart"; import 'package:photos/utils/local_settings.dart'; import "package:photos/utils/navigation_util.dart"; @@ -44,19 +45,31 @@ class _UserCollectionsTabState extends State AlbumSortKey? sortKey; String _loadReason = "init"; final _scrollController = ScrollController(); + final _debouncer = Debouncer( + const Duration(seconds: 2), + executionInterval: const Duration(seconds: 5), + ); static const int _kOnEnteItemLimitCount = 10; @override void initState() { _localFilesSubscription = Bus.instance.on().listen((event) { - _loadReason = event.reason; - setState(() {}); + _debouncer.run(() async { + if (mounted) { + _loadReason = event.reason; + setState(() {}); + } + }); }); _collectionUpdatesSubscription = Bus.instance.on().listen((event) { - _loadReason = event.reason; - setState(() {}); + _debouncer.run(() async { + if (mounted) { + _loadReason = event.reason; + setState(() {}); + } + }); }); _loggedOutEvent = Bus.instance.on().listen((event) { _loadReason = event.reason; @@ -268,6 +281,7 @@ class _UserCollectionsTabState extends State _collectionUpdatesSubscription.cancel(); _loggedOutEvent.cancel(); _scrollController.dispose(); + _debouncer.cancelDebounce(); super.dispose(); } diff --git a/lib/ui/viewer/actions/file_selection_actions_widget.dart b/lib/ui/viewer/actions/file_selection_actions_widget.dart index 6f26d8e7d..0baccceaf 100644 --- a/lib/ui/viewer/actions/file_selection_actions_widget.dart +++ b/lib/ui/viewer/actions/file_selection_actions_widget.dart @@ -319,21 +319,30 @@ class _FileSelectionActionsWidgetState ); if (items.isNotEmpty) { - return SizedBox( - width: double.infinity, - child: Center( - child: SingleChildScrollView( - physics: const BouncingScrollPhysics( - decelerationRate: ScrollDecelerationRate.fast, - ), - scrollDirection: Axis.horizontal, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(width: 4), - ...items, - const SizedBox(width: 4), - ], + final scrollController = ScrollController(); + // h4ck: https://github.com/flutter/flutter/issues/57920#issuecomment-893970066 + return MediaQuery( + data: MediaQuery.of(context).removePadding(removeBottom: true), + child: SafeArea( + child: Scrollbar( + controller: scrollController, + thumbVisibility: true, + child: SingleChildScrollView( + physics: const BouncingScrollPhysics( + decelerationRate: ScrollDecelerationRate.fast, + ), + scrollDirection: Axis.horizontal, + child: Container( + padding: const EdgeInsets.only(bottom: 24), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(width: 4), + ...items, + const SizedBox(width: 4), + ], + ), + ), ), ), ), diff --git a/lib/ui/viewer/file/file_app_bar.dart b/lib/ui/viewer/file/file_app_bar.dart index d52d8ed14..c5d7d8487 100644 --- a/lib/ui/viewer/file/file_app_bar.dart +++ b/lib/ui/viewer/file/file_app_bar.dart @@ -257,15 +257,15 @@ class FileAppBarState extends State { }, onSelected: (dynamic value) async { if (value == 1) { - _download(widget.file); + await _download(widget.file); } else if (value == 2) { await _toggleFileArchiveStatus(widget.file); } else if (value == 3) { - _setAs(widget.file); + await _setAs(widget.file); } else if (value == 4) { - _handleHideRequest(context); + await _handleHideRequest(context); } else if (value == 5) { - _handleUnHideRequest(context); + await _handleUnHideRequest(context); } }, ), @@ -371,7 +371,7 @@ class FileAppBarState extends State { } catch (e) { _logger.warning("Failed to save file", e); await dialog.hide(); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); } finally { PhotoManager.startChangeNotify(); LocalSyncService.instance.checkAndSync().ignore(); @@ -432,7 +432,7 @@ class FileAppBarState extends State { } catch (e) { dialog.hide(); _logger.severe("Failed to use as", e); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); } } } diff --git a/lib/ui/viewer/file/zoomable_image.dart b/lib/ui/viewer/file/zoomable_image.dart index 51597e90e..3487a1778 100644 --- a/lib/ui/viewer/file/zoomable_image.dart +++ b/lib/ui/viewer/file/zoomable_image.dart @@ -53,13 +53,18 @@ class _ZoomableImageState extends State bool _loadingFinalImage = false; bool _loadedFinalImage = false; PhotoViewController _photoViewController = PhotoViewController(); - double? _initialScale; + bool _isZooming = false; + ValueChanged? _scaleStateChangedCallback; @override void initState() { _photo = widget.photo; _logger = Logger("ZoomableImage"); _logger.info('initState for ${_photo.generatedID} with tag ${_photo.tag}'); + _scaleStateChangedCallback = (value) { + _isZooming = value != PhotoViewScaleState.initial; + debugPrint("isZooming = $_isZooming, currentState $value"); + }; super.initState(); } @@ -81,6 +86,7 @@ class _ZoomableImageState extends State if (_imageProvider != null) { content = PhotoViewGallery.builder( gaplessPlayback: true, + scaleStateChangedCallback: _scaleStateChangedCallback, backgroundDecoration: widget.backgroundDecoration as BoxDecoration?, builder: (context, index) { return PhotoViewGalleryPageOptions( @@ -99,25 +105,20 @@ class _ZoomableImageState extends State } else { content = const EnteLoadingWidget(); } - - dragFunction(d) => { - if (d.delta.dy > dragSensitivity) - { - {Navigator.of(context).pop()}, - } - else if (d.delta.dy < (dragSensitivity * -1)) + verticalDragCallback(d) => { + if (!_isZooming) { - showDetailsSheet(context, widget.photo), + if (d.delta.dy > dragSensitivity) + { + {Navigator.of(context).pop()}, + } + else if (d.delta.dy < (dragSensitivity * -1)) + { + showDetailsSheet(context, widget.photo), + }, }, }; - verticalDragCallback(d) { - if (_initialScale == null || - _photoViewController.scale! <= _initialScale!) { - dragFunction(d); - } - } - return GestureDetector( onVerticalDragUpdate: verticalDragCallback, child: content, @@ -258,8 +259,7 @@ class _ZoomableImageState extends State required ImageProvider? previewImageProvider, required ImageProvider finalImageProvider, }) async { - final bool shouldFixPosition = - previewImageProvider != null && _photoViewController.scale != null; + final bool shouldFixPosition = previewImageProvider != null && _isZooming; ImageInfo? finalImageInfo; if (shouldFixPosition) { if (kDebugMode) { @@ -282,9 +282,6 @@ class _ZoomableImageState extends State initialPosition: newPosition, initialScale: scale, ); - setState(() { - _initialScale = scale; - }); } final bool canUpdateMetadata = _photo.canEditMetaInfo; // forcefully get finalImageInfo is dimensions are not available in metadata diff --git a/lib/ui/viewer/file_details/favorite_widget.dart b/lib/ui/viewer/file_details/favorite_widget.dart index 5e39b1510..4e3fb1b5f 100644 --- a/lib/ui/viewer/file_details/favorite_widget.dart +++ b/lib/ui/viewer/file_details/favorite_widget.dart @@ -1,3 +1,5 @@ +import "dart:async"; + import "package:flutter/material.dart"; import "package:like_button/like_button.dart"; import "package:logging/logging.dart"; @@ -77,9 +79,11 @@ class _FavoriteWidgetState extends State { } catch (e, s) { _logger.severe(e, s); hasError = true; - showToast( - context, - S.of(context).sorryCouldNotRemoveFromFavorites, + unawaited( + showToast( + context, + S.of(context).sorryCouldNotRemoveFromFavorites, + ), ); } } diff --git a/lib/ui/viewer/gallery/empty_album_state.dart b/lib/ui/viewer/gallery/empty_album_state.dart index 0ec5b0756..c90721a68 100644 --- a/lib/ui/viewer/gallery/empty_album_state.dart +++ b/lib/ui/viewer/gallery/empty_album_state.dart @@ -31,7 +31,7 @@ class EmptyAlbumState extends StatelessWidget { try { await showAddPhotosSheet(context, c); } catch (e) { - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); } }, ), diff --git a/lib/ui/viewer/gallery/gallery.dart b/lib/ui/viewer/gallery/gallery.dart index 6d7f4b6cd..112a14d0e 100644 --- a/lib/ui/viewer/gallery/gallery.dart +++ b/lib/ui/viewer/gallery/gallery.dart @@ -16,6 +16,7 @@ import "package:photos/ui/viewer/gallery/component/multiple_groups_gallery_view. import 'package:photos/ui/viewer/gallery/empty_state.dart'; import "package:photos/ui/viewer/gallery/state/gallery_context_state.dart"; import 'package:photos/utils/date_time_util.dart'; +import "package:photos/utils/debouncer.dart"; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; typedef GalleryLoader = Future Function( @@ -43,6 +44,8 @@ class Gallery extends StatefulWidget { final bool enableFileGrouping; final Widget loadingWidget; final bool disableScroll; + final Duration reloadDebounceTime; + final Duration reloadDebounceExecutionInterval; /// When true, selection will be limited to one item. Tapping on any item /// will select even when no other item is selected. @@ -78,6 +81,8 @@ class Gallery extends StatefulWidget { this.sortAsyncFn, this.showSelectAllByDefault = true, this.isScrollablePositionedList = true, + this.reloadDebounceTime = const Duration(milliseconds: 500), + this.reloadDebounceExecutionInterval = const Duration(seconds: 2), Key? key, }) : super(key: key); @@ -89,6 +94,7 @@ class Gallery extends StatefulWidget { class GalleryState extends State { static const int kInitialLoadLimit = 100; + late final Debouncer _debouncer; late Logger _logger; List> currentGroupedFiles = []; @@ -106,20 +112,31 @@ class GalleryState extends State { "Gallery_${widget.tagPrefix}${kDebugMode ? "_" + widget.albumName! : ""}"; _logger = Logger(_logTag); _logger.finest("init Gallery"); + _debouncer = Debouncer( + widget.reloadDebounceTime, + executionInterval: widget.reloadDebounceExecutionInterval, + ); _sortOrderAsc = widget.sortAsyncFn != null ? widget.sortAsyncFn!() : false; _itemScroller = ItemScrollController(); if (widget.reloadEvent != null) { _reloadEventSubscription = widget.reloadEvent!.listen((event) async { - // In soft refresh, setState is called for entire gallery only when - // number of child change - _logger.finest("Soft refresh all files on ${event.reason} "); - final result = await _loadFiles(); - final bool hasReloaded = _onFilesLoaded(result.files); - if (hasReloaded && kDebugMode) { - _logger.finest( - "Reloaded gallery on soft refresh all files on ${event.reason}", - ); - } + _debouncer.run(() async { + // In soft refresh, setState is called for entire gallery only when + // number of child change + _logger.finest("Soft refresh all files on ${event.reason} "); + final result = await _loadFiles(); + final bool hasReloaded = _onFilesLoaded(result.files); + if (hasReloaded && kDebugMode) { + _logger.finest( + "Reloaded gallery on soft refresh all files on ${event.reason}", + ); + } + if (event.type == EventType.deletedFromDevice || + event.type == EventType.deletedFromEverywhere || + event.type == EventType.deletedFromRemote) { + setState(() {}); + } + }); }); } _tabDoubleTapEvent = @@ -137,11 +154,13 @@ class GalleryState extends State { for (final event in widget.forceReloadEvents!) { _forceReloadEventSubscriptions.add( event.listen((event) async { - _logger.finest("Force refresh all files on ${event.reason}"); - _sortOrderAsc = - widget.sortAsyncFn != null ? widget.sortAsyncFn!() : false; - final result = await _loadFiles(); - _setFilesAndReload(result.files); + _debouncer.run(() async { + _logger.finest("Force refresh all files on ${event.reason}"); + _sortOrderAsc = + widget.sortAsyncFn != null ? widget.sortAsyncFn!() : false; + final result = await _loadFiles(); + _setFilesAndReload(result.files); + }); }), ); } @@ -219,6 +238,7 @@ class GalleryState extends State { for (final subscription in _forceReloadEventSubscriptions) { subscription.cancel(); } + _debouncer.cancelDebounce(); super.dispose(); } diff --git a/lib/ui/viewer/gallery/gallery_app_bar_widget.dart b/lib/ui/viewer/gallery/gallery_app_bar_widget.dart index a1dde81f1..21f2f862e 100644 --- a/lib/ui/viewer/gallery/gallery_app_bar_widget.dart +++ b/lib/ui/viewer/gallery/gallery_app_bar_widget.dart @@ -172,7 +172,7 @@ class _GalleryAppBarWidgetState extends State { }, ); if (result is Exception) { - showGenericErrorDialog(context: context, error: result); + await showGenericErrorDialog(context: context, error: result); } } @@ -204,7 +204,10 @@ class _GalleryAppBarWidgetState extends State { ); if (actionResult?.action != null && mounted) { if (actionResult!.action == ButtonAction.error) { - showGenericErrorDialog(context: context, error: actionResult.exception); + await showGenericErrorDialog( + context: context, + error: actionResult.exception, + ); } else if (actionResult.action == ButtonAction.first) { Navigator.of(context).pop(); } @@ -224,7 +227,7 @@ class _GalleryAppBarWidgetState extends State { .getBackupStatus(pathID: widget.deviceCollection!.id); } catch (e) { await dialog.hide(); - showGenericErrorDialog(context: context, error: e); + unawaited(showGenericErrorDialog(context: context, error: e)); return; } @@ -664,7 +667,7 @@ class _GalleryAppBarWidgetState extends State { } catch (e, s) { _logger.severe("failed to trash collection", e, s); await dialog.hide(); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); } } else { final bool result = await collectionActions.deleteCollectionSheet( @@ -691,7 +694,7 @@ class _GalleryAppBarWidgetState extends State { } } catch (e, s) { _logger.severe("failed to trash collection", e, s); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); } } @@ -726,7 +729,7 @@ class _GalleryAppBarWidgetState extends State { } } catch (e, s) { _logger.severe(e, s); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); } } @@ -736,7 +739,7 @@ class _GalleryAppBarWidgetState extends State { await showAddPhotosSheet(bContext, collection!); } catch (e, s) { _logger.severe(e, s); - showGenericErrorDialog(context: bContext, error: e); + await showGenericErrorDialog(context: bContext, error: e); } } diff --git a/lib/ui/viewer/gallery/hooks/add_photos_sheet.dart b/lib/ui/viewer/gallery/hooks/add_photos_sheet.dart index f9db777a8..9f7921760 100644 --- a/lib/ui/viewer/gallery/hooks/add_photos_sheet.dart +++ b/lib/ui/viewer/gallery/hooks/add_photos_sheet.dart @@ -205,7 +205,7 @@ class AddPhotosPhotoWidget extends StatelessWidget { if (e is StateError) { final PermissionState ps = await PhotoManager.requestPermissionExtend(); if (ps != PermissionState.authorized && ps != PermissionState.limited) { - showChoiceDialog( + await showChoiceDialog( context, title: context.l10n.grantPermission, body: context.l10n.pleaseGrantPermissions, diff --git a/lib/ui/viewer/location/location_screen.dart b/lib/ui/viewer/location/location_screen.dart index 5ff279288..ecdf902af 100644 --- a/lib/ui/viewer/location/location_screen.dart +++ b/lib/ui/viewer/location/location_screen.dart @@ -118,7 +118,7 @@ class LocationScreenPopUpMenu extends StatelessWidget { ); Navigator.of(context).pop(); } catch (e) { - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); } } }, diff --git a/lib/utils/debouncer.dart b/lib/utils/debouncer.dart index afa3b2cde..b9185f8a4 100644 --- a/lib/utils/debouncer.dart +++ b/lib/utils/debouncer.dart @@ -12,19 +12,19 @@ class Debouncer { /// If executionIntervalInSeconds is not null, then the debouncer will execute the /// current callback it has in run() method repeatedly in the given interval. /// This is useful for example when you want to execute a callback every 5 seconds - final int? executionIntervalInMilliSeconds; + final Duration? executionInterval; Timer? _debounceTimer; - Debouncer(this._duration, {this.executionIntervalInMilliSeconds}); + Debouncer(this._duration, {this.executionInterval}); final Stopwatch _stopwatch = Stopwatch(); void run(FutureVoidCallback fn) { bool shouldRunImmediately = false; - if (executionIntervalInMilliSeconds != null) { + if (executionInterval != null) { // ensure the stop watch is running _stopwatch.start(); - if (_stopwatch.elapsedMilliseconds > executionIntervalInMilliSeconds!) { + if (_stopwatch.elapsedMilliseconds > executionInterval!.inMilliseconds) { shouldRunImmediately = true; _stopwatch.stop(); _stopwatch.reset(); diff --git a/lib/utils/delete_file_util.dart b/lib/utils/delete_file_util.dart index 1128887a2..76d74065f 100644 --- a/lib/utils/delete_file_util.dart +++ b/lib/utils/delete_file_util.dart @@ -102,7 +102,7 @@ Future deleteFilesFromEverywhere( await FilesDB.instance.deleteMultipleUploadedFiles(fileIDs); } catch (e) { _logger.severe(e); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); rethrow; } for (final collectionID in updatedCollectionIDs) { @@ -127,9 +127,9 @@ Future deleteFilesFromEverywhere( ), ); if (hasLocalOnlyFiles && Platform.isAndroid) { - showShortToast(context, S.of(context).filesDeleted); + await showShortToast(context, S.of(context).filesDeleted); } else { - showShortToast(context, S.of(context).movedToTrash); + await showShortToast(context, S.of(context).movedToTrash); } } if (uploadedFilesToBeTrashed.isNotEmpty) { @@ -163,7 +163,7 @@ Future deleteFilesFromRemoteOnly( await FilesDB.instance.deleteMultipleUploadedFiles(uploadedFileIDs); } catch (e, s) { _logger.severe("Failed to delete files from remote", e, s); - showGenericErrorDialog(context: context, error: e); + await showGenericErrorDialog(context: context, error: e); rethrow; } for (final collectionID in updatedCollectionIDs) { @@ -626,7 +626,10 @@ Future showDeleteSheet( ); if (actionResult?.action != null && actionResult!.action == ButtonAction.error) { - showGenericErrorDialog(context: context, error: actionResult.exception); + await showGenericErrorDialog( + context: context, + error: actionResult.exception, + ); } else { selectedFiles.clearAll(); } diff --git a/lib/utils/file_uploader_util.dart b/lib/utils/file_uploader_util.dart index 91d735202..d445d808d 100644 --- a/lib/utils/file_uploader_util.dart +++ b/lib/utils/file_uploader_util.dart @@ -129,8 +129,8 @@ Future _getMediaUploadDataFromAssetFile(EnteFile file) async { _logger.fine("Uploading zipped live photo from " + livePhotoPath); final encoder = ZipFileEncoder(); encoder.create(livePhotoPath); - encoder.addFile(videoUrl, "video" + extension(videoUrl.path)); - encoder.addFile(sourceFile, "image" + extension(sourceFile.path)); + await encoder.addFile(videoUrl, "video" + extension(videoUrl.path)); + await encoder.addFile(sourceFile, "image" + extension(sourceFile.path)); encoder.close(); // delete the temporary video and image copy (only in IOS) if (Platform.isIOS) { diff --git a/lib/utils/file_util.dart b/lib/utils/file_util.dart index 10d5bcd9a..ff45dfcaf 100644 --- a/lib/utils/file_util.dart +++ b/lib/utils/file_util.dart @@ -204,7 +204,7 @@ Future _getLivePhotoFromServer( return needLiveVideo ? livePhoto.video : livePhoto.image; } catch (e, s) { _logger.warning("live photo get failed", e, s); - _livePhotoDownloadsTracker.remove(downloadID); + await _livePhotoDownloadsTracker.remove(downloadID); return null; } } @@ -348,9 +348,9 @@ Future compressThumbnail(Uint8List thumbnail) { Future clearCache(EnteFile file) async { if (file.fileType == FileType.video) { - VideoCacheManager.instance.removeFile(file.downloadUrl); + await VideoCacheManager.instance.removeFile(file.downloadUrl); } else { - DefaultCacheManager().removeFile(file.downloadUrl); + await DefaultCacheManager().removeFile(file.downloadUrl); } final cachedThumbnail = File( Configuration.instance.getThumbnailCacheDirectory() + diff --git a/lib/utils/magic_util.dart b/lib/utils/magic_util.dart index fc5fef9bc..539ccf9e4 100644 --- a/lib/utils/magic_util.dart +++ b/lib/utils/magic_util.dart @@ -1,3 +1,5 @@ +import "dart:async"; + import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; import 'package:path/path.dart'; @@ -134,7 +136,7 @@ Future updateOrder( ); } catch (e, s) { _logger.severe("failed to update order", e, s); - showShortToast(context, S.of(context).somethingWentWrong); + unawaited(showShortToast(context, S.of(context).somethingWentWrong)); rethrow; } } @@ -160,7 +162,7 @@ Future changeCoverPhoto( ); } catch (e, s) { _logger.severe("failed to update cover", e, s); - showShortToast(context, S.of(context).somethingWentWrong); + unawaited(showShortToast(context, S.of(context).somethingWentWrong)); rethrow; } } @@ -179,7 +181,7 @@ Future editTime( ); return true; } catch (e) { - showShortToast(context, S.of(context).somethingWentWrong); + showShortToast(context, S.of(context).somethingWentWrong).ignore(); return false; } } @@ -218,7 +220,7 @@ Future editFilename( ); if (result is Exception) { _logger.severe("Failed to rename file"); - showGenericErrorDialog(context: context, error: result); + await showGenericErrorDialog(context: context, error: result); } } @@ -238,7 +240,7 @@ Future editFileCaption( return true; } catch (e) { if (context != null) { - showShortToast(context, S.of(context).somethingWentWrong); + unawaited(showShortToast(context, S.of(context).somethingWentWrong)); } return false; } @@ -265,7 +267,7 @@ Future _updatePublicMetadata( await FileMagicService.instance.updatePublicMagicMetadata(files, update); if (context != null) { if (showDoneToast) { - showShortToast(context, S.of(context).done); + await showShortToast(context, S.of(context).done); } await dialog?.hide(); } diff --git a/pubspec.lock b/pubspec.lock index 9a485ae0c..e17876d6b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -293,7 +293,7 @@ packages: source: hosted version: "1.6.3" cross_file: - dependency: transitive + dependency: "direct main" description: name: cross_file sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9" @@ -500,6 +500,15 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.4" + file_saver: + dependency: "direct main" + description: + path: "." + ref: HEAD + resolved-ref: "01b2e6b6fe520cfa5d2d91342ccbfbaefa8f6482" + url: "https://github.com/jesims/file_saver.git" + source: git + version: "0.2.9" firebase_core: dependency: "direct main" description: @@ -1163,18 +1172,18 @@ packages: dependency: "direct main" description: name: media_kit - sha256: "3dffc6d0c19117d51fbc42a7f89612e0595665800a596289ab7a80bdd93e0ad1" + sha256: "3289062540e3b8b9746e5c50d95bd78a9289826b7227e253dff806d002b9e67a" url: "https://pub.dev" source: hosted - version: "1.1.9" + version: "1.1.10+1" media_kit_libs_android_video: dependency: transitive description: name: media_kit_libs_android_video - sha256: a7ef60926ac528e2fabe9ee7084e648e385422a881ba914c978a7a81e6595dee + sha256: "9dd8012572e4aff47516e55f2597998f0a378e3d588d0fad0ca1f11a53ae090c" url: "https://pub.dev" source: hosted - version: "1.3.5" + version: "1.3.6" media_kit_libs_ios_video: dependency: transitive description: @@ -1203,10 +1212,10 @@ packages: dependency: "direct main" description: name: media_kit_libs_video - sha256: f130964bd4c0907d0af645ba03c8080a914776bfd2e23761a5e22ac3c0c0906a + sha256: "3688e0c31482074578652bf038ce6301a5d21e1eda6b54fc3117ffeb4bdba067" url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" media_kit_libs_windows_video: dependency: transitive description: @@ -1227,10 +1236,10 @@ packages: dependency: "direct main" description: name: media_kit_video - sha256: b1a427f0540c5f052dfab73e4b76a5eb8efa7ebb5d83179cb23fc3932afc315a + sha256: c048d11a19e379aebbe810647636e3fc6d18374637e2ae12def4ff8a4b99a882 url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.4" meta: dependency: transitive description: @@ -1268,10 +1277,10 @@ packages: description: path: "." ref: HEAD - resolved-ref: c0409b2e812c7457908a6e492abae6e4f5b457a7 + resolved-ref: f1ec3d35d5cee2ec1c098b5ca276f311a96d800a url: "https://github.com/ente-io/motion_photo.git" source: git - version: "0.0.3" + version: "0.0.6" motionphoto: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 77d8cd3b5..560dab58d 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.5+525 +version: 0.8.11+531 environment: sdk: ">=3.0.0 <4.0.0" @@ -55,8 +55,10 @@ dependencies: extended_image: ^8.1.1 fade_indexed_stack: ^0.2.2 fast_base58: ^0.2.1 - # https://github.com/incrediblezayed/file_saver/issues/86 - file_saver: 0.2.8 + + file_saver: + # Use forked version till this PR is merged: https://github.com/incrediblezayed/file_saver/pull/87 + git: https://github.com/jesims/file_saver.git firebase_core: ^2.13.1 firebase_messaging: ^14.6.2 fk_user_agent: ^2.0.1 @@ -99,9 +101,9 @@ dependencies: logging: ^1.0.1 lottie: ^1.2.2 media_extension: ^1.0.1 - media_kit: ^1.1.9 - media_kit_libs_video: ^1.0.3 - media_kit_video: ^1.2.1 + media_kit: ^1.1.10+1 + media_kit_libs_video: ^1.0.4 + media_kit_video: ^1.2.4 modal_bottom_sheet: ^3.0.0-pre motion_photos: git: "https://github.com/ente-io/motion_photo.git"