Compare commits
10 Commits
usearch_up
...
auth-v4.4.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5d725e139 | ||
|
|
5750d72c5a | ||
|
|
00a430927f | ||
|
|
ab57a1f8fe | ||
|
|
cfdeb475ef | ||
|
|
1f0f240f97 | ||
|
|
2ff5058a3e | ||
|
|
641dfdd11e | ||
|
|
b3827dd812 | ||
|
|
087ba629e0 |
Submodule auth/assets/simple-icons deleted from 6dcfdc2f58
Submodule auth/flutter deleted from 5874a72aa4
@@ -739,6 +739,10 @@
|
||||
"lu.ma"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "MangaDex",
|
||||
"slug": "mangadex"
|
||||
},
|
||||
{
|
||||
"title": "Marketplace.tf",
|
||||
"slug": "marketplacedottf"
|
||||
|
||||
1
mobile/apps/auth/assets/custom-icons/icons/mangadex.svg
Normal file
1
mobile/apps/auth/assets/custom-icons/icons/mangadex.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 5.0 KiB |
@@ -78,6 +78,7 @@
|
||||
"contactSupport": "Звярнуцца ў службу падтрымкі",
|
||||
"rateUsOnStore": "Ацаніць нас у {storeName}",
|
||||
"blog": "Блог",
|
||||
"merchandise": "Тавары",
|
||||
"verifyPassword": "Праверыць пароль",
|
||||
"pleaseWait": "Пачакайце...",
|
||||
"generatingEncryptionKeysTitle": "Генерацыя ключоў шыфравання...",
|
||||
@@ -85,6 +86,9 @@
|
||||
"useRecoveryKey": "Выкарыстоўваць ключ аднаўлення",
|
||||
"incorrectPasswordTitle": "Няправільны пароль",
|
||||
"welcomeBack": "З вяртаннем!",
|
||||
"emailAlreadyRegistered": "Электронная пошта ўжо зарэгістравана.",
|
||||
"emailNotRegistered": "Электронная пошта не зарэгістравана.",
|
||||
"madeWithLoveAtPrefix": "зроблена з ❤️ у ",
|
||||
"changeEmail": "Змяніць адрас электроннай пошты",
|
||||
"changePassword": "Змяніць пароль",
|
||||
"data": "Даныя",
|
||||
@@ -94,9 +98,13 @@
|
||||
"passwordForDecryptingExport": "Пароль для дэшыфроўкі экспартавання",
|
||||
"passwordEmptyError": "Пароль не можа быць пустым",
|
||||
"importFromApp": "Імпартаваць коды з {appName}",
|
||||
"importSelectJsonFile": "Выбраць файл JSON",
|
||||
"importSelectAppExport": "Выберыце файл экспартавання {appName}",
|
||||
"exportCodes": "Экспартаваць коды",
|
||||
"importLabel": "Імпарт",
|
||||
"selectFile": "Выбраць файл",
|
||||
"emailVerificationToggle": "Праверка эл. пошты",
|
||||
"authenticateGeneric": "Прайдзіце аўтэнтыфікацыю",
|
||||
"ok": "OK",
|
||||
"cancel": "Скасаваць",
|
||||
"yes": "Так",
|
||||
@@ -113,19 +121,29 @@
|
||||
"enterYourPasswordHint": "Увядзіце ваш пароль",
|
||||
"forgotPassword": "Забылі пароль",
|
||||
"oops": "Вой",
|
||||
"suggestFeatures": "Прапанаваць функцыю",
|
||||
"faq": "Частыя пытанні",
|
||||
"leaveFamily": "Пакінуць сямейны план",
|
||||
"inFamilyPlanMessage": "Вы ўдзельнік сямейнага плана!",
|
||||
"scan": "Сканіраваць",
|
||||
"scanACode": "Сканіраваць код",
|
||||
"verify": "Праверыць",
|
||||
"verifyEmail": "Праверыць электронную пошту",
|
||||
"lostDeviceTitle": "Згубілі прыладу?",
|
||||
"twoFactorAuthTitle": "Двухфактарная аўтэнтыфікацыя",
|
||||
"passkeyAuthTitle": "Праверка ключа доступу",
|
||||
"verifyPasskey": "Праверыць ключ доступу",
|
||||
"loginWithTOTP": "Увайсці з TOTP",
|
||||
"recoverAccount": "Аднавіць уліковы запіс",
|
||||
"enterRecoveryKeyHint": "Увядзіце свой ключ аднаўлення",
|
||||
"recover": "Аднавіць",
|
||||
"invalidQRCode": "Памылковы QR-код",
|
||||
"noRecoveryKeyTitle": "Няма ключа аднаўлення?",
|
||||
"enterEmailHint": "Увядзіце свой адрас электроннай пошты",
|
||||
"enterNewEmailHint": "Увядзіце свой новы адрас электроннай пошты",
|
||||
"invalidEmailTitle": "Памылковы адрас электроннай пошты",
|
||||
"deleteAccount": "Выдаліць уліковы запіс",
|
||||
"yesSendFeedbackAction": "Так. Адправіць водгук",
|
||||
"noDeleteAccountAction": "Не, выдаліць уліковы запіс",
|
||||
"sendEmail": "Адправіць ліст",
|
||||
"createNewAccount": "Стварыць новы ўліковы запіс",
|
||||
@@ -140,16 +158,21 @@
|
||||
"social": "Сацыяльныя сеткі",
|
||||
"security": "Бяспека",
|
||||
"lockscreen": "Экран блакіроўкі",
|
||||
"viewActiveSessions": "Паглядзець актыўныя сеансы",
|
||||
"searchHint": "Пошук...",
|
||||
"search": "Пошук",
|
||||
"noResult": "Няма вынікаў",
|
||||
"addCode": "Дадаць код",
|
||||
"scanAQrCode": "Сканіраваць QR-код",
|
||||
"enterDetailsManually": "Увесці падрабязнасці ўручную",
|
||||
"edit": "Рэдагаваць",
|
||||
"share": "Абагуліць",
|
||||
"shareCodes": "Абагуліць коды",
|
||||
"restore": "Аднавіць",
|
||||
"copiedToClipboard": "Скапіявана ў буфер абмену",
|
||||
"copiedNextToClipboard": "Скапіяваць наступны код у буфер абмену",
|
||||
"error": "Памылка",
|
||||
"recoveryKeyCopiedToClipboard": "Ключ аднаўлення скапіяваны ў буфер абмену",
|
||||
"doThisLater": "Зрабіць гэта пазней",
|
||||
"saveKey": "Захаваць ключ",
|
||||
"save": "Захаваць",
|
||||
@@ -164,19 +187,27 @@
|
||||
"changePasswordTitle": "Змяніць пароль",
|
||||
"resetPasswordTitle": "Скінуць пароль",
|
||||
"encryptionKeys": "Ключы шыфравання",
|
||||
"passwordChangedSuccessfully": "Пароль паспяхова зменены",
|
||||
"generatingEncryptionKeys": "Генерацыя ключоў шыфравання...",
|
||||
"continueLabel": "Працягнуць",
|
||||
"insecureDevice": "Небяспечная прылада",
|
||||
"howItWorks": "Як гэта працуе",
|
||||
"logInLabel": "Увайсці",
|
||||
"logout": "Выйсці",
|
||||
"areYouSureYouWantToLogout": "Вы сапраўды хочаце выйсці?",
|
||||
"yesLogout": "Так, выйсці",
|
||||
"exit": "Выхад",
|
||||
"theme": "Тема",
|
||||
"lightTheme": "Светлая",
|
||||
"darkTheme": "Цёмная",
|
||||
"systemTheme": "Сістэманая",
|
||||
"verifyingRecoveryKey": "Праверка ключа аднаўлення...",
|
||||
"recoveryKeyVerified": "Ключ аднаўлення правераны",
|
||||
"recreatePasswordTitle": "Стварыць пароль паўторна",
|
||||
"invalidKey": "Памылковы ключ",
|
||||
"tryAgain": "Паспрабуйце яшчэ раз",
|
||||
"viewRecoveryKey": "Прагледзець ключ аднаўлення",
|
||||
"confirmRecoveryKey": "Пацвердзіце ключ аднаўлення",
|
||||
"confirmYourRecoveryKey": "Пацвердзіце свой ключ аднаўлення",
|
||||
"confirm": "Пацвердзіць",
|
||||
"emailYourLogs": "Адправіць журналы",
|
||||
@@ -221,15 +252,22 @@
|
||||
"pendingSyncs": "Папярэджанне",
|
||||
"pendingSyncsWarningBody": "Некаторыя вашы коды не былі зарэзерваваны.\n\nПераканайцеся, што ў вас ёсць іх рэзервовая копія перад выхадам з сістэмы.",
|
||||
"checkInboxAndSpamFolder": "Праверце свае ўваходныя лісты (і спам) для завяршэння праверкі",
|
||||
"tapToEnterCode": "Націсніце, каб увесці код",
|
||||
"resendEmail": "Адправіць ліст яшчэ раз",
|
||||
"manualSort": "Карыстальніцкая",
|
||||
"editOrder": "Рэдагаваць заказ",
|
||||
"mostFrequentlyUsed": "Часта выкарыстоўваюцца",
|
||||
"mostRecentlyUsed": "Нядаўна выкарыстаныя",
|
||||
"activeSessions": "Актыўныя сеансы",
|
||||
"terminateSession": "Перарваць сеанс?",
|
||||
"terminate": "Перарваць",
|
||||
"thisDevice": "Гэта прылада",
|
||||
"thisEmailIsAlreadyInUse": "Гэта электронная пошта ўжо выкарыстоўваецца",
|
||||
"yourVerificationCodeHasExpired": "Ваш праверачны код пратэрмінаваны",
|
||||
"incorrectCode": "Няправільны код",
|
||||
"emailChangedTo": "Электронная пошта зменена на {newEmail}",
|
||||
"authenticationSuccessful": "Аўтэнтыфікацыя паспяхова пройдзена!",
|
||||
"incorrectRecoveryKey": "Няправільны ключ аднаўлення",
|
||||
"enterPassword": "Увядзіце пароль",
|
||||
"selectExportFormat": "Выберыце фармат экспартавання",
|
||||
"exportDialogDesc": "Зашыфраванае экспартаванне будзе абаронена паролем, які вы выберыце.",
|
||||
@@ -249,10 +287,18 @@
|
||||
"focusOnSearchBar": "Сфакусіравацца на пошуку пры запуску праграмы",
|
||||
"confirmUpdatingkey": "Вы сапраўды хочаце абнавіць сакрэтны ключ?",
|
||||
"minimizeAppOnCopy": "Згортваць праграму пры капіяванні",
|
||||
"editCodeAuthMessage": "Прайдзіце аўтэнтыфікацыю, каб рэдагаваць код",
|
||||
"deleteCodeAuthMessage": "Прайдзіце аўтэнтыфікацыю, каб выдаліць код",
|
||||
"showQRAuthMessage": "Прайдзіце аўтэнтыфікацыю, каб паказаць QR-код",
|
||||
"confirmAccountDeleteTitle": "Пацвердзіце выдаленне ўліковага запісу",
|
||||
"androidBiometricHint": "Праверыць ідэнтыфікацыю",
|
||||
"@androidBiometricHint": {
|
||||
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricNotRecognized": "Не распазнана. Паспрабуйце яшчэ раз.",
|
||||
"@androidBiometricNotRecognized": {
|
||||
"description": "Message to let the user know that authentication was failed. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricSuccess": "Паспяхова",
|
||||
"@androidBiometricSuccess": {
|
||||
"description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters."
|
||||
@@ -261,6 +307,22 @@
|
||||
"@androidCancelButton": {
|
||||
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters."
|
||||
},
|
||||
"androidSignInTitle": "Патрабуецца аўтэнтыфікацыя",
|
||||
"@androidSignInTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user that they need to scan biometric to continue. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricRequiredTitle": "Патрабуецца біяметрыя",
|
||||
"@androidBiometricRequiredTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user has not set up biometric authentication on their device. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidDeviceCredentialsRequiredTitle": "Патрабуюцца ўліковыя даныя прылады",
|
||||
"@androidDeviceCredentialsRequiredTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user has not set up credentials authentication on their device. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidDeviceCredentialsSetupDescription": "Патрабуюцца ўліковыя даныя прылады",
|
||||
"@androidDeviceCredentialsSetupDescription": {
|
||||
"description": "Message advising the user to go to the settings and configure device credentials on their device. It shows in a dialog on Android side."
|
||||
},
|
||||
"goToSettings": "Перайсці ў налады",
|
||||
"@goToSettings": {
|
||||
"description": "Message showed on a button that the user can click to go to settings pages from the current dialog. It is used on both Android and iOS side. Maximum 30 characters."
|
||||
@@ -269,11 +331,24 @@
|
||||
"@iOSOkButton": {
|
||||
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters."
|
||||
},
|
||||
"noInternetConnection": "Адсутнічае падключэнне да інтэрнэту",
|
||||
"signOutFromOtherDevices": "Выйсці з іншых прылад",
|
||||
"signOutOtherDevices": "Выйсці на іншых прыладах",
|
||||
"doNotSignOut": "Не выходзіць",
|
||||
"waitingForBrowserRequest": "Чаканне запыту браўзера...",
|
||||
"waitingForVerification": "Чаканне праверкі...",
|
||||
"passkey": "Ключ доступу",
|
||||
"passKeyPendingVerification": "Праверка пакуль яшчэ не завершана",
|
||||
"loginSessionExpired": "Сеанс завяршыўся",
|
||||
"developerSettings": "Налады распрацоўшчыка",
|
||||
"serverEndpoint": "Канцавы пункт сервера",
|
||||
"invalidEndpoint": "Памылковы канцавы пункт",
|
||||
"endpointUpdatedMessage": "Канцавы пункт паспяхова абноўлены",
|
||||
"customEndpoint": "Падключана да {endpoint}",
|
||||
"pinText": "Замацаваць",
|
||||
"unpinText": "Адмацаваць",
|
||||
"pinnedCodeMessage": "{code} быў замацаваны",
|
||||
"unpinnedCodeMessage": "{code} быў адмацаваны",
|
||||
"pinned": "Замацавана",
|
||||
"tags": "Тэгі",
|
||||
"createNewTag": "Стварыць новы тэг",
|
||||
@@ -281,23 +356,38 @@
|
||||
"create": "Стварыць",
|
||||
"editTag": "Рэдагаванне тэг",
|
||||
"deleteTagTitle": "Выдаліць тэг?",
|
||||
"updateNotAvailable": "Абнаўленне недаступна",
|
||||
"viewRawCodes": "Паглядзець неапрацаваныя коды",
|
||||
"rawCodes": "Неапрацаваныя коды",
|
||||
"rawCodeData": "Неапрацаваныя даныя кода",
|
||||
"appLock": "Блакіроўка праграмы",
|
||||
"noSystemLockFound": "Сістэма блакіроўкі не знойдзена",
|
||||
"autoLock": "Аўтаблакіроўка",
|
||||
"immediately": "Адразу",
|
||||
"reEnterPassword": "Увядзіце пароль паўторна",
|
||||
"reEnterPin": "Увядзіце PIN-код яшчэ раз",
|
||||
"next": "Далей",
|
||||
"tooManyIncorrectAttempts": "Занадта шмат няўдалых спроб",
|
||||
"tapToUnlock": "Націсніце для разблакіроўкі",
|
||||
"setNewPassword": "Задаць новы пароль",
|
||||
"deviceLock": "Блакіроўка прылады",
|
||||
"hideContent": "Схаваць змест",
|
||||
"pinLock": "Блакіроўка PIN'ам",
|
||||
"enterPin": "Увядзіце PIN-код",
|
||||
"setNewPin": "Задаць новы PIN",
|
||||
"appLockNotEnabled": "Блакіроўка праграмы не ўключана",
|
||||
"duplicateCodes": "Дублікаты кадоў",
|
||||
"noDuplicates": "✨ Няма дублікатаў",
|
||||
"deduplicateCodes": "Дубліраваныя кады",
|
||||
"deselectAll": "Зняць выбар з усіх",
|
||||
"selectAll": "Выбраць усе",
|
||||
"deleteDuplicates": "Выдаліць дублікаты",
|
||||
"plainHTML": "Звычайны HTML",
|
||||
"tellUsWhatYouThink": "Раскажыце, што вы думаеце",
|
||||
"dropReviewiOS": "Пакіньце водгук у App Store",
|
||||
"dropReviewAndroid": "Пакіньце водгук у Play Store",
|
||||
"giveUsAStarOnGithub": "Адзначце нас зоркай на Github",
|
||||
"loginWithAuthAccount": "Увайдзіце з дапамогай уліковага запісу Auth",
|
||||
"advanced": "Пашыраныя",
|
||||
"algorithm": "Алгарытм",
|
||||
"type": "Тып",
|
||||
|
||||
@@ -173,6 +173,7 @@
|
||||
"invalidQRCode": "Código QR no válido",
|
||||
"noRecoveryKeyTitle": "¿No tienes la clave de recuperación?",
|
||||
"enterEmailHint": "Introduce tu dirección de correo electrónico",
|
||||
"enterNewEmailHint": "Introduce tu nueva dirección de correo electrónico",
|
||||
"invalidEmailTitle": "Dirección de correo electrónico no válida",
|
||||
"invalidEmailMessage": "Por favor, introduce una dirección de correo electrónico válida.",
|
||||
"deleteAccount": "Eliminar cuenta",
|
||||
@@ -513,5 +514,10 @@
|
||||
"free5GB": "5 GB gratis en <bold-green>ente</bold-green> Fotos",
|
||||
"loginWithAuthAccount": "Inicia sesión con tu cuenta de Auth",
|
||||
"freeStorageOffer": "10% de descuento en <bold-green>ente</bold-green> fotos",
|
||||
"freeStorageOfferDescription": "Usa el cupón \"AUTH\" para obtener un 10% de descuento en el primer año"
|
||||
"freeStorageOfferDescription": "Usa el cupón \"AUTH\" para obtener un 10% de descuento en el primer año",
|
||||
"advanced": "Avanzado",
|
||||
"algorithm": "Algoritmo",
|
||||
"type": "Tipo",
|
||||
"period": "Periodo",
|
||||
"digits": "Dígitos"
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
"setupFirstAccount": "Lisa oma esimene kasutajakonto",
|
||||
"importScanQrCode": "Skanneeri QR-koodi",
|
||||
"qrCode": "QR-kood",
|
||||
"importEnterSetupKey": "Sisesta seadistusvõti",
|
||||
"importAccountPageTitle": "Sisesta kasutajakonto üksikasjad",
|
||||
"secretCanNotBeEmpty": "Saladus ei tohi jääda tühjaks",
|
||||
"bothIssuerAndAccountCanNotBeEmpty": "Nii kasutajakonto kui väljaandja ei tohi tühjaks jääda",
|
||||
@@ -32,6 +33,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"codeAccountHint": "Kasutajakonto (sina@domeen.com)",
|
||||
"codeTagHint": "Silt",
|
||||
"accountKeyType": "Võtme tüüp",
|
||||
"sessionExpired": "Sessioon on aegunud",
|
||||
@@ -40,7 +42,12 @@
|
||||
},
|
||||
"pleaseLoginAgain": "Palun logi uuesti sisse",
|
||||
"loggingOut": "Väljalogimine...",
|
||||
"timeBasedKeyType": "Ajapõhine (TOTP)",
|
||||
"counterBasedKeyType": "Loenduripõhine (HOTP)",
|
||||
"saveAction": "Salvesta",
|
||||
"nextTotpTitle": "järgmine",
|
||||
"deleteCodeTitle": "Kas kustutame koodi?",
|
||||
"deleteCodeMessage": "Kas sa oled kindel, et soovid selle koodi kustutada? Seda tegevust ei saa tagasi pöörata.",
|
||||
"trash": "Prügikast",
|
||||
"viewLogsAction": "Vaata logisid",
|
||||
"preparingLogsTitle": "Valmistan logisid ette...",
|
||||
@@ -56,7 +63,18 @@
|
||||
"copyEmailAction": "Kopeeri e-posti aadress",
|
||||
"exportLogsAction": "Ekspordi logid",
|
||||
"reportABug": "Teata veast",
|
||||
"contactSupport": "Võtke ühendust klienditoega",
|
||||
"crashAndErrorReporting": "Teatamine vigadest ja kokkujooksmistest",
|
||||
"reportBug": "Teata veast",
|
||||
"emailUsMessage": "Saada meile e-kiri aadressile {email}",
|
||||
"@emailUsMessage": {
|
||||
"placeholders": {
|
||||
"email": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"contactSupport": "Võta ühendust klienditoega",
|
||||
"rateUsOnStore": "Arvusta meid rakendustepoes: {storeName}",
|
||||
"blog": "Blogi",
|
||||
"verifyPassword": "Korda salasõna",
|
||||
"pleaseWait": "Palun oota...",
|
||||
@@ -70,8 +88,13 @@
|
||||
"changeEmail": "Muuda e-posti aadressi",
|
||||
"changePassword": "Muuda salasõna",
|
||||
"data": "Andmed",
|
||||
"importCodes": "Impordi koode",
|
||||
"importTypePlainText": "Votmindamata tekstina",
|
||||
"importTypeEnteEncrypted": "Ente krüptitud ekspordina",
|
||||
"passwordForDecryptingExport": "Salasõna eksporditud andmete dekrüptimiseks",
|
||||
"passwordEmptyError": "Salasõna väli ei saa olla tühi",
|
||||
"importFromApp": "Impordi koodid rakendusest {appName}",
|
||||
"selectFile": "Vali fail",
|
||||
"ok": "Sobib",
|
||||
"cancel": "Katkesta",
|
||||
"yes": "Jah",
|
||||
|
||||
@@ -506,7 +506,7 @@
|
||||
"selectAll": "Chọn tất cả",
|
||||
"deleteDuplicates": "Xóa trùng lặp",
|
||||
"plainHTML": "HTML thuần",
|
||||
"tellUsWhatYouThink": "Hãy cho chúng tôi biết bạn nghĩ gì",
|
||||
"tellUsWhatYouThink": "Cho biết bạn nghĩ gì",
|
||||
"dropReviewiOS": "Đánh giá ngay trên App Store",
|
||||
"dropReviewAndroid": "Đánh giá ngay trên Play Store",
|
||||
"supportEnte": "Hỗ trợ <bold-green>ente</bold-green>",
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<releases>
|
||||
<release version="4.4.2" date="2025-06-21" />
|
||||
<release version="4.4.0" date="2025-05-31" />
|
||||
<release version="4.3.8" date="2025-05-20" />
|
||||
<release version="4.2.4" date="2025-01-11" />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
name: ente_auth
|
||||
description: ente two-factor authenticator
|
||||
version: 4.4.1+441
|
||||
version: 4.4.2+442
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
|
||||
@@ -46,27 +46,25 @@ You can alternatively install the build from PlayStore or F-Droid.
|
||||
|
||||
## 🧑💻 Building from source
|
||||
|
||||
1. Install [Flutter v3.24.3](https://flutter.dev/docs/get-started/install) and [Rust v1.85.1](https://www.rust-lang.org/tools/install).
|
||||
1. [Install Flutter v3.24.3](https://flutter.dev/docs/get-started/install).
|
||||
|
||||
2. Install [Flutter Rust Bridge](https://cjycode.com/flutter_rust_bridge/) with `cargo install flutter_rust_bridge_codegen`
|
||||
2. Pull in all submodules with `git submodule update --init --recursive`
|
||||
|
||||
3. Pull in all submodules with `git submodule update --init --recursive`
|
||||
3. Enable repo git hooks `git config core.hooksPath hooks`
|
||||
|
||||
4. Enable repo git hooks `git config core.hooksPath hooks`
|
||||
|
||||
5. If using Visual Studio Code, add the [Flutter
|
||||
4. If using Visual Studio Code, add the [Flutter
|
||||
Intl](https://marketplace.visualstudio.com/items?itemName=localizely.flutter-intl)
|
||||
extension
|
||||
|
||||
6. On Android:
|
||||
5. On Android:
|
||||
|
||||
- For development, run `flutter run -t lib/main.dart --flavor independent`
|
||||
* For development, run `flutter run -t lib/main.dart --flavor independent`
|
||||
|
||||
- For building APK, [setup your
|
||||
* For building APK, [setup your
|
||||
keystore](https://docs.flutter.dev/deployment/android#create-an-upload-keystore)
|
||||
and run `flutter build apk --release --flavor independent`
|
||||
|
||||
7. For iOS, run `flutter build ios`
|
||||
6. For iOS, run `flutter build ios`
|
||||
|
||||
Some common issues and troubleshooting tips are in [docs/dev](docs/dev.md).
|
||||
|
||||
@@ -90,12 +88,11 @@ issue](https://github.com/ente-io/ente/issues/new?title=Request+for+New+Language
|
||||
to have it added.
|
||||
|
||||
## Certificate Fingerprints
|
||||
|
||||
|
||||
- **SHA1**: E1:60:10:18:B6:B0:2E:A3:74:6F:90:67:50:30:29:75:0E:EF:6D:39
|
||||
- **SHA256**: 35:ED:56:81:B7:0B:B3:BD:35:D9:0D:85:6A:F5:69:4C:50:4D:EF:46:AA:D8:3F:77:7B:1C:67:5C:F4:51:35:0B
|
||||
|
||||
To verify these fingerprints, use the following command:
|
||||
|
||||
```bash
|
||||
apksigner verify --print-certs <path_to_apk>
|
||||
```
|
||||
|
||||
@@ -31,7 +31,7 @@ if (keystorePropertiesFile.exists()) {
|
||||
android {
|
||||
namespace = "io.ente.photos"
|
||||
compileSdk = 35
|
||||
ndkVersion = "28.0.13004108"
|
||||
ndkVersion = flutter.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
rust_input: crate::api
|
||||
rust_root: rust/
|
||||
dart_output: lib/src/rust
|
||||
|
||||
dart_preamble: |
|
||||
// ignore_for_file: require_trailing_commas
|
||||
|
||||
web: false
|
||||
@@ -91,9 +91,10 @@ Future<void> dismissUpdateAppDialog(WidgetTester tester) async {
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
|
||||
///Use this widget as floating action buttom in HomeWidget so that frames
|
||||
///are built and rendered continuously so that timeline trace has continuous
|
||||
///data. Change the duraiton in `_startTimer()` to control the duraiton of
|
||||
///are built and rendered continuously so that timeline trace has continuous
|
||||
///data. Change the duraiton in `_startTimer()` to control the duraiton of
|
||||
///test on app init.
|
||||
|
||||
// class TempWidget extends StatefulWidget {
|
||||
@@ -126,4 +127,4 @@ Future<void> dismissUpdateAppDialog(WidgetTester tester) async {
|
||||
// ? const CircularProgressIndicator()
|
||||
// : const SizedBox.shrink();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
@@ -1,13 +0,0 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
import "package:photos/src/rust/api/simple.dart";
|
||||
import 'package:photos/src/rust/frb_generated.dart';
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
setUpAll(() async => await RustLib.init());
|
||||
testWidgets('Can call rust function', (WidgetTester tester) async {
|
||||
final testString = greet(name: "Tom");
|
||||
expect(testString.contains('Tom'), true);
|
||||
});
|
||||
}
|
||||
@@ -288,7 +288,6 @@ DEPENDENCIES:
|
||||
- photo_manager (from `.symlinks/plugins/photo_manager/ios`)
|
||||
- privacy_screen (from `.symlinks/plugins/privacy_screen/ios`)
|
||||
- receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
|
||||
- rust_lib_photos (from `.symlinks/plugins/rust_lib_photos/ios`)
|
||||
- sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
@@ -416,8 +415,6 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/privacy_screen/ios"
|
||||
receive_sharing_intent:
|
||||
:path: ".symlinks/plugins/receive_sharing_intent/ios"
|
||||
rust_lib_photos:
|
||||
:path: ".symlinks/plugins/rust_lib_photos/ios"
|
||||
sentry_flutter:
|
||||
:path: ".symlinks/plugins/sentry_flutter/ios"
|
||||
share_plus:
|
||||
|
||||
@@ -566,7 +566,6 @@
|
||||
"${BUILT_PRODUCTS_DIR}/photo_manager/photo_manager.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/privacy_screen/privacy_screen.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/receive_sharing_intent/receive_sharing_intent.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/rust_lib_photos/rust_lib_photos.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/sentry_flutter/sentry_flutter.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/share_plus/share_plus.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/shared_preferences_foundation/shared_preferences_foundation.framework",
|
||||
@@ -663,7 +662,6 @@
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/photo_manager.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/privacy_screen.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/receive_sharing_intent.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/rust_lib_photos.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sentry_flutter.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share_plus.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_foundation.framework",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import "dart:io";
|
||||
|
||||
import 'package:photos/core/cache/lru_map.dart';
|
||||
|
||||
@@ -58,7 +58,7 @@ bool isHandledSyncError(Object errObj) {
|
||||
|
||||
class LockAlreadyAcquiredError extends Error {}
|
||||
|
||||
class LockFreedError extends Error {}
|
||||
class LockFreedError extends Error{}
|
||||
|
||||
class UnauthorizedError extends Error {}
|
||||
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
import "dart:typed_data" show Float32List;
|
||||
|
||||
import "package:flutter_rust_bridge/flutter_rust_bridge.dart" show Uint64List;
|
||||
import "package:logging/logging.dart";
|
||||
import "package:path/path.dart";
|
||||
import "package:path_provider/path_provider.dart";
|
||||
import "package:photos/models/ml/vector.dart";
|
||||
import "package:photos/services/machine_learning/semantic_search/query_result.dart";
|
||||
import "package:photos/src/rust/api/usearch_api.dart";
|
||||
|
||||
class ClipVectorDB {
|
||||
static final Logger _logger = Logger("ClipVectorDB");
|
||||
|
||||
static const _databaseName = "ente.ml.vectordb.clip";
|
||||
|
||||
static final BigInt _embeddingDimension = BigInt.from(512);
|
||||
|
||||
static Logger get logger => _logger;
|
||||
|
||||
// Singleton pattern
|
||||
ClipVectorDB._privateConstructor();
|
||||
static final instance = ClipVectorDB._privateConstructor();
|
||||
factory ClipVectorDB() => instance;
|
||||
|
||||
// only have a single app-wide reference to the database
|
||||
static Future<VectorDb>? _vectorDbFuture;
|
||||
|
||||
Future<VectorDb> get _vectorDB async {
|
||||
_vectorDbFuture ??= _initVectorDB();
|
||||
return _vectorDbFuture!;
|
||||
}
|
||||
|
||||
Future<VectorDb> _initVectorDB() async {
|
||||
final documentsDirectory = await getApplicationDocumentsDirectory();
|
||||
final String databaseDirectory =
|
||||
join(documentsDirectory.path, _databaseName);
|
||||
_logger.info("Opening vectorDB access: DB path " + databaseDirectory);
|
||||
final vectorDB = VectorDb(
|
||||
filePath: databaseDirectory,
|
||||
dimensions: _embeddingDimension,
|
||||
);
|
||||
final stats = await getIndexStats(vectorDB);
|
||||
_logger.info("VectorDB connection opened with stats: ${stats.toString()}");
|
||||
|
||||
return vectorDB;
|
||||
}
|
||||
|
||||
Future<void> insertEmbedding({
|
||||
required int fileID,
|
||||
required List<double> embedding,
|
||||
}) async {
|
||||
final db = await _vectorDB;
|
||||
try {
|
||||
await db.addVector(key: BigInt.from(fileID), vector: embedding);
|
||||
} catch (e, s) {
|
||||
_logger.severe("Error inserting embedding", e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> bulkInsertEmbeddings({
|
||||
required List<int> fileIDs,
|
||||
required List<Float32List> embeddings,
|
||||
}) async {
|
||||
final db = await _vectorDB;
|
||||
final bigKeys = Uint64List.fromList(fileIDs);
|
||||
try {
|
||||
await db.bulkAddVectors(keys: bigKeys, vectors: embeddings);
|
||||
} catch (e, s) {
|
||||
_logger.severe("Error bulk inserting embeddings", e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<EmbeddingVector>> getEmbeddings(List<int> fileIDs) async {
|
||||
final db = await _vectorDB;
|
||||
try {
|
||||
final keys = Uint64List.fromList(fileIDs);
|
||||
final vectors = await db.bulkGetVectors(keys: keys);
|
||||
return List.generate(
|
||||
vectors.length,
|
||||
(index) => EmbeddingVector(
|
||||
fileID: fileIDs[index],
|
||||
embedding: vectors[index],
|
||||
),
|
||||
);
|
||||
} catch (e, s) {
|
||||
_logger.severe("Error getting embeddings", e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteEmbeddings(List<int> fileIDs) async {
|
||||
final db = await _vectorDB;
|
||||
try {
|
||||
final deletedCount =
|
||||
await db.bulkRemoveVectors(keys: Uint64List.fromList(fileIDs));
|
||||
_logger.info(
|
||||
"Deleted $deletedCount embeddings, from ${fileIDs.length} keys",
|
||||
);
|
||||
} catch (e, s) {
|
||||
_logger.severe("Error bulk deleting specific embeddings", e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteAllEmbeddings() async {
|
||||
final db = await _vectorDB;
|
||||
try {
|
||||
await db.resetIndex();
|
||||
} catch (e, s) {
|
||||
_logger.severe("Error deleting all embeddings", e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteIndex() async {
|
||||
final db = await _vectorDB;
|
||||
try {
|
||||
await db.deleteIndex();
|
||||
_vectorDbFuture = null;
|
||||
} catch (e, s) {
|
||||
_logger.severe("Error deleting index", e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<VectorDbStats> getIndexStats([VectorDb? db]) async {
|
||||
db ??= await _vectorDB;
|
||||
try {
|
||||
final stats = await db.getIndexStats();
|
||||
return VectorDbStats(
|
||||
size: stats.$1.toInt(),
|
||||
capacity: stats.$2.toInt(),
|
||||
dimensions: stats.$3.toInt(),
|
||||
fileSize: stats.$4.toInt(),
|
||||
memoryUsage: stats.$5.toInt(),
|
||||
expansionAdd: stats.$6.toInt(),
|
||||
expansionSearch: stats.$7.toInt(),
|
||||
);
|
||||
} catch (e, s) {
|
||||
_logger.severe("Error getting index stats", e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<(Uint64List, Float32List)> searchClosestVectors(
|
||||
List<double> query,
|
||||
int count,
|
||||
) async {
|
||||
final db = await _vectorDB;
|
||||
try {
|
||||
final result =
|
||||
await db.searchVectors(query: query, count: BigInt.from(count));
|
||||
return result;
|
||||
} catch (e, s) {
|
||||
_logger.severe("Error searching closest vectors", e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<(BigInt, double)> searchClosestVector(
|
||||
List<double> query,
|
||||
) async {
|
||||
final db = await _vectorDB;
|
||||
try {
|
||||
final result = await db.searchVectors(query: query, count: BigInt.one);
|
||||
return (result.$1[0], result.$2[0]);
|
||||
} catch (e, s) {
|
||||
_logger.severe("Error searching closest vector", e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<Map<String, List<QueryResult>>> computeBulkSimilarities(
|
||||
Map<String, List<double>> textQueryToEmbeddingMap,
|
||||
Map<String, double> minimumSimilarityMap,
|
||||
) async {
|
||||
try {
|
||||
final queryToResults = <String, List<QueryResult>>{};
|
||||
for (final MapEntry<String, List<double>> entry
|
||||
in textQueryToEmbeddingMap.entries) {
|
||||
final query = entry.key;
|
||||
final minimumSimilarity = minimumSimilarityMap[query]!;
|
||||
final textEmbedding = entry.value;
|
||||
final (potentialFileIDs, distances) =
|
||||
await searchClosestVectors(textEmbedding, 1000);
|
||||
final queryResults = <QueryResult>[];
|
||||
for (var i = 0; i < potentialFileIDs.length; i++) {
|
||||
final similarity = 1 - distances[i];
|
||||
if (similarity >= minimumSimilarity) {
|
||||
queryResults
|
||||
.add(QueryResult(potentialFileIDs[i].toInt(), similarity));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
queryToResults[query] = queryResults;
|
||||
}
|
||||
return queryToResults;
|
||||
} catch (e, s) {
|
||||
_logger.severe(
|
||||
"Could not bulk find embeddings similarities using vector DB",
|
||||
e,
|
||||
s,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class VectorDbStats {
|
||||
final int size;
|
||||
final int capacity;
|
||||
final int dimensions;
|
||||
|
||||
// in bytes
|
||||
final int fileSize;
|
||||
final int memoryUsage;
|
||||
|
||||
final int expansionAdd;
|
||||
final int expansionSearch;
|
||||
|
||||
VectorDbStats({
|
||||
required this.size,
|
||||
required this.capacity,
|
||||
required this.dimensions,
|
||||
required this.fileSize,
|
||||
required this.memoryUsage,
|
||||
required this.expansionAdd,
|
||||
required this.expansionSearch,
|
||||
});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "VectorDbStats(size: $size, capacity: $capacity, dimensions: $dimensions, file size on disk (bytes): $fileSize, memory usage (bytes): $memoryUsage, expansionAdd: $expansionAdd, expansionSearch: $expansionSearch)";
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'dart:async';
|
||||
import "dart:io" show File;
|
||||
import "dart:math";
|
||||
|
||||
import "package:collection/collection.dart";
|
||||
@@ -10,7 +9,6 @@ import 'package:path_provider/path_provider.dart';
|
||||
import "package:photos/core/event_bus.dart";
|
||||
import "package:photos/db/common/base.dart";
|
||||
import "package:photos/db/ml/base.dart";
|
||||
import "package:photos/db/ml/clip_vector_db.dart";
|
||||
import "package:photos/db/ml/db_model_mappers.dart";
|
||||
import 'package:photos/db/ml/schema.dart';
|
||||
import "package:photos/events/embedding_updated_event.dart";
|
||||
@@ -20,7 +18,6 @@ import "package:photos/models/ml/face/face.dart";
|
||||
import "package:photos/models/ml/face/face_with_embedding.dart";
|
||||
import "package:photos/models/ml/ml_versions.dart";
|
||||
import "package:photos/models/ml/vector.dart";
|
||||
import "package:photos/service_locator.dart";
|
||||
import "package:photos/services/machine_learning/face_ml/face_clustering/face_db_info_for_clustering.dart";
|
||||
import 'package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart';
|
||||
import "package:photos/services/machine_learning/ml_result.dart";
|
||||
@@ -87,8 +84,6 @@ class MLDataDB with SqlDbBase implements IMLDataDB<int> {
|
||||
"MLDataDB Migration took ${stopwatch.elapsedMilliseconds} ms",
|
||||
);
|
||||
stopwatch.stop();
|
||||
_logger.info("Starting CLIP vector DB migration check unawaited");
|
||||
if (flagService.enableVectorDb) unawaited(checkMigrateFillClipVectorDB());
|
||||
|
||||
return asyncDBConnection;
|
||||
}
|
||||
@@ -1254,121 +1249,6 @@ class MLDataDB with SqlDbBase implements IMLDataDB<int> {
|
||||
return embeddings;
|
||||
}
|
||||
|
||||
Future<void> checkMigrateFillClipVectorDB({bool force = false}) async {
|
||||
_logger.info("Waiting for ClipVectorDB to be ready");
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
_logger.info("Checking if ClipVectorDB migration is needed");
|
||||
|
||||
// Check if vector DB migration has run
|
||||
_logger.info("Checking if ClipVectorDB migration has run");
|
||||
final documentsDirectory = await getApplicationDocumentsDirectory();
|
||||
final migrationFlagFile =
|
||||
File(join(documentsDirectory.path, 'clip_vector_migration_done'));
|
||||
if (await migrationFlagFile.exists() && !force) {
|
||||
_logger.info("ClipVectorDB migration not needed, already done");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get total count first to track progress
|
||||
_logger.info("Getting total count of clip embeddings");
|
||||
final db = await instance.asyncDB;
|
||||
final countResult =
|
||||
await db.getAll('SELECT COUNT($fileIDColumn) as total FROM $clipTable');
|
||||
final totalCount = countResult.first['total'] as int;
|
||||
if (totalCount == 0) {
|
||||
_logger.info("No clip embeddings to migrate");
|
||||
await migrationFlagFile.create();
|
||||
return;
|
||||
}
|
||||
_logger.info("Total count of clip embeddings: $totalCount");
|
||||
|
||||
_logger.info("First time referencing ClipVectorDB in migration");
|
||||
final clipVectorDB = ClipVectorDB.instance;
|
||||
_logger.info("ClipVectorDB referenced");
|
||||
await clipVectorDB.deleteAllEmbeddings();
|
||||
_logger.info("ClipVectorDB all embeddings cleared");
|
||||
|
||||
_logger
|
||||
.info("Starting migration of $totalCount clip embeddings to vector DB");
|
||||
const batchSize = 1000;
|
||||
int offset = 0;
|
||||
int processedCount = 0;
|
||||
int weirdCount = 0;
|
||||
int whileCount = 0;
|
||||
final stopwatch = Stopwatch()..start();
|
||||
try {
|
||||
while (true) {
|
||||
whileCount++;
|
||||
_logger.info("$whileCount st round of while loop");
|
||||
// Allow some time for any GC to finish
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
_logger.info("Reading $batchSize rows from DB");
|
||||
final List<Map<String, dynamic>> results = await db.getAll('''
|
||||
SELECT $fileIDColumn, $embeddingColumn
|
||||
FROM $clipTable
|
||||
ORDER BY $fileIDColumn DESC
|
||||
LIMIT $batchSize OFFSET $offset
|
||||
''');
|
||||
_logger.info("Got ${results.length} results from DB");
|
||||
if (results.isEmpty) {
|
||||
_logger.info("No more results, breaking out of while loop");
|
||||
break;
|
||||
}
|
||||
_logger.info("Processing ${results.length} results");
|
||||
final List<int> fileIDs = [];
|
||||
final List<Float32List> embeddings = [];
|
||||
for (final result in results) {
|
||||
final embedding =
|
||||
Float32List.view((result[embeddingColumn] as Uint8List).buffer);
|
||||
if (embedding.length == 512) {
|
||||
fileIDs.add(result[fileIDColumn] as int);
|
||||
embeddings.add(Float32List.view(result[embeddingColumn].buffer));
|
||||
} else {
|
||||
weirdCount++;
|
||||
}
|
||||
}
|
||||
_logger.info(
|
||||
"Got ${fileIDs.length} valid embeddings, $weirdCount weird embeddings",
|
||||
);
|
||||
|
||||
await ClipVectorDB.instance
|
||||
.bulkInsertEmbeddings(fileIDs: fileIDs, embeddings: embeddings);
|
||||
_logger.info("Inserted ${fileIDs.length} embeddings to ClipVectorDB");
|
||||
processedCount += fileIDs.length;
|
||||
offset += batchSize;
|
||||
_logger.info(
|
||||
"migrated $processedCount/$totalCount embeddings to ClipVectorDB",
|
||||
);
|
||||
if (processedCount >= totalCount) {
|
||||
_logger.info("All embeddings migrated, breaking out of while loop");
|
||||
break;
|
||||
}
|
||||
_logger.info("Clearing out embeddings and fileIDs");
|
||||
embeddings.clear();
|
||||
fileIDs.clear();
|
||||
results.clear();
|
||||
// Allow some time for any GC to finish
|
||||
_logger.info("Waiting for 100ms for GC to finish");
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
}
|
||||
_logger.info(
|
||||
"migrated all $totalCount embeddings to ClipVectorDB in ${stopwatch.elapsed.inMilliseconds} ms, with $weirdCount weird embeddings not migrated",
|
||||
);
|
||||
await migrationFlagFile.create();
|
||||
_logger.info("ClipVectorDB migration done, flag file created");
|
||||
} catch (e) {
|
||||
_logger.severe(
|
||||
"Error migrating ClipVectorDB after ${stopwatch.elapsed.inMilliseconds} ms, clearing out DB again",
|
||||
e,
|
||||
);
|
||||
await clipVectorDB.deleteAllEmbeddings();
|
||||
rethrow;
|
||||
} finally {
|
||||
stopwatch.stop();
|
||||
}
|
||||
}
|
||||
|
||||
// Get indexed FileIDs
|
||||
@override
|
||||
Future<Map<int, int>> clipIndexedFileWithVersion() async {
|
||||
@@ -1402,25 +1282,12 @@ class MLDataDB with SqlDbBase implements IMLDataDB<int> {
|
||||
'INSERT OR REPLACE INTO $clipTable ($fileIDColumn, $embeddingColumn, $mlVersionColumn) VALUES (?, ?, ?)',
|
||||
_getRowFromEmbedding(embeddings.first),
|
||||
);
|
||||
if (flagService.enableVectorDb) {
|
||||
await ClipVectorDB.instance.insertEmbedding(
|
||||
fileID: embeddings.first.fileID,
|
||||
embedding: embeddings.first.embedding,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
final inputs = embeddings.map((e) => _getRowFromEmbedding(e)).toList();
|
||||
await db.executeBatch(
|
||||
'INSERT OR REPLACE INTO $clipTable ($fileIDColumn, $embeddingColumn, $mlVersionColumn) values(?, ?, ?)',
|
||||
inputs,
|
||||
);
|
||||
if (flagService.enableVectorDb) {
|
||||
await ClipVectorDB.instance.bulkInsertEmbeddings(
|
||||
fileIDs: embeddings.map((e) => e.fileID).toList(),
|
||||
embeddings:
|
||||
embeddings.map((e) => Float32List.fromList(e.embedding)).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Bus.instance.fire(EmbeddingUpdatedEvent());
|
||||
}
|
||||
@@ -1431,9 +1298,6 @@ class MLDataDB with SqlDbBase implements IMLDataDB<int> {
|
||||
await db.execute(
|
||||
'DELETE FROM $clipTable WHERE $fileIDColumn IN (${fileIDs.join(", ")})',
|
||||
);
|
||||
if (flagService.enableVectorDb) {
|
||||
await ClipVectorDB.instance.deleteEmbeddings(fileIDs);
|
||||
}
|
||||
Bus.instance.fire(EmbeddingUpdatedEvent());
|
||||
}
|
||||
|
||||
@@ -1441,9 +1305,6 @@ class MLDataDB with SqlDbBase implements IMLDataDB<int> {
|
||||
Future<void> deleteClipIndexes() async {
|
||||
final db = await instance.asyncDB;
|
||||
await db.execute('DELETE FROM $clipTable');
|
||||
if (flagService.enableVectorDb) {
|
||||
await ClipVectorDB.instance.deleteAllEmbeddings();
|
||||
}
|
||||
Bus.instance.fire(EmbeddingUpdatedEvent());
|
||||
}
|
||||
|
||||
|
||||
@@ -37,32 +37,27 @@ class CenterBox extends $pb.GeneratedMessage {
|
||||
return $result;
|
||||
}
|
||||
CenterBox._() : super();
|
||||
factory CenterBox.fromBuffer($core.List<$core.int> i,
|
||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(i, r);
|
||||
factory CenterBox.fromJson($core.String i,
|
||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(i, r);
|
||||
factory CenterBox.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory CenterBox.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'CenterBox',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.common'),
|
||||
createEmptyInstance: create)
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CenterBox', package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.common'), createEmptyInstance: create)
|
||||
..a<$core.double>(1, _omitFieldNames ? '' : 'x', $pb.PbFieldType.OF)
|
||||
..a<$core.double>(2, _omitFieldNames ? '' : 'y', $pb.PbFieldType.OF)
|
||||
..a<$core.double>(3, _omitFieldNames ? '' : 'height', $pb.PbFieldType.OF)
|
||||
..a<$core.double>(4, _omitFieldNames ? '' : 'width', $pb.PbFieldType.OF)
|
||||
..hasRequiredFields = false;
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
|
||||
@$core.Deprecated('Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
CenterBox clone() => CenterBox()..mergeFromMessage(this);
|
||||
@$core.Deprecated('Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
CenterBox copyWith(void Function(CenterBox) updates) =>
|
||||
super.copyWith((message) => updates(message as CenterBox)) as CenterBox;
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
CenterBox copyWith(void Function(CenterBox) updates) => super.copyWith((message) => updates(message as CenterBox)) as CenterBox;
|
||||
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@@ -71,17 +66,13 @@ class CenterBox extends $pb.GeneratedMessage {
|
||||
CenterBox createEmptyInstance() => create();
|
||||
static $pb.PbList<CenterBox> createRepeated() => $pb.PbList<CenterBox>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static CenterBox getDefault() =>
|
||||
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<CenterBox>(create);
|
||||
static CenterBox getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<CenterBox>(create);
|
||||
static CenterBox? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.double get x => $_getN(0);
|
||||
@$pb.TagNumber(1)
|
||||
set x($core.double v) {
|
||||
$_setFloat(0, v);
|
||||
}
|
||||
|
||||
set x($core.double v) { $_setFloat(0, v); }
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasX() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
@@ -90,10 +81,7 @@ class CenterBox extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(2)
|
||||
$core.double get y => $_getN(1);
|
||||
@$pb.TagNumber(2)
|
||||
set y($core.double v) {
|
||||
$_setFloat(1, v);
|
||||
}
|
||||
|
||||
set y($core.double v) { $_setFloat(1, v); }
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasY() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
@@ -102,10 +90,7 @@ class CenterBox extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(3)
|
||||
$core.double get height => $_getN(2);
|
||||
@$pb.TagNumber(3)
|
||||
set height($core.double v) {
|
||||
$_setFloat(2, v);
|
||||
}
|
||||
|
||||
set height($core.double v) { $_setFloat(2, v); }
|
||||
@$pb.TagNumber(3)
|
||||
$core.bool hasHeight() => $_has(2);
|
||||
@$pb.TagNumber(3)
|
||||
@@ -114,16 +99,13 @@ class CenterBox extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(4)
|
||||
$core.double get width => $_getN(3);
|
||||
@$pb.TagNumber(4)
|
||||
set width($core.double v) {
|
||||
$_setFloat(3, v);
|
||||
}
|
||||
|
||||
set width($core.double v) { $_setFloat(3, v); }
|
||||
@$pb.TagNumber(4)
|
||||
$core.bool hasWidth() => $_has(3);
|
||||
@$pb.TagNumber(4)
|
||||
void clearWidth() => clearField(4);
|
||||
}
|
||||
|
||||
|
||||
const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
|
||||
const _omitMessageNames =
|
||||
$core.bool.fromEnvironment('protobuf.omit_message_names');
|
||||
const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
|
||||
|
||||
@@ -8,3 +8,4 @@
|
||||
// ignore_for_file: constant_identifier_names, library_prefixes
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
|
||||
|
||||
@@ -35,3 +35,4 @@ final $typed_data.Uint8List centerBoxDescriptor = $convert.base64Decode(
|
||||
'CglDZW50ZXJCb3gSEQoBeBgBIAEoAkgAUgF4iAEBEhEKAXkYAiABKAJIAVIBeYgBARIbCgZoZW'
|
||||
'lnaHQYAyABKAJIAlIGaGVpZ2h0iAEBEhkKBXdpZHRoGAQgASgCSANSBXdpZHRoiAEBQgQKAl94'
|
||||
'QgQKAl95QgkKB19oZWlnaHRCCAoGX3dpZHRo');
|
||||
|
||||
|
||||
@@ -11,3 +11,4 @@
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
|
||||
export 'box.pb.dart';
|
||||
|
||||
|
||||
@@ -29,30 +29,25 @@ class EPoint extends $pb.GeneratedMessage {
|
||||
return $result;
|
||||
}
|
||||
EPoint._() : super();
|
||||
factory EPoint.fromBuffer($core.List<$core.int> i,
|
||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(i, r);
|
||||
factory EPoint.fromJson($core.String i,
|
||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(i, r);
|
||||
factory EPoint.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory EPoint.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'EPoint',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.common'),
|
||||
createEmptyInstance: create)
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'EPoint', package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.common'), createEmptyInstance: create)
|
||||
..a<$core.double>(1, _omitFieldNames ? '' : 'x', $pb.PbFieldType.OF)
|
||||
..a<$core.double>(2, _omitFieldNames ? '' : 'y', $pb.PbFieldType.OF)
|
||||
..hasRequiredFields = false;
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
|
||||
@$core.Deprecated('Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
EPoint clone() => EPoint()..mergeFromMessage(this);
|
||||
@$core.Deprecated('Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
EPoint copyWith(void Function(EPoint) updates) =>
|
||||
super.copyWith((message) => updates(message as EPoint)) as EPoint;
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
EPoint copyWith(void Function(EPoint) updates) => super.copyWith((message) => updates(message as EPoint)) as EPoint;
|
||||
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@@ -61,17 +56,13 @@ class EPoint extends $pb.GeneratedMessage {
|
||||
EPoint createEmptyInstance() => create();
|
||||
static $pb.PbList<EPoint> createRepeated() => $pb.PbList<EPoint>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static EPoint getDefault() =>
|
||||
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<EPoint>(create);
|
||||
static EPoint getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<EPoint>(create);
|
||||
static EPoint? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.double get x => $_getN(0);
|
||||
@$pb.TagNumber(1)
|
||||
set x($core.double v) {
|
||||
$_setFloat(0, v);
|
||||
}
|
||||
|
||||
set x($core.double v) { $_setFloat(0, v); }
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasX() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
@@ -80,16 +71,13 @@ class EPoint extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(2)
|
||||
$core.double get y => $_getN(1);
|
||||
@$pb.TagNumber(2)
|
||||
set y($core.double v) {
|
||||
$_setFloat(1, v);
|
||||
}
|
||||
|
||||
set y($core.double v) { $_setFloat(1, v); }
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasY() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearY() => clearField(2);
|
||||
}
|
||||
|
||||
|
||||
const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
|
||||
const _omitMessageNames =
|
||||
$core.bool.fromEnvironment('protobuf.omit_message_names');
|
||||
const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
|
||||
|
||||
@@ -8,3 +8,4 @@
|
||||
// ignore_for_file: constant_identifier_names, library_prefixes
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
|
||||
|
||||
@@ -30,3 +30,4 @@ const EPoint$json = {
|
||||
final $typed_data.Uint8List ePointDescriptor = $convert.base64Decode(
|
||||
'CgZFUG9pbnQSEQoBeBgBIAEoAkgAUgF4iAEBEhEKAXkYAiABKAJIAVIBeYgBAUIECgJfeEIECg'
|
||||
'JfeQ==');
|
||||
|
||||
|
||||
@@ -11,3 +11,4 @@
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
|
||||
export 'point.pb.dart';
|
||||
|
||||
|
||||
@@ -26,29 +26,24 @@ class EVector extends $pb.GeneratedMessage {
|
||||
return $result;
|
||||
}
|
||||
EVector._() : super();
|
||||
factory EVector.fromBuffer($core.List<$core.int> i,
|
||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(i, r);
|
||||
factory EVector.fromJson($core.String i,
|
||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(i, r);
|
||||
factory EVector.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory EVector.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'EVector',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.common'),
|
||||
createEmptyInstance: create)
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'EVector', package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.common'), createEmptyInstance: create)
|
||||
..p<$core.double>(1, _omitFieldNames ? '' : 'values', $pb.PbFieldType.KD)
|
||||
..hasRequiredFields = false;
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
|
||||
@$core.Deprecated('Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
EVector clone() => EVector()..mergeFromMessage(this);
|
||||
@$core.Deprecated('Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
EVector copyWith(void Function(EVector) updates) =>
|
||||
super.copyWith((message) => updates(message as EVector)) as EVector;
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
EVector copyWith(void Function(EVector) updates) => super.copyWith((message) => updates(message as EVector)) as EVector;
|
||||
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@@ -57,14 +52,13 @@ class EVector extends $pb.GeneratedMessage {
|
||||
EVector createEmptyInstance() => create();
|
||||
static $pb.PbList<EVector> createRepeated() => $pb.PbList<EVector>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static EVector getDefault() =>
|
||||
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<EVector>(create);
|
||||
static EVector getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<EVector>(create);
|
||||
static EVector? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.List<$core.double> get values => $_getList(0);
|
||||
}
|
||||
|
||||
|
||||
const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
|
||||
const _omitMessageNames =
|
||||
$core.bool.fromEnvironment('protobuf.omit_message_names');
|
||||
const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
|
||||
|
||||
@@ -8,3 +8,4 @@
|
||||
// ignore_for_file: constant_identifier_names, library_prefixes
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
|
||||
|
||||
@@ -22,5 +22,6 @@ const EVector$json = {
|
||||
};
|
||||
|
||||
/// Descriptor for `EVector`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List eVectorDescriptor =
|
||||
$convert.base64Decode('CgdFVmVjdG9yEhYKBnZhbHVlcxgBIAMoAVIGdmFsdWVz');
|
||||
final $typed_data.Uint8List eVectorDescriptor = $convert.base64Decode(
|
||||
'CgdFVmVjdG9yEhYKBnZhbHVlcxgBIAMoAVIGdmFsdWVz');
|
||||
|
||||
|
||||
@@ -11,3 +11,4 @@
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
|
||||
export 'vector.pb.dart';
|
||||
|
||||
|
||||
@@ -31,32 +31,25 @@ class Detection extends $pb.GeneratedMessage {
|
||||
return $result;
|
||||
}
|
||||
Detection._() : super();
|
||||
factory Detection.fromBuffer($core.List<$core.int> i,
|
||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(i, r);
|
||||
factory Detection.fromJson($core.String i,
|
||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(i, r);
|
||||
factory Detection.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory Detection.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'Detection',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.ml'),
|
||||
createEmptyInstance: create)
|
||||
..aOM<$0.CenterBox>(1, _omitFieldNames ? '' : 'box',
|
||||
subBuilder: $0.CenterBox.create)
|
||||
..aOM<$1.EPoint>(2, _omitFieldNames ? '' : 'landmarks',
|
||||
subBuilder: $1.EPoint.create)
|
||||
..hasRequiredFields = false;
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Detection', package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.ml'), createEmptyInstance: create)
|
||||
..aOM<$0.CenterBox>(1, _omitFieldNames ? '' : 'box', subBuilder: $0.CenterBox.create)
|
||||
..aOM<$1.EPoint>(2, _omitFieldNames ? '' : 'landmarks', subBuilder: $1.EPoint.create)
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
|
||||
@$core.Deprecated('Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
Detection clone() => Detection()..mergeFromMessage(this);
|
||||
@$core.Deprecated('Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
Detection copyWith(void Function(Detection) updates) =>
|
||||
super.copyWith((message) => updates(message as Detection)) as Detection;
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
Detection copyWith(void Function(Detection) updates) => super.copyWith((message) => updates(message as Detection)) as Detection;
|
||||
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@@ -65,17 +58,13 @@ class Detection extends $pb.GeneratedMessage {
|
||||
Detection createEmptyInstance() => create();
|
||||
static $pb.PbList<Detection> createRepeated() => $pb.PbList<Detection>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static Detection getDefault() =>
|
||||
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Detection>(create);
|
||||
static Detection getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Detection>(create);
|
||||
static Detection? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$0.CenterBox get box => $_getN(0);
|
||||
@$pb.TagNumber(1)
|
||||
set box($0.CenterBox v) {
|
||||
setField(1, v);
|
||||
}
|
||||
|
||||
set box($0.CenterBox v) { setField(1, v); }
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasBox() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
@@ -86,10 +75,7 @@ class Detection extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(2)
|
||||
$1.EPoint get landmarks => $_getN(1);
|
||||
@$pb.TagNumber(2)
|
||||
set landmarks($1.EPoint v) {
|
||||
setField(2, v);
|
||||
}
|
||||
|
||||
set landmarks($1.EPoint v) { setField(2, v); }
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasLandmarks() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
@@ -117,33 +103,26 @@ class Face extends $pb.GeneratedMessage {
|
||||
return $result;
|
||||
}
|
||||
Face._() : super();
|
||||
factory Face.fromBuffer($core.List<$core.int> i,
|
||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(i, r);
|
||||
factory Face.fromJson($core.String i,
|
||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(i, r);
|
||||
factory Face.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory Face.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'Face',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.ml'),
|
||||
createEmptyInstance: create)
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Face', package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.ml'), createEmptyInstance: create)
|
||||
..aOS(1, _omitFieldNames ? '' : 'id')
|
||||
..aOM<Detection>(2, _omitFieldNames ? '' : 'detection',
|
||||
subBuilder: Detection.create)
|
||||
..a<$core.double>(
|
||||
3, _omitFieldNames ? '' : 'confidence', $pb.PbFieldType.OF)
|
||||
..hasRequiredFields = false;
|
||||
..aOM<Detection>(2, _omitFieldNames ? '' : 'detection', subBuilder: Detection.create)
|
||||
..a<$core.double>(3, _omitFieldNames ? '' : 'confidence', $pb.PbFieldType.OF)
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
|
||||
@$core.Deprecated('Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
Face clone() => Face()..mergeFromMessage(this);
|
||||
@$core.Deprecated('Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
Face copyWith(void Function(Face) updates) =>
|
||||
super.copyWith((message) => updates(message as Face)) as Face;
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
Face copyWith(void Function(Face) updates) => super.copyWith((message) => updates(message as Face)) as Face;
|
||||
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@@ -152,17 +131,13 @@ class Face extends $pb.GeneratedMessage {
|
||||
Face createEmptyInstance() => create();
|
||||
static $pb.PbList<Face> createRepeated() => $pb.PbList<Face>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static Face getDefault() =>
|
||||
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Face>(create);
|
||||
static Face getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Face>(create);
|
||||
static Face? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get id => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set id($core.String v) {
|
||||
$_setString(0, v);
|
||||
}
|
||||
|
||||
set id($core.String v) { $_setString(0, v); }
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasId() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
@@ -171,10 +146,7 @@ class Face extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(2)
|
||||
Detection get detection => $_getN(1);
|
||||
@$pb.TagNumber(2)
|
||||
set detection(Detection v) {
|
||||
setField(2, v);
|
||||
}
|
||||
|
||||
set detection(Detection v) { setField(2, v); }
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasDetection() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
@@ -185,16 +157,13 @@ class Face extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(3)
|
||||
$core.double get confidence => $_getN(2);
|
||||
@$pb.TagNumber(3)
|
||||
set confidence($core.double v) {
|
||||
$_setFloat(2, v);
|
||||
}
|
||||
|
||||
set confidence($core.double v) { $_setFloat(2, v); }
|
||||
@$pb.TagNumber(3)
|
||||
$core.bool hasConfidence() => $_has(2);
|
||||
@$pb.TagNumber(3)
|
||||
void clearConfidence() => clearField(3);
|
||||
}
|
||||
|
||||
|
||||
const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
|
||||
const _omitMessageNames =
|
||||
$core.bool.fromEnvironment('protobuf.omit_message_names');
|
||||
const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
|
||||
|
||||
@@ -8,3 +8,4 @@
|
||||
// ignore_for_file: constant_identifier_names, library_prefixes
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
|
||||
|
||||
@@ -17,26 +17,8 @@ import 'dart:typed_data' as $typed_data;
|
||||
const Detection$json = {
|
||||
'1': 'Detection',
|
||||
'2': [
|
||||
{
|
||||
'1': 'box',
|
||||
'3': 1,
|
||||
'4': 1,
|
||||
'5': 11,
|
||||
'6': '.ente.common.CenterBox',
|
||||
'9': 0,
|
||||
'10': 'box',
|
||||
'17': true
|
||||
},
|
||||
{
|
||||
'1': 'landmarks',
|
||||
'3': 2,
|
||||
'4': 1,
|
||||
'5': 11,
|
||||
'6': '.ente.common.EPoint',
|
||||
'9': 1,
|
||||
'10': 'landmarks',
|
||||
'17': true
|
||||
},
|
||||
{'1': 'box', '3': 1, '4': 1, '5': 11, '6': '.ente.common.CenterBox', '9': 0, '10': 'box', '17': true},
|
||||
{'1': 'landmarks', '3': 2, '4': 1, '5': 11, '6': '.ente.common.EPoint', '9': 1, '10': 'landmarks', '17': true},
|
||||
],
|
||||
'8': [
|
||||
{'1': '_box'},
|
||||
@@ -55,25 +37,8 @@ const Face$json = {
|
||||
'1': 'Face',
|
||||
'2': [
|
||||
{'1': 'id', '3': 1, '4': 1, '5': 9, '9': 0, '10': 'id', '17': true},
|
||||
{
|
||||
'1': 'detection',
|
||||
'3': 2,
|
||||
'4': 1,
|
||||
'5': 11,
|
||||
'6': '.ente.ml.Detection',
|
||||
'9': 1,
|
||||
'10': 'detection',
|
||||
'17': true
|
||||
},
|
||||
{
|
||||
'1': 'confidence',
|
||||
'3': 3,
|
||||
'4': 1,
|
||||
'5': 2,
|
||||
'9': 2,
|
||||
'10': 'confidence',
|
||||
'17': true
|
||||
},
|
||||
{'1': 'detection', '3': 2, '4': 1, '5': 11, '6': '.ente.ml.Detection', '9': 1, '10': 'detection', '17': true},
|
||||
{'1': 'confidence', '3': 3, '4': 1, '5': 2, '9': 2, '10': 'confidence', '17': true},
|
||||
],
|
||||
'8': [
|
||||
{'1': '_id'},
|
||||
@@ -87,3 +52,4 @@ final $typed_data.Uint8List faceDescriptor = $convert.base64Decode(
|
||||
'CgRGYWNlEhMKAmlkGAEgASgJSABSAmlkiAEBEjUKCWRldGVjdGlvbhgCIAEoCzISLmVudGUubW'
|
||||
'wuRGV0ZWN0aW9uSAFSCWRldGVjdGlvbogBARIjCgpjb25maWRlbmNlGAMgASgCSAJSCmNvbmZp'
|
||||
'ZGVuY2WIAQFCBQoDX2lkQgwKCl9kZXRlY3Rpb25CDQoLX2NvbmZpZGVuY2U=');
|
||||
|
||||
|
||||
@@ -11,3 +11,4 @@
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
|
||||
export 'face.pb.dart';
|
||||
|
||||
|
||||
@@ -31,30 +31,25 @@ class FileML extends $pb.GeneratedMessage {
|
||||
return $result;
|
||||
}
|
||||
FileML._() : super();
|
||||
factory FileML.fromBuffer($core.List<$core.int> i,
|
||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(i, r);
|
||||
factory FileML.fromJson($core.String i,
|
||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(i, r);
|
||||
factory FileML.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory FileML.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'FileML',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.ml'),
|
||||
createEmptyInstance: create)
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'FileML', package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.ml'), createEmptyInstance: create)
|
||||
..aInt64(1, _omitFieldNames ? '' : 'id')
|
||||
..p<$core.double>(2, _omitFieldNames ? '' : 'clip', $pb.PbFieldType.KD)
|
||||
..hasRequiredFields = false;
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
|
||||
@$core.Deprecated('Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
FileML clone() => FileML()..mergeFromMessage(this);
|
||||
@$core.Deprecated('Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
FileML copyWith(void Function(FileML) updates) =>
|
||||
super.copyWith((message) => updates(message as FileML)) as FileML;
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
FileML copyWith(void Function(FileML) updates) => super.copyWith((message) => updates(message as FileML)) as FileML;
|
||||
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@@ -63,17 +58,13 @@ class FileML extends $pb.GeneratedMessage {
|
||||
FileML createEmptyInstance() => create();
|
||||
static $pb.PbList<FileML> createRepeated() => $pb.PbList<FileML>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static FileML getDefault() =>
|
||||
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<FileML>(create);
|
||||
static FileML getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<FileML>(create);
|
||||
static FileML? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$fixnum.Int64 get id => $_getI64(0);
|
||||
@$pb.TagNumber(1)
|
||||
set id($fixnum.Int64 v) {
|
||||
$_setInt64(0, v);
|
||||
}
|
||||
|
||||
set id($fixnum.Int64 v) { $_setInt64(0, v); }
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasId() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
@@ -110,34 +101,28 @@ class FileFaces extends $pb.GeneratedMessage {
|
||||
return $result;
|
||||
}
|
||||
FileFaces._() : super();
|
||||
factory FileFaces.fromBuffer($core.List<$core.int> i,
|
||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(i, r);
|
||||
factory FileFaces.fromJson($core.String i,
|
||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(i, r);
|
||||
factory FileFaces.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory FileFaces.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'FileFaces',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.ml'),
|
||||
createEmptyInstance: create)
|
||||
..pc<$2.Face>(1, _omitFieldNames ? '' : 'faces', $pb.PbFieldType.PM,
|
||||
subBuilder: $2.Face.create)
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'FileFaces', package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.ml'), createEmptyInstance: create)
|
||||
..pc<$2.Face>(1, _omitFieldNames ? '' : 'faces', $pb.PbFieldType.PM, subBuilder: $2.Face.create)
|
||||
..a<$core.int>(2, _omitFieldNames ? '' : 'height', $pb.PbFieldType.O3)
|
||||
..a<$core.int>(3, _omitFieldNames ? '' : 'width', $pb.PbFieldType.O3)
|
||||
..a<$core.int>(4, _omitFieldNames ? '' : 'version', $pb.PbFieldType.O3)
|
||||
..aOS(5, _omitFieldNames ? '' : 'error')
|
||||
..hasRequiredFields = false;
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
|
||||
@$core.Deprecated('Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
FileFaces clone() => FileFaces()..mergeFromMessage(this);
|
||||
@$core.Deprecated('Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
FileFaces copyWith(void Function(FileFaces) updates) =>
|
||||
super.copyWith((message) => updates(message as FileFaces)) as FileFaces;
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
FileFaces copyWith(void Function(FileFaces) updates) => super.copyWith((message) => updates(message as FileFaces)) as FileFaces;
|
||||
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@@ -146,8 +131,7 @@ class FileFaces extends $pb.GeneratedMessage {
|
||||
FileFaces createEmptyInstance() => create();
|
||||
static $pb.PbList<FileFaces> createRepeated() => $pb.PbList<FileFaces>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static FileFaces getDefault() =>
|
||||
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<FileFaces>(create);
|
||||
static FileFaces getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<FileFaces>(create);
|
||||
static FileFaces? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
@@ -156,10 +140,7 @@ class FileFaces extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(2)
|
||||
$core.int get height => $_getIZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
set height($core.int v) {
|
||||
$_setSignedInt32(1, v);
|
||||
}
|
||||
|
||||
set height($core.int v) { $_setSignedInt32(1, v); }
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasHeight() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
@@ -168,10 +149,7 @@ class FileFaces extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(3)
|
||||
$core.int get width => $_getIZ(2);
|
||||
@$pb.TagNumber(3)
|
||||
set width($core.int v) {
|
||||
$_setSignedInt32(2, v);
|
||||
}
|
||||
|
||||
set width($core.int v) { $_setSignedInt32(2, v); }
|
||||
@$pb.TagNumber(3)
|
||||
$core.bool hasWidth() => $_has(2);
|
||||
@$pb.TagNumber(3)
|
||||
@@ -180,10 +158,7 @@ class FileFaces extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(4)
|
||||
$core.int get version => $_getIZ(3);
|
||||
@$pb.TagNumber(4)
|
||||
set version($core.int v) {
|
||||
$_setSignedInt32(3, v);
|
||||
}
|
||||
|
||||
set version($core.int v) { $_setSignedInt32(3, v); }
|
||||
@$pb.TagNumber(4)
|
||||
$core.bool hasVersion() => $_has(3);
|
||||
@$pb.TagNumber(4)
|
||||
@@ -192,16 +167,13 @@ class FileFaces extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(5)
|
||||
$core.String get error => $_getSZ(4);
|
||||
@$pb.TagNumber(5)
|
||||
set error($core.String v) {
|
||||
$_setString(4, v);
|
||||
}
|
||||
|
||||
set error($core.String v) { $_setString(4, v); }
|
||||
@$pb.TagNumber(5)
|
||||
$core.bool hasError() => $_has(4);
|
||||
@$pb.TagNumber(5)
|
||||
void clearError() => clearField(5);
|
||||
}
|
||||
|
||||
|
||||
const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
|
||||
const _omitMessageNames =
|
||||
$core.bool.fromEnvironment('protobuf.omit_message_names');
|
||||
const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
|
||||
|
||||
@@ -8,3 +8,4 @@
|
||||
// ignore_for_file: constant_identifier_names, library_prefixes
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
|
||||
|
||||
@@ -34,25 +34,10 @@ final $typed_data.Uint8List fileMLDescriptor = $convert.base64Decode(
|
||||
const FileFaces$json = {
|
||||
'1': 'FileFaces',
|
||||
'2': [
|
||||
{
|
||||
'1': 'faces',
|
||||
'3': 1,
|
||||
'4': 3,
|
||||
'5': 11,
|
||||
'6': '.ente.ml.Face',
|
||||
'10': 'faces'
|
||||
},
|
||||
{'1': 'faces', '3': 1, '4': 3, '5': 11, '6': '.ente.ml.Face', '10': 'faces'},
|
||||
{'1': 'height', '3': 2, '4': 1, '5': 5, '9': 0, '10': 'height', '17': true},
|
||||
{'1': 'width', '3': 3, '4': 1, '5': 5, '9': 1, '10': 'width', '17': true},
|
||||
{
|
||||
'1': 'version',
|
||||
'3': 4,
|
||||
'4': 1,
|
||||
'5': 5,
|
||||
'9': 2,
|
||||
'10': 'version',
|
||||
'17': true
|
||||
},
|
||||
{'1': 'version', '3': 4, '4': 1, '5': 5, '9': 2, '10': 'version', '17': true},
|
||||
{'1': 'error', '3': 5, '4': 1, '5': 9, '9': 3, '10': 'error', '17': true},
|
||||
],
|
||||
'8': [
|
||||
@@ -69,3 +54,4 @@ final $typed_data.Uint8List fileFacesDescriptor = $convert.base64Decode(
|
||||
'dodBgCIAEoBUgAUgZoZWlnaHSIAQESGQoFd2lkdGgYAyABKAVIAVIFd2lkdGiIAQESHQoHdmVy'
|
||||
'c2lvbhgEIAEoBUgCUgd2ZXJzaW9uiAEBEhkKBWVycm9yGAUgASgJSANSBWVycm9yiAEBQgkKB1'
|
||||
'9oZWlnaHRCCAoGX3dpZHRoQgoKCF92ZXJzaW9uQggKBl9lcnJvcg==');
|
||||
|
||||
|
||||
@@ -11,3 +11,4 @@
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
|
||||
export 'fileml.pb.dart';
|
||||
|
||||
|
||||
@@ -1602,6 +1602,7 @@
|
||||
"processing": "Przetwarzanie",
|
||||
"queued": "W kolejce",
|
||||
"ineligible": "Nie kwalifikuje się",
|
||||
"failed": "Nie powiodło się",
|
||||
"playOriginal": "Odtwórz oryginał",
|
||||
"joinAlbumConfirmationDialogBody": "Dołączenie do albumu sprawi, że Twój e-mail będzie widoczny dla jego uczestników.",
|
||||
"pleaseWaitThisWillTakeAWhile": "Prosimy czekać, to może zająć chwilę.",
|
||||
@@ -1621,6 +1622,7 @@
|
||||
"appIcon": "Ikona aplikacji",
|
||||
"notThisPerson": "Nie ta osoba?",
|
||||
"selectedItemsWillBeRemovedFromThisPerson": "Wybrane elementy zostaną usunięte z tej osoby, ale nie zostaną usunięte z Twojej biblioteki.",
|
||||
"throughTheYears": "{dateFormat} przez lata",
|
||||
"thisWeekThroughTheYears": "Ten tydzień przez lata",
|
||||
"youAndThem": "Ty i {name}",
|
||||
"admiringThem": "Podziwianie {name}",
|
||||
@@ -1705,5 +1707,7 @@
|
||||
"cLDesc5": "Od teraz otrzymasz powiadomienie z możliwością rezygnacji dotyczące wszystkich zapisanych urodzin w Ente, wraz z kolekcją najlepszych zdjęć danej osoby.",
|
||||
"cLTitle6": "Wznawialne Przesyłanie i Pobieranie Danych",
|
||||
"cLDesc6": "Nie musisz już czekać na zakończenie przesyłania ani pobierania, żeby móc zamknąć aplikację. Wszystkie operacje przesyłania i pobierania można teraz wstrzymać w dowolnym momencie i wznowić od miejsca, w którym zostały przerwane.",
|
||||
"indexingPausedStatusDescription": "Indeksowanie zostało wstrzymane. Zostanie automatycznie wznowione, gdy urządzenie będzie gotowe. Urządzenie uznaje się za gotowe, gdy poziom baterii, stan jej zdrowia oraz status termiczny znajdują się w bezpiecznym zakresie."
|
||||
"indexingPausedStatusDescription": "Indeksowanie zostało wstrzymane. Zostanie automatycznie wznowione, gdy urządzenie będzie gotowe. Urządzenie uznaje się za gotowe, gdy poziom baterii, stan jej zdrowia oraz status termiczny znajdują się w bezpiecznym zakresie.",
|
||||
"faceThumbnailGenerationFailed": "Nie można wygenerować miniaturek twarzy",
|
||||
"fileAnalysisFailed": "Nie można przeanalizować pliku"
|
||||
}
|
||||
@@ -1788,5 +1788,7 @@
|
||||
"cLDesc5": "Теперь вы будете получать уведомления о всех днях рождениях, которые вы сохранили на Ente, а также коллекцию их лучших фотографий.",
|
||||
"cLTitle6": "Возобновляемые загрузки и скачивания",
|
||||
"cLDesc6": "Больше не нужно ждать завершения загрузки/скачивания, прежде чем закрыть приложение. Все загрузки и скачивания теперь можно приостановить и возобновить с того места, где вы остановились.",
|
||||
"indexingPausedStatusDescription": "Индексирование приостановлено. Оно автоматически возобновится, когда устройство будет готово. Устройство считается готовым, когда уровень заряда батареи, её состояние и температура находятся в пределах нормы."
|
||||
"indexingPausedStatusDescription": "Индексирование приостановлено. Оно автоматически возобновится, когда устройство будет готово. Устройство считается готовым, когда уровень заряда батареи, её состояние и температура находятся в пределах нормы.",
|
||||
"faceThumbnailGenerationFailed": "Не удалось создать миниатюры лиц",
|
||||
"fileAnalysisFailed": "Не удалось проанализировать файл"
|
||||
}
|
||||
@@ -825,8 +825,8 @@
|
||||
"doubleYourStorage": "Gấp đôi dung lượng lưu trữ của bạn",
|
||||
"referFriendsAnd2xYourPlan": "Giới thiệu bạn bè và ×2 gói của bạn",
|
||||
"shareAlbumHint": "Mở album và nhấn nút chia sẻ ở góc trên bên phải để chia sẻ.",
|
||||
"itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": "Các mục hiện số ngày còn lại trước khi xóa vĩnh viễn",
|
||||
"trashDaysLeft": "{count, plural, =0 {Sắp tới} =1 {1 ngày} other {{count} ngày}}",
|
||||
"itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": "Trên các mục là số ngày còn lại trước khi xóa vĩnh viễn",
|
||||
"trashDaysLeft": "{count, plural, =0 {Sắp xóa} =1 {1 ngày} other {{count} ngày}}",
|
||||
"@trashDaysLeft": {
|
||||
"description": "Text to indicate number of days remaining before permanent deletion",
|
||||
"placeholders": {
|
||||
@@ -1178,7 +1178,7 @@
|
||||
"addPhotos": "Thêm ảnh",
|
||||
"noPhotosFoundHere": "Không tìm thấy ảnh ở đây",
|
||||
"zoomOutToSeePhotos": "Phóng to để xem ảnh",
|
||||
"noImagesWithLocation": "Không có ảnh ở vị trí này",
|
||||
"noImagesWithLocation": "Không có ảnh với vị trí",
|
||||
"unpinAlbum": "Bỏ ghim album",
|
||||
"pinAlbum": "Ghim album",
|
||||
"create": "Tạo",
|
||||
|
||||
@@ -1788,5 +1788,7 @@
|
||||
"cLDesc5": "您现在将收到 Ente 上保存的所有生日的可选退出通知,同时附上他们最佳照片的合集。",
|
||||
"cLTitle6": "可恢复的上传和下载",
|
||||
"cLDesc6": "无需等待上传/下载完成即可关闭应用程序。所有上传和下载现在都可以中途暂停,并从中断处继续。",
|
||||
"indexingPausedStatusDescription": "索引已暂停。待设备准备就绪后,索引将自动恢复。当设备的电池电量、电池健康度和温度状态处于健康范围内时,设备即被视为准备就绪。"
|
||||
"indexingPausedStatusDescription": "索引已暂停。待设备准备就绪后,索引将自动恢复。当设备的电池电量、电池健康度和温度状态处于健康范围内时,设备即被视为准备就绪。",
|
||||
"faceThumbnailGenerationFailed": "无法生成人脸缩略图",
|
||||
"fileAnalysisFailed": "无法分析文件"
|
||||
}
|
||||
@@ -43,7 +43,6 @@ import 'package:photos/services/sync/remote_sync_service.dart';
|
||||
import "package:photos/services/sync/sync_service.dart";
|
||||
import "package:photos/services/video_preview_service.dart";
|
||||
import "package:photos/services/wake_lock_service.dart";
|
||||
import "package:photos/src/rust/frb_generated.dart";
|
||||
import 'package:photos/ui/tools/app_lock.dart';
|
||||
import 'package:photos/ui/tools/lock_screen.dart';
|
||||
import "package:photos/utils/email_util.dart";
|
||||
@@ -64,7 +63,6 @@ const kFGTaskDeathTimeoutInMicroseconds = 5000000;
|
||||
|
||||
void main() async {
|
||||
debugRepaintRainbowEnabled = false;
|
||||
await RustLib.init();
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
MediaKit.ensureInitialized();
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ class SetupSRPRequest {
|
||||
final String srpA;
|
||||
final bool isUpdate;
|
||||
|
||||
|
||||
SetupSRPRequest({
|
||||
required this.srpUserID,
|
||||
required this.srpSalt,
|
||||
@@ -81,7 +82,6 @@ class CompleteSRPSetupRequest {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SrpAttributes {
|
||||
final String srpUserID;
|
||||
final String srpSalt;
|
||||
|
||||
@@ -507,8 +507,7 @@ ClusteringResult _runCompleteClustering(Map args) {
|
||||
EVector.fromBuffer(entry.value).values,
|
||||
dtype: DType.float32,
|
||||
),
|
||||
fileCreationTime:
|
||||
fileIDToCreationTime?[getFileIdFromFaceId<int>(entry.key)],
|
||||
fileCreationTime: fileIDToCreationTime?[getFileIdFromFaceId<int>(entry.key)],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
const imageEmbeddingsKey = "imageEmbeddings";
|
||||
const imageEmbeddingsKey = "imageEmbeddings";
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
class GeneralFaceMlException implements Exception {
|
||||
final String message;
|
||||
|
||||
@@ -25,4 +26,4 @@ class CouldNotRunFaceDetector implements Exception {}
|
||||
|
||||
class CouldNotWarpAffine implements Exception {}
|
||||
|
||||
class CouldNotRunFaceEmbeddor implements Exception {}
|
||||
class CouldNotRunFaceEmbeddor implements Exception {}
|
||||
@@ -3,4 +3,4 @@ class QueryResult {
|
||||
final double score;
|
||||
|
||||
QueryResult(this.id, this.score);
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import "package:logging/logging.dart";
|
||||
import "package:photos/core/cache/lru_map.dart";
|
||||
import "package:photos/core/event_bus.dart";
|
||||
import "package:photos/db/files_db.dart";
|
||||
import "package:photos/db/ml/clip_vector_db.dart";
|
||||
import "package:photos/db/ml/db.dart";
|
||||
import 'package:photos/events/embedding_updated_event.dart';
|
||||
import "package:photos/models/file/file.dart";
|
||||
@@ -266,25 +265,10 @@ class SemanticSearchService {
|
||||
required Map<String, double> minimumSimilarityMap,
|
||||
}) async {
|
||||
final startTime = DateTime.now();
|
||||
if (kDebugMode) {
|
||||
for (final queryText in textQueryToEmbeddingMap.keys) {
|
||||
final embedding = textQueryToEmbeddingMap[queryText]!;
|
||||
dev.log("CLIPTEXT Query: $queryText, embedding: $embedding");
|
||||
}
|
||||
}
|
||||
late final Map<String, List<QueryResult>> queryResults;
|
||||
if (flagService.enableVectorDb) {
|
||||
queryResults = await ClipVectorDB.instance.computeBulkSimilarities(
|
||||
textQueryToEmbeddingMap,
|
||||
minimumSimilarityMap,
|
||||
);
|
||||
} else {
|
||||
await _cacheClipVectors();
|
||||
queryResults = await MLComputer.instance.computeBulkSimilarities(
|
||||
textQueryToEmbeddingMap,
|
||||
minimumSimilarityMap,
|
||||
);
|
||||
}
|
||||
await _cacheClipVectors();
|
||||
final Map<String, List<QueryResult>> queryResults = await MLComputer
|
||||
.instance
|
||||
.computeBulkSimilarities(textQueryToEmbeddingMap, minimumSimilarityMap);
|
||||
final endTime = DateTime.now();
|
||||
_logger.info(
|
||||
"computingSimilarities took for ${textQueryToEmbeddingMap.length} queries " +
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
// This file is automatically generated, so please do not edit it.
|
||||
// @generated by `flutter_rust_bridge`@ 2.11.1.
|
||||
|
||||
// ignore_for_file: require_trailing_commas
|
||||
|
||||
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
|
||||
|
||||
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
|
||||
import 'package:photos/src/rust/frb_generated.dart';
|
||||
|
||||
String greet({required String name}) =>
|
||||
RustLib.instance.api.crateApiSimpleGreet(name: name);
|
||||
@@ -1,48 +0,0 @@
|
||||
// This file is automatically generated, so please do not edit it.
|
||||
// @generated by `flutter_rust_bridge`@ 2.11.1.
|
||||
|
||||
// ignore_for_file: require_trailing_commas
|
||||
|
||||
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
|
||||
|
||||
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
|
||||
import 'package:photos/src/rust/frb_generated.dart';
|
||||
|
||||
// These functions are ignored because they are not marked as `pub`: `ensure_capacity`, `save_index`
|
||||
|
||||
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<VectorDB>>
|
||||
abstract class VectorDb implements RustOpaqueInterface {
|
||||
Future<void> addVector({required BigInt key, required List<double> vector});
|
||||
|
||||
Future<void> bulkAddVectors(
|
||||
{required Uint64List keys, required List<Float32List> vectors});
|
||||
|
||||
Future<List<Float32List>> bulkGetVectors({required Uint64List keys});
|
||||
|
||||
Future<BigInt> bulkRemoveVectors({required Uint64List keys});
|
||||
|
||||
Future<(List<Uint64List>, List<Float32List>)> bulkSearchVectors(
|
||||
{required List<Float32List> queries, required BigInt count});
|
||||
|
||||
/// Check if a vector with the given key exists in the index.
|
||||
/// `true` if the index contains the vector with the given key, `false` otherwise.
|
||||
Future<bool> containsVector({required BigInt key});
|
||||
|
||||
Future<void> deleteIndex();
|
||||
|
||||
Future<(BigInt, BigInt, BigInt, BigInt, BigInt, BigInt, BigInt)>
|
||||
getIndexStats();
|
||||
|
||||
Future<Float32List> getVector({required BigInt key});
|
||||
|
||||
factory VectorDb({required String filePath, required BigInt dimensions}) =>
|
||||
RustLib.instance.api.crateApiUsearchApiVectorDbNew(
|
||||
filePath: filePath, dimensions: dimensions);
|
||||
|
||||
Future<BigInt> removeVector({required BigInt key});
|
||||
|
||||
Future<void> resetIndex();
|
||||
|
||||
Future<(Uint64List, Float32List)> searchVectors(
|
||||
{required List<double> query, required BigInt count});
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,293 +0,0 @@
|
||||
// This file is automatically generated, so please do not edit it.
|
||||
// @generated by `flutter_rust_bridge`@ 2.11.1.
|
||||
|
||||
// ignore_for_file: require_trailing_commas
|
||||
|
||||
// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:ffi' as ffi;
|
||||
|
||||
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart';
|
||||
import 'package:photos/src/rust/api/simple.dart';
|
||||
import 'package:photos/src/rust/api/usearch_api.dart';
|
||||
import 'package:photos/src/rust/frb_generated.dart';
|
||||
|
||||
abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
RustLibApiImplPlatform({
|
||||
required super.handler,
|
||||
required super.wire,
|
||||
required super.generalizedFrbRustBinding,
|
||||
required super.portManager,
|
||||
});
|
||||
|
||||
CrossPlatformFinalizerArg get rust_arc_decrement_strong_count_VectorDbPtr => wire
|
||||
._rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDBPtr;
|
||||
|
||||
@protected
|
||||
VectorDb
|
||||
dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB(
|
||||
dynamic raw);
|
||||
|
||||
@protected
|
||||
VectorDb
|
||||
dco_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB(
|
||||
dynamic raw);
|
||||
|
||||
@protected
|
||||
VectorDb
|
||||
dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB(
|
||||
dynamic raw);
|
||||
|
||||
@protected
|
||||
String dco_decode_String(dynamic raw);
|
||||
|
||||
@protected
|
||||
bool dco_decode_bool(dynamic raw);
|
||||
|
||||
@protected
|
||||
double dco_decode_f_32(dynamic raw);
|
||||
|
||||
@protected
|
||||
List<Float32List> dco_decode_list_list_prim_f_32_strict(dynamic raw);
|
||||
|
||||
@protected
|
||||
List<Uint64List> dco_decode_list_list_prim_u_64_strict(dynamic raw);
|
||||
|
||||
@protected
|
||||
List<double> dco_decode_list_prim_f_32_loose(dynamic raw);
|
||||
|
||||
@protected
|
||||
Float32List dco_decode_list_prim_f_32_strict(dynamic raw);
|
||||
|
||||
@protected
|
||||
Uint64List dco_decode_list_prim_u_64_strict(dynamic raw);
|
||||
|
||||
@protected
|
||||
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
|
||||
|
||||
@protected
|
||||
(List<Uint64List>, List<Float32List>)
|
||||
dco_decode_record_list_list_prim_u_64_strict_list_list_prim_f_32_strict(
|
||||
dynamic raw);
|
||||
|
||||
@protected
|
||||
(
|
||||
Uint64List,
|
||||
Float32List
|
||||
) dco_decode_record_list_prim_u_64_strict_list_prim_f_32_strict(dynamic raw);
|
||||
|
||||
@protected
|
||||
(BigInt, BigInt, BigInt, BigInt, BigInt, BigInt, BigInt)
|
||||
dco_decode_record_usize_usize_usize_usize_usize_usize_usize(dynamic raw);
|
||||
|
||||
@protected
|
||||
BigInt dco_decode_u_64(dynamic raw);
|
||||
|
||||
@protected
|
||||
int dco_decode_u_8(dynamic raw);
|
||||
|
||||
@protected
|
||||
void dco_decode_unit(dynamic raw);
|
||||
|
||||
@protected
|
||||
BigInt dco_decode_usize(dynamic raw);
|
||||
|
||||
@protected
|
||||
VectorDb
|
||||
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB(
|
||||
SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
VectorDb
|
||||
sse_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB(
|
||||
SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
VectorDb
|
||||
sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB(
|
||||
SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
String sse_decode_String(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
bool sse_decode_bool(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
double sse_decode_f_32(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
List<Float32List> sse_decode_list_list_prim_f_32_strict(
|
||||
SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
List<Uint64List> sse_decode_list_list_prim_u_64_strict(
|
||||
SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
List<double> sse_decode_list_prim_f_32_loose(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
Float32List sse_decode_list_prim_f_32_strict(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
Uint64List sse_decode_list_prim_u_64_strict(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
(List<Uint64List>, List<Float32List>)
|
||||
sse_decode_record_list_list_prim_u_64_strict_list_list_prim_f_32_strict(
|
||||
SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
(Uint64List, Float32List)
|
||||
sse_decode_record_list_prim_u_64_strict_list_prim_f_32_strict(
|
||||
SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
(BigInt, BigInt, BigInt, BigInt, BigInt, BigInt, BigInt)
|
||||
sse_decode_record_usize_usize_usize_usize_usize_usize_usize(
|
||||
SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
BigInt sse_decode_u_64(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
int sse_decode_u_8(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
void sse_decode_unit(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
BigInt sse_decode_usize(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
int sse_decode_i_32(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
void
|
||||
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB(
|
||||
VectorDb self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB(
|
||||
VectorDb self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void
|
||||
sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB(
|
||||
VectorDb self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_String(String self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_bool(bool self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_f_32(double self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_list_list_prim_f_32_strict(
|
||||
List<Float32List> self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_list_list_prim_u_64_strict(
|
||||
List<Uint64List> self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_list_prim_f_32_loose(
|
||||
List<double> self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_list_prim_f_32_strict(
|
||||
Float32List self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_list_prim_u_64_strict(
|
||||
Uint64List self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_list_prim_u_8_strict(
|
||||
Uint8List self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_record_list_list_prim_u_64_strict_list_list_prim_f_32_strict(
|
||||
(List<Uint64List>, List<Float32List>) self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_record_list_prim_u_64_strict_list_prim_f_32_strict(
|
||||
(Uint64List, Float32List) self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_record_usize_usize_usize_usize_usize_usize_usize(
|
||||
(BigInt, BigInt, BigInt, BigInt, BigInt, BigInt, BigInt) self,
|
||||
SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_u_64(BigInt self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_u_8(int self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_unit(void self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_usize(BigInt self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_i_32(int self, SseSerializer serializer);
|
||||
}
|
||||
|
||||
// Section: wire_class
|
||||
|
||||
class RustLibWire implements BaseWire {
|
||||
factory RustLibWire.fromExternalLibrary(ExternalLibrary lib) =>
|
||||
RustLibWire(lib.ffiDynamicLibrary);
|
||||
|
||||
/// Holds the symbol lookup function.
|
||||
final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
|
||||
_lookup;
|
||||
|
||||
/// The symbols are looked up in [dynamicLibrary].
|
||||
RustLibWire(ffi.DynamicLibrary dynamicLibrary)
|
||||
: _lookup = dynamicLibrary.lookup;
|
||||
|
||||
void
|
||||
rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB(
|
||||
ffi.Pointer<ffi.Void> ptr,
|
||||
) {
|
||||
return _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB(
|
||||
ptr,
|
||||
);
|
||||
}
|
||||
|
||||
late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDBPtr =
|
||||
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
|
||||
'frbgen_photos_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB');
|
||||
late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB =
|
||||
_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDBPtr
|
||||
.asFunction<void Function(ffi.Pointer<ffi.Void>)>();
|
||||
|
||||
void
|
||||
rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB(
|
||||
ffi.Pointer<ffi.Void> ptr,
|
||||
) {
|
||||
return _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB(
|
||||
ptr,
|
||||
);
|
||||
}
|
||||
|
||||
late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDBPtr =
|
||||
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
|
||||
'frbgen_photos_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB');
|
||||
late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB =
|
||||
_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDBPtr
|
||||
.asFunction<void Function(ffi.Pointer<ffi.Void>)>();
|
||||
}
|
||||
@@ -18,9 +18,8 @@ class BottomOfTitleBarWidget extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: showCloseButton
|
||||
? MainAxisAlignment.spaceBetween
|
||||
: MainAxisAlignment.start,
|
||||
mainAxisAlignment: showCloseButton ? MainAxisAlignment.spaceBetween :
|
||||
MainAxisAlignment.start,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Padding(
|
||||
|
||||
@@ -100,7 +100,7 @@ class ExtentsPageView extends StatefulWidget {
|
||||
int? itemCount,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
this.openDrawer,
|
||||
}) : childrenDelegate = SliverChildBuilderDelegate(
|
||||
}) : childrenDelegate = SliverChildBuilderDelegate(
|
||||
itemBuilder,
|
||||
childCount: itemCount,
|
||||
addAutomaticKeepAlives: false,
|
||||
@@ -198,7 +198,7 @@ class ExtentsPageView extends StatefulWidget {
|
||||
required this.childrenDelegate,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
this.openDrawer,
|
||||
}) : extents = 0;
|
||||
}) : extents = 0;
|
||||
|
||||
/// The number of pages to build off screen.
|
||||
///
|
||||
|
||||
@@ -9,7 +9,8 @@ import "package:photos/utils/navigation_util.dart";
|
||||
class HeaderErrorWidget extends StatelessWidget {
|
||||
final Error? _error;
|
||||
|
||||
const HeaderErrorWidget({super.key, required Error? error}) : _error = error;
|
||||
const HeaderErrorWidget({super.key, required Error? error})
|
||||
: _error = error;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
@@ -1,20 +1,11 @@
|
||||
import "dart:async";
|
||||
import "dart:math" show Random;
|
||||
import "dart:typed_data" show Float32List;
|
||||
|
||||
import "package:flutter/foundation.dart" show kDebugMode;
|
||||
import 'package:flutter/material.dart';
|
||||
import "package:flutter_rust_bridge/flutter_rust_bridge.dart";
|
||||
import "package:logging/logging.dart";
|
||||
import "package:ml_linalg/linalg.dart";
|
||||
import "package:path_provider/path_provider.dart";
|
||||
import "package:photos/core/constants.dart";
|
||||
import "package:photos/core/event_bus.dart";
|
||||
import "package:photos/db/ml/clip_vector_db.dart";
|
||||
import "package:photos/db/ml/db.dart";
|
||||
import "package:photos/events/people_changed_event.dart";
|
||||
import "package:photos/extensions/stop_watch.dart";
|
||||
import "package:photos/generated/protos/ente/common/vector.pb.dart";
|
||||
import "package:photos/models/ml/face/person.dart";
|
||||
import "package:photos/models/search/generic_search_result.dart";
|
||||
import "package:photos/service_locator.dart";
|
||||
@@ -24,8 +15,6 @@ import 'package:photos/services/machine_learning/ml_service.dart';
|
||||
import "package:photos/services/machine_learning/semantic_search/semantic_search_service.dart";
|
||||
import "package:photos/services/notification_service.dart";
|
||||
import "package:photos/services/search_service.dart";
|
||||
import "package:photos/src/rust/api/simple.dart";
|
||||
import "package:photos/src/rust/api/usearch_api.dart";
|
||||
import 'package:photos/theme/ente_theme.dart';
|
||||
import 'package:photos/ui/components/captioned_text_widget.dart';
|
||||
import 'package:photos/ui/components/expandable_menu_item_widget.dart';
|
||||
@@ -195,380 +184,6 @@ class _MLDebugSectionWidgetState extends State<MLDebugSectionWidget> {
|
||||
},
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Do some basic usearch",
|
||||
),
|
||||
pressedColor: getEnteColorScheme(context).fillFaint,
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
try {
|
||||
// randomly generate some vectors and keys
|
||||
final random = Random();
|
||||
final tenEmbeddings = List.generate(
|
||||
10,
|
||||
(index) {
|
||||
final randomList = List<double>.generate(
|
||||
192,
|
||||
(_) => random.nextDouble(), // Values between 0 and 1
|
||||
);
|
||||
final randomVector = Vector.fromList(randomList).normalize();
|
||||
return Float32List.fromList(randomVector.toList());
|
||||
},
|
||||
);
|
||||
final tenKeys = Uint64List.fromList(
|
||||
List.generate(
|
||||
tenEmbeddings.length,
|
||||
(index) => BigInt.from(index + 1),
|
||||
),
|
||||
);
|
||||
final embedDimensions = BigInt.from(tenEmbeddings.first.length);
|
||||
final indexPath = (await getApplicationSupportDirectory()).path +
|
||||
"/ml/test/vector_db_index.usearch";
|
||||
final rustVectorDB = VectorDb(
|
||||
filePath: indexPath,
|
||||
dimensions: embedDimensions,
|
||||
);
|
||||
await rustVectorDB.resetIndex();
|
||||
final stats = await rustVectorDB.getIndexStats();
|
||||
logger.info("vector_db stats: $stats");
|
||||
await rustVectorDB.bulkAddVectors(
|
||||
keys: tenKeys,
|
||||
vectors: tenEmbeddings,
|
||||
);
|
||||
final statsAgain = await rustVectorDB.getIndexStats();
|
||||
logger.info("vector_db stats again: $statsAgain");
|
||||
final size = statsAgain.$1;
|
||||
final capacity = statsAgain.$2;
|
||||
final dimensions = statsAgain.$3;
|
||||
showShortToast(
|
||||
context,
|
||||
"Size: $size, Capacity: $capacity, Dimensions: $dimensions",
|
||||
);
|
||||
await rustVectorDB.deleteIndex();
|
||||
} catch (e, s) {
|
||||
logger.warning('Rust bridge failed ', e, s);
|
||||
await showGenericErrorDialog(context: context, error: e);
|
||||
}
|
||||
},
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Fill ClipVectorDB",
|
||||
),
|
||||
pressedColor: getEnteColorScheme(context).fillFaint,
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
try {
|
||||
final allClip = await MLDataDB.instance.getAllClipVectors();
|
||||
final allClipSmall = allClip.sublist(0, 15000);
|
||||
showShortToast(context, "Got all embeddings");
|
||||
logger.info("Got all embeddings");
|
||||
|
||||
final clipVectorDB = ClipVectorDB.instance;
|
||||
await clipVectorDB.deleteAllEmbeddings();
|
||||
logger.info("Clean vector DB");
|
||||
final stats = await clipVectorDB.getIndexStats();
|
||||
logger.info(stats.toString());
|
||||
showShortToast(context, stats.toString());
|
||||
|
||||
final fileIDs = allClipSmall.map((e) => e.fileID).toList();
|
||||
final embeddings = allClipSmall
|
||||
.map((e) => Float32List.fromList(e.vector.toList()))
|
||||
.toList();
|
||||
showShortToast(context, "Reshaped embeddings data");
|
||||
logger.info("Reshaped embeddings data");
|
||||
|
||||
final now = DateTime.now();
|
||||
await clipVectorDB.bulkInsertEmbeddings(
|
||||
fileIDs: fileIDs,
|
||||
embeddings: embeddings,
|
||||
);
|
||||
final duration = DateTime.now().difference(now);
|
||||
logger.info(
|
||||
"ClipVectorDB bulk insert took ${duration.inMilliseconds} ms for ${fileIDs.length} embeddings",
|
||||
);
|
||||
final statsAfter = await clipVectorDB.getIndexStats();
|
||||
logger.info(statsAfter.toString());
|
||||
showShortToast(context, statsAfter.toString());
|
||||
} catch (e, s) {
|
||||
logger.warning('ClipVectorDB migration failed ', e, s);
|
||||
await showGenericErrorDialog(context: context, error: e);
|
||||
}
|
||||
},
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Migrate to ClipVectorDB",
|
||||
),
|
||||
pressedColor: getEnteColorScheme(context).fillFaint,
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
try {
|
||||
await MLDataDB.instance.checkMigrateFillClipVectorDB();
|
||||
showShortToast(context, "Migration done!");
|
||||
} catch (e, s) {
|
||||
logger.warning('ClipVectorDB migration failed ', e, s);
|
||||
await showGenericErrorDialog(context: context, error: e);
|
||||
}
|
||||
},
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Show ClipVectorDB stats",
|
||||
),
|
||||
pressedColor: getEnteColorScheme(context).fillFaint,
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
try {
|
||||
final clipVectorDB = ClipVectorDB.instance;
|
||||
final stats = await clipVectorDB.getIndexStats();
|
||||
logger.info(stats.toString());
|
||||
showShortToast(context, stats.toString());
|
||||
} catch (e, s) {
|
||||
logger.warning('ClipVectorDB stats failed ', e, s);
|
||||
await showGenericErrorDialog(context: context, error: e);
|
||||
}
|
||||
},
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Delete/Empty ClipVectorDB",
|
||||
),
|
||||
pressedColor: getEnteColorScheme(context).fillFaint,
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
try {
|
||||
final clipVectorDB = ClipVectorDB.instance;
|
||||
await clipVectorDB.deleteIndex();
|
||||
} catch (e, s) {
|
||||
logger.warning('ClipVectorDB cleanup failed ', e, s);
|
||||
await showGenericErrorDialog(context: context, error: e);
|
||||
}
|
||||
},
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Benchmark Vector DB Face",
|
||||
),
|
||||
pressedColor: getEnteColorScheme(context).fillFaint,
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
try {
|
||||
final w = (kDebugMode ? EnteWatch('MLDebugSectionWidget') : null)
|
||||
?..start();
|
||||
final persons = await PersonService.instance.getPersons();
|
||||
w?.log('get all persons for ${persons.length} persons');
|
||||
String laurensID = '';
|
||||
for (final person in persons) {
|
||||
if (person.data.name.toLowerCase().contains('laurens')) {
|
||||
laurensID = person.remoteID;
|
||||
}
|
||||
}
|
||||
if (laurensID.isEmpty) {
|
||||
throw Exception('Laurens not found');
|
||||
}
|
||||
final laurensFaceIDs =
|
||||
await MLDataDB.instance.getFaceIDsForPerson(laurensID);
|
||||
w?.log(
|
||||
'getting all face ids for laurens (${laurensFaceIDs.length} faces)',
|
||||
);
|
||||
final laurensFaceIdToEmbeddingData = await MLDataDB.instance
|
||||
.getFaceEmbeddingMapForFaces(laurensFaceIDs);
|
||||
|
||||
// Fill the vector DB with all embeddings
|
||||
final laurensFaceIdToFloat32 = laurensFaceIdToEmbeddingData.map(
|
||||
(key, value) => MapEntry(
|
||||
key,
|
||||
Float32List.fromList(EVector.fromBuffer(value).values),
|
||||
),
|
||||
);
|
||||
final keys = Uint64List.fromList(
|
||||
List.generate(
|
||||
laurensFaceIdToFloat32.length,
|
||||
(index) => BigInt.from(index + 1),
|
||||
),
|
||||
);
|
||||
final vectorDB = VectorDb(
|
||||
filePath: (await getApplicationSupportDirectory()).path +
|
||||
"/ml/test/vector_db_face_index.usearch",
|
||||
dimensions: BigInt.from(
|
||||
laurensFaceIdToFloat32.values.first.length,
|
||||
),
|
||||
);
|
||||
await vectorDB.resetIndex();
|
||||
await vectorDB.bulkAddVectors(
|
||||
keys: keys,
|
||||
vectors: laurensFaceIdToFloat32.values.toList(),
|
||||
);
|
||||
|
||||
// Benchmarking the vector DB
|
||||
final queries = laurensFaceIdToFloat32.values.toList();
|
||||
final count = BigInt.from(10);
|
||||
w?.reset();
|
||||
final (vectorKeys, distances) = await vectorDB.bulkSearchVectors(
|
||||
queries: queries,
|
||||
count: count,
|
||||
);
|
||||
|
||||
w?.log(
|
||||
'Done with ${queries.length * queries.length} (${queries.length} x ${queries.length}}) embeddings comparisons in vector DB',
|
||||
);
|
||||
logger.info(
|
||||
'vector db results: ${vectorKeys.length} results, first: ${vectorKeys.first}, hundredth: ${vectorKeys[99]}',
|
||||
);
|
||||
|
||||
// Benchmarking our own vector comparisons
|
||||
final laurensFaceIdToEmbeddingVectors =
|
||||
laurensFaceIdToEmbeddingData.map(
|
||||
(key, value) => MapEntry(
|
||||
key,
|
||||
Vector.fromList(EVector.fromBuffer(value).values),
|
||||
),
|
||||
);
|
||||
final faceVectors = laurensFaceIdToEmbeddingVectors.values;
|
||||
w?.reset();
|
||||
for (final faceVector in faceVectors) {
|
||||
for (final otherFaceVector in faceVectors) {
|
||||
final _ = 1 - faceVector.dot(otherFaceVector);
|
||||
}
|
||||
}
|
||||
|
||||
w?.log(
|
||||
'Done with ${faceVectors.length * faceVectors.length} (${faceVectors.length} x ${faceVectors.length}}) embeddings comparisons in own method',
|
||||
);
|
||||
await vectorDB.deleteIndex();
|
||||
} catch (e, s) {
|
||||
logger.warning('vector DB search failed ', e, s);
|
||||
|
||||
await showGenericErrorDialog(context: context, error: e);
|
||||
}
|
||||
},
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Benchmark Vector DB CLIP",
|
||||
),
|
||||
pressedColor: getEnteColorScheme(context).fillFaint,
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
try {
|
||||
final w = (kDebugMode ? EnteWatch('MLDebugSectionWidget') : null)
|
||||
?..start();
|
||||
final clipEmbeddings = await mlDataDB.getAllClipVectors();
|
||||
w?.log(
|
||||
'getting all clip embeddings (${clipEmbeddings.length} embeddings)',
|
||||
);
|
||||
|
||||
// Fill the vector DB with all embeddings
|
||||
final clipFloat32 = clipEmbeddings
|
||||
.map(
|
||||
(value) => Float32List.fromList(value.vector.toList()),
|
||||
)
|
||||
.toList();
|
||||
final keys = Uint64List.fromList(
|
||||
List.generate(
|
||||
clipFloat32.length,
|
||||
(index) => BigInt.from(index + 1),
|
||||
),
|
||||
);
|
||||
final vectorDB = VectorDb(
|
||||
filePath: (await getApplicationSupportDirectory()).path +
|
||||
"/ml/test/vector_db_clip_index.usearch",
|
||||
dimensions: BigInt.from(
|
||||
clipFloat32.first.length,
|
||||
),
|
||||
);
|
||||
await vectorDB.resetIndex();
|
||||
await vectorDB.bulkAddVectors(
|
||||
keys: keys,
|
||||
vectors: clipFloat32,
|
||||
);
|
||||
|
||||
// Benchmarking the vector DB
|
||||
final count = BigInt.from(10);
|
||||
w?.reset();
|
||||
final (vectorKeys, distances) = await vectorDB.bulkSearchVectors(
|
||||
queries: clipFloat32,
|
||||
count: count,
|
||||
);
|
||||
|
||||
w?.log(
|
||||
'Done with ${clipFloat32.length * clipFloat32.length} (${clipFloat32.length} x ${clipFloat32.length}}) embeddings comparisons in vector DB',
|
||||
);
|
||||
logger.info(
|
||||
'vector db results: ${vectorKeys.length} results, first: ${vectorKeys.first} with distances ${distances.first}, hundredth: ${vectorKeys[99]} with distances ${distances[99]}',
|
||||
);
|
||||
|
||||
// // Benchmarking our own vector comparisons
|
||||
// final clipVectors = clipEmbeddings
|
||||
// .map(
|
||||
// (value) => value.vector,
|
||||
// )
|
||||
// .toList();
|
||||
// w?.reset();
|
||||
// int compared = 0;
|
||||
// int ms = DateTime.now().millisecondsSinceEpoch;
|
||||
// for (final faceVector in clipVectors) {
|
||||
// for (final otherFaceVector in clipVectors) {
|
||||
// final _ = 1 - faceVector.dot(otherFaceVector);
|
||||
// }
|
||||
// compared++;
|
||||
// if (compared % 100 == 0) {
|
||||
// final now = DateTime.now().millisecondsSinceEpoch;
|
||||
// logger.info(
|
||||
// 'Compared next 100 in ${now - ms} ms, progress: ($compared / ${clipVectors.length})',
|
||||
// );
|
||||
// ms = now;
|
||||
// }
|
||||
// }
|
||||
// w?.log(
|
||||
// 'Done with ${clipVectors.length * clipVectors.length} (${clipVectors.length} x ${clipVectors.length}}) embeddings comparisons in own method',
|
||||
// );
|
||||
|
||||
await vectorDB.deleteIndex();
|
||||
} catch (e, s) {
|
||||
logger.warning('vector DB search failed ', e, s);
|
||||
|
||||
await showGenericErrorDialog(context: context, error: e);
|
||||
}
|
||||
},
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Test rust bridge",
|
||||
),
|
||||
pressedColor: getEnteColorScheme(context).fillFaint,
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
try {
|
||||
final String greetings = greet(name: "Tom");
|
||||
const String expected = "Hello, Tom!";
|
||||
assert(greetings == expected);
|
||||
debugPrint("String from rust: $greetings");
|
||||
showShortToast(context, greetings);
|
||||
} catch (e, s) {
|
||||
logger.warning('Rust bridge failed ', e, s);
|
||||
await showGenericErrorDialog(context: context, error: e);
|
||||
}
|
||||
},
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: FutureBuilder<IndexStatus>(
|
||||
future: getIndexStatus(),
|
||||
|
||||
@@ -57,69 +57,57 @@ class _MLUserDeveloperOptionsState extends State<MLUserDeveloperOptions> {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 48),
|
||||
widget.mlIsEnabled
|
||||
? ButtonWidget(
|
||||
buttonType: ButtonType.neutral,
|
||||
labelText: "Purge empty indices",
|
||||
onTap: () async {
|
||||
await deleteEmptyIndices(context);
|
||||
},
|
||||
)
|
||||
: const SizedBox(),
|
||||
widget.mlIsEnabled
|
||||
? const SizedBox(height: 24)
|
||||
: const SizedBox(),
|
||||
widget.mlIsEnabled
|
||||
? ButtonWidget(
|
||||
buttonType: ButtonType.neutral,
|
||||
labelText: "Reset all local ML",
|
||||
onTap: () async {
|
||||
await deleteAllLocalML(context);
|
||||
},
|
||||
)
|
||||
: const SizedBox(),
|
||||
widget.mlIsEnabled
|
||||
? const SizedBox(height: 24)
|
||||
: const SizedBox(),
|
||||
widget.mlIsEnabled
|
||||
? MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Remote fetch",
|
||||
),
|
||||
menuItemColor: colorScheme.fillFaint,
|
||||
trailingWidget: ToggleSwitchWidget(
|
||||
value: () => localSettings.remoteFetchEnabled,
|
||||
onChanged: () async {
|
||||
try {
|
||||
await localSettings.toggleRemoteFetch();
|
||||
_logger.info(
|
||||
'Remote fetch is turned ${localSettings.remoteFetchEnabled ? 'on' : 'off'}',
|
||||
);
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
} catch (e, s) {
|
||||
_logger.warning(
|
||||
'Remote fetch toggle failed ',
|
||||
e,
|
||||
s,
|
||||
);
|
||||
await showGenericErrorDialog(
|
||||
context: context,
|
||||
error: e,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
singleBorderRadius: 8,
|
||||
alignCaptionedTextToLeft: true,
|
||||
isBottomBorderRadiusRemoved: true,
|
||||
isGestureDetectorDisabled: true,
|
||||
)
|
||||
: const SizedBox(),
|
||||
widget.mlIsEnabled
|
||||
? const SizedBox(height: 24)
|
||||
: const SizedBox.shrink(),
|
||||
widget.mlIsEnabled ? ButtonWidget(
|
||||
buttonType: ButtonType.neutral,
|
||||
labelText: "Purge empty indices",
|
||||
onTap: () async {
|
||||
await deleteEmptyIndices(context);
|
||||
},
|
||||
) : const SizedBox(),
|
||||
widget.mlIsEnabled ? const SizedBox(height: 24) : const SizedBox(),
|
||||
widget.mlIsEnabled ? ButtonWidget(
|
||||
buttonType: ButtonType.neutral,
|
||||
labelText: "Reset all local ML",
|
||||
onTap: () async {
|
||||
await deleteAllLocalML(context);
|
||||
},
|
||||
) : const SizedBox(),
|
||||
widget.mlIsEnabled ? const SizedBox(height: 24) : const SizedBox(),
|
||||
widget.mlIsEnabled ? MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Remote fetch",
|
||||
),
|
||||
menuItemColor: colorScheme.fillFaint,
|
||||
trailingWidget: ToggleSwitchWidget(
|
||||
value: () => localSettings.remoteFetchEnabled,
|
||||
onChanged: () async {
|
||||
try {
|
||||
await localSettings.toggleRemoteFetch();
|
||||
_logger.info(
|
||||
'Remote fetch is turned ${localSettings.remoteFetchEnabled ? 'on' : 'off'}',
|
||||
);
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
} catch (e, s) {
|
||||
_logger.warning(
|
||||
'Remote fetch toggle failed ',
|
||||
e,
|
||||
s,
|
||||
);
|
||||
await showGenericErrorDialog(
|
||||
context: context,
|
||||
error: e,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
singleBorderRadius: 8,
|
||||
alignCaptionedTextToLeft: true,
|
||||
isBottomBorderRadiusRemoved: true,
|
||||
isGestureDetectorDisabled: true,
|
||||
) : const SizedBox(),
|
||||
widget.mlIsEnabled ? const SizedBox(height: 24) : const SizedBox.shrink(),
|
||||
ButtonWidget(
|
||||
buttonType: ButtonType.neutral,
|
||||
labelText: "Load face detection model",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import "package:flutter/material.dart";
|
||||
import 'package:photos/models/file/file.dart';
|
||||
import "package:photos/ui/viewer/file/zoomable_image.dart";
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import "dart:async";
|
||||
|
||||
import 'package:fast_base58/fast_base58.dart';
|
||||
import "package:flutter/cupertino.dart";
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import "package:local_auth/local_auth.dart";
|
||||
|
||||
@@ -3,8 +3,7 @@ import "package:flutter/material.dart";
|
||||
import "package:photos/generated/l10n.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
|
||||
Future<DateTime?> showDatePickerSheet(
|
||||
BuildContext context, {
|
||||
Future<DateTime?> showDatePickerSheet(BuildContext context, {
|
||||
required DateTime initialDate,
|
||||
DateTime? maxDate,
|
||||
DateTime? minDate,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import "package:photos/generated/l10n.dart";
|
||||
import 'package:photos/models/file/file.dart';
|
||||
|
||||
@@ -5,7 +5,6 @@ import "package:photos/theme/ente_theme.dart";
|
||||
import "package:photos/ui/components/info_item_widget.dart";
|
||||
import "package:photos/ui/viewer/date/edit_date_sheet.dart";
|
||||
import "package:photos/utils/standalone/date_time.dart";
|
||||
|
||||
class CreationTimeItem extends StatefulWidget {
|
||||
final EnteFile file;
|
||||
final int currentUserID;
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
|
||||
|
||||
import "package:photos/core/configuration.dart";
|
||||
import "package:photos/services/machine_learning/face_ml/person/person_service.dart";
|
||||
|
||||
Future<bool> isMeAssigned() async {
|
||||
final personEntities = await PersonService.instance.getPersons();
|
||||
final currentUserEmail = Configuration.instance.getEmail();
|
||||
final personEntities = await PersonService.instance.getPersons();
|
||||
final currentUserEmail = Configuration.instance.getEmail();
|
||||
|
||||
bool isAssigned = false;
|
||||
for (final personEntity in personEntities) {
|
||||
if (personEntity.data.email == currentUserEmail) {
|
||||
isAssigned = true;
|
||||
break;
|
||||
bool isAssigned = false;
|
||||
for (final personEntity in personEntities) {
|
||||
if (personEntity.data.email == currentUserEmail) {
|
||||
isAssigned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return isAssigned;
|
||||
}
|
||||
return isAssigned;
|
||||
}
|
||||
@@ -23,7 +23,7 @@ import "package:photos/events/file_uploaded_event.dart";
|
||||
import 'package:photos/events/files_updated_event.dart';
|
||||
import 'package:photos/events/local_photos_updated_event.dart';
|
||||
import 'package:photos/events/subscription_purchased_event.dart';
|
||||
import "package:photos/main.dart";
|
||||
import 'package:photos/main.dart';
|
||||
import "package:photos/models/api/metadata.dart";
|
||||
import "package:photos/models/backup/backup_item.dart";
|
||||
import "package:photos/models/backup/backup_item_status.dart";
|
||||
|
||||
@@ -58,8 +58,6 @@ class FlagService {
|
||||
|
||||
bool get enableMobMultiPart => flags.enableMobMultiPart || internalUser;
|
||||
|
||||
bool get enableVectorDb => flags.internalUser;
|
||||
|
||||
String get castUrl => flags.castUrl;
|
||||
|
||||
bool hasSyncedAccountFlags() {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -175,14 +175,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
build_cli_annotations:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_cli_annotations
|
||||
sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
build_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1015,14 +1007,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.24"
|
||||
flutter_rust_bridge:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_rust_bridge
|
||||
sha256: "37ef40bc6f863652e865f0b2563ea07f0d3c58d8efad803cc01933a4b2ee067e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.11.1"
|
||||
flutter_secure_storage:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2153,13 +2137,6 @@ packages:
|
||||
url: "https://github.com/KasemJaffer/receive_sharing_intent.git"
|
||||
source: git
|
||||
version: "1.8.1"
|
||||
rust_lib_photos:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: rust_builder
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.0.1"
|
||||
rxdart:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -12,11 +12,11 @@ description: ente photos application
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
|
||||
version: 1.1.63+1097
|
||||
version: 1.1.54+1084
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
sdk: ">=3.3.0 <4.0.0"
|
||||
sdk: ">=3.0.0 <4.0.0"
|
||||
|
||||
dependencies:
|
||||
adaptive_theme: ^3.1.0
|
||||
@@ -95,7 +95,6 @@ dependencies:
|
||||
flutter_map: ^6.2.0
|
||||
flutter_map_marker_cluster: ^1.3.6
|
||||
flutter_password_strength: ^0.1.6
|
||||
flutter_rust_bridge: 2.11.1
|
||||
# Do not upgrade this package unless this issue is resolved:
|
||||
# https://github.com/juliansteenbakker/flutter_secure_storage/issues/870
|
||||
# On v9.2.4, keys related to lockscreen persist even after reintsall. For context see:
|
||||
@@ -178,8 +177,6 @@ dependencies:
|
||||
git:
|
||||
url: https://github.com/KasemJaffer/receive_sharing_intent.git
|
||||
ref: 2cea396
|
||||
rust_lib_photos:
|
||||
path: rust_builder
|
||||
screenshot: ^3.0.0
|
||||
scrollable_positioned_list: ^0.3.5
|
||||
sentry: ^8.14.1
|
||||
|
||||
1
mobile/apps/photos/rust/.gitignore
vendored
1
mobile/apps/photos/rust/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
/target
|
||||
901
mobile/apps/photos/rust/Cargo.lock
generated
901
mobile/apps/photos/rust/Cargo.lock
generated
@@ -1,901 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allo-isolate"
|
||||
version = "0.1.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "449e356a4864c017286dbbec0e12767ea07efba29e3b7d984194c2a7ff3c4550"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"atomic",
|
||||
"backtrace",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android_log-sys"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84521a3cf562bc62942e294181d9eef17eb38ceb8c68677bc49f144e4c3d4f8d"
|
||||
|
||||
[[package]]
|
||||
name = "android_logger"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbb4e440d04be07da1f1bf44fb4495ebd58669372fe0cffa6e48595ac5bd88a3"
|
||||
dependencies = [
|
||||
"android_log-sys",
|
||||
"env_filter",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "atomic"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "build-target"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "832133bbabbbaa9fbdba793456a2827627a7d2b8fb96032fa1e7666d7895832b"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
|
||||
dependencies = [
|
||||
"termcolor",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console_error_panic_hook"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.112"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58ab30434ea0ff6aa640a08dda5284026a366d47565496fd40b6cbfbdd7e31a2"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cxxbridge-flags",
|
||||
"cxxbridge-macro",
|
||||
"link-cplusplus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-build"
|
||||
version = "1.0.112"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b649d7dfae8268450d53d109388b337b9352c7cba1fc10db4a1bc23c3dc189fb"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"codespan-reporting",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-flags"
|
||||
version = "1.0.112"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42281b20eba5218c539295c667c18e2f50211bb11902419194c6ed1ae808e547"
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-macro"
|
||||
version = "1.0.112"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b45506e3c66512b0a65d291a6b452128b7b1dd9841e20d1e151addbd2c00ea50"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dart-sys"
|
||||
version = "4.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57967e4b200d767d091b961d6ab42cc7d0cc14fe9e052e75d0d3cf9eb732d895"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "5.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"hashbrown",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "delegate-attr"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51aac4c99b2e6775164b412ea33ae8441b2fde2dbf05a20bc0052a63d08c475b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flutter_rust_bridge"
|
||||
version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dde126295b2acc5f0a712e265e91b6fdc0ed38767496483e592ae7134db83725"
|
||||
dependencies = [
|
||||
"allo-isolate",
|
||||
"android_logger",
|
||||
"anyhow",
|
||||
"build-target",
|
||||
"bytemuck",
|
||||
"byteorder",
|
||||
"console_error_panic_hook",
|
||||
"dart-sys",
|
||||
"delegate-attr",
|
||||
"flutter_rust_bridge_macros",
|
||||
"futures",
|
||||
"js-sys",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"oslog",
|
||||
"portable-atomic",
|
||||
"threadpool",
|
||||
"tokio",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flutter_rust_bridge_macros"
|
||||
version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5f0420326b13675321b194928bb7830043b68cf8b810e1c651285c747abb080"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"md-5",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.28.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
|
||||
[[package]]
|
||||
name = "link-cplusplus"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a6f6da007f968f9def0d65a05b187e2960183de70c160204ecfccf0ee330212"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "md-5"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "oslog"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80d2043d1f61d77cb2f4b1f7b7b2295f40507f5f8e9d1c8bf10a1ca5f97a3969"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"dashmap",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e8af0dde094006011e6a740d4879319439489813bd0bcdc7d821beaeeff48ec"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "rust_lib_photos"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"flutter_rust_bridge",
|
||||
"usearch",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "scratch"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f6280af86e5f559536da57a45ebc84948833b3bee313a7dd25232e09c878a52"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "threadpool"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
|
||||
dependencies = [
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"num_cpus",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||
|
||||
[[package]]
|
||||
name = "usearch"
|
||||
version = "2.17.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "908331accde6ff6bfe83e1f2dfd4cc77343d107bfacecd2f19b7a14d87cdb2df"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"cxx-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
@@ -1,14 +0,0 @@
|
||||
[package]
|
||||
name = "rust_lib_photos"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "staticlib"]
|
||||
|
||||
[dependencies]
|
||||
flutter_rust_bridge = "=2.11.1"
|
||||
usearch = "2.17.11"
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(frb_expand)'] }
|
||||
@@ -1,2 +0,0 @@
|
||||
pub mod simple;
|
||||
pub mod usearch_api;
|
||||
@@ -1,10 +0,0 @@
|
||||
#[flutter_rust_bridge::frb(sync)] // Synchronous mode for simplicity of the demo
|
||||
pub fn greet(name: String) -> String {
|
||||
format!("Hello, {name}!")
|
||||
}
|
||||
|
||||
#[flutter_rust_bridge::frb(init)]
|
||||
pub fn init_app() {
|
||||
// Default utilities - feel free to customize
|
||||
flutter_rust_bridge::setup_default_user_utils();
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
use flutter_rust_bridge::frb;
|
||||
use usearch::{Index, IndexOptions, MetricKind, ScalarKind};
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[frb(opaque)]
|
||||
pub struct VectorDB {
|
||||
index: Index,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl VectorDB {
|
||||
#[frb(sync)]
|
||||
pub fn new(file_path: &str, dimensions: usize) -> Self {
|
||||
let path = PathBuf::from(file_path);
|
||||
let file_exists = path.try_exists().unwrap_or(false);
|
||||
|
||||
let mut options = IndexOptions::default();
|
||||
options.dimensions = dimensions;
|
||||
options.metric = MetricKind::IP;
|
||||
options.quantization = ScalarKind::F32;
|
||||
options.connectivity = 0; // auto
|
||||
options.expansion_add = 0; // auto
|
||||
options.expansion_search = 0; // auto
|
||||
|
||||
let index = Index::new(&options).expect("Failed to create index");
|
||||
index
|
||||
.reserve(1000)
|
||||
.expect("Failed to reserve space in index");
|
||||
|
||||
let db = Self { index, path };
|
||||
|
||||
if file_exists {
|
||||
println!("Loading index from disk.");
|
||||
db.index.load(file_path).expect("Failed to load index");
|
||||
} else {
|
||||
println!("Creating new index.");
|
||||
db.save_index();
|
||||
}
|
||||
db
|
||||
}
|
||||
|
||||
fn save_index(&self) {
|
||||
// Ensure directory exists
|
||||
if let Some(parent) = self.path.parent() {
|
||||
std::fs::create_dir_all(parent).expect("Failed to create directory");
|
||||
}
|
||||
self.index
|
||||
.save(self.path.to_str().expect("Invalid path"))
|
||||
.expect("Failed to save index");
|
||||
}
|
||||
|
||||
fn ensure_capacity(&self, margin: usize) {
|
||||
let current_size = self.index.size();
|
||||
let capacity = self.index.capacity();
|
||||
if current_size + margin + 1000 >= capacity {
|
||||
self.index
|
||||
.reserve(current_size + margin)
|
||||
.expect("Failed to reserve space in index");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_vector(&self, key: u64, vector: &Vec<f32>) {
|
||||
if self.contains_vector(key) {
|
||||
self.remove_vector(key);
|
||||
} else {
|
||||
self.ensure_capacity(1);
|
||||
}
|
||||
self.index.add(key, vector).expect("Failed to add vector");
|
||||
self.save_index();
|
||||
}
|
||||
|
||||
pub fn bulk_add_vectors(&self, keys: Vec<u64>, vectors: &Vec<Vec<f32>>) {
|
||||
self.ensure_capacity(keys.len());
|
||||
for (key, vector) in keys.iter().zip(vectors.iter()) {
|
||||
if self.contains_vector(*key) {
|
||||
self.remove_vector(*key);
|
||||
}
|
||||
self.index
|
||||
.add(*key, vector)
|
||||
.expect("Failed to (bulk) add vector");
|
||||
}
|
||||
self.save_index();
|
||||
}
|
||||
|
||||
pub fn search_vectors(&self, query: &Vec<f32>, count: usize) -> (Vec<u64>, Vec<f32>) {
|
||||
let matches = self
|
||||
.index
|
||||
.search(query, count)
|
||||
.expect("Failed to search vectors");
|
||||
(matches.keys, matches.distances)
|
||||
}
|
||||
|
||||
pub fn bulk_search_vectors(
|
||||
&self,
|
||||
queries: &Vec<Vec<f32>>,
|
||||
count: usize,
|
||||
) -> (Vec<Vec<u64>>, Vec<Vec<f32>>) {
|
||||
let mut keys = Vec::new();
|
||||
let mut distances = Vec::new();
|
||||
|
||||
for query in queries {
|
||||
let (keys_result, distances_result) = self.search_vectors(query, count);
|
||||
keys.push(keys_result);
|
||||
distances.push(distances_result);
|
||||
}
|
||||
(keys, distances)
|
||||
}
|
||||
|
||||
/// Check if a vector with the given key exists in the index.
|
||||
/// `true` if the index contains the vector with the given key, `false` otherwise.
|
||||
pub fn contains_vector(&self, key: u64) -> bool {
|
||||
self.index.contains(key)
|
||||
}
|
||||
|
||||
pub fn get_vector(&self, key: u64) -> Vec<f32> {
|
||||
let mut vector: Vec<f32> = vec![0.0; self.index.dimensions()];
|
||||
self.index
|
||||
.get(key, &mut vector)
|
||||
.expect("Failed to get vector");
|
||||
vector
|
||||
}
|
||||
|
||||
pub fn bulk_get_vectors(&self, keys: Vec<u64>) -> Vec<Vec<f32>> {
|
||||
let mut vectors = Vec::new();
|
||||
for key in keys {
|
||||
let vector = self.get_vector(key);
|
||||
vectors.push(vector);
|
||||
}
|
||||
vectors
|
||||
}
|
||||
|
||||
pub fn remove_vector(&self, key: u64) -> usize {
|
||||
let removed_count = self.index.remove(key).expect("Failed to remove vector");
|
||||
self.save_index();
|
||||
removed_count
|
||||
}
|
||||
|
||||
pub fn bulk_remove_vectors(&self, keys: Vec<u64>) -> usize {
|
||||
let mut removed_count = 0;
|
||||
for key in keys {
|
||||
removed_count += self
|
||||
.index
|
||||
.remove(key)
|
||||
.expect("Failed to (bulk) remove vector");
|
||||
}
|
||||
self.save_index();
|
||||
removed_count
|
||||
}
|
||||
|
||||
pub fn reset_index(&self) {
|
||||
self.index.reset().expect("Failed to reset index");
|
||||
self.index
|
||||
.reserve(1000)
|
||||
.expect("Failed to reserve space in index");
|
||||
self.save_index();
|
||||
}
|
||||
|
||||
pub fn delete_index(self) {
|
||||
if self.path.exists() {
|
||||
std::fs::remove_file(&self.path).expect("Failed to delete index file");
|
||||
} else {
|
||||
println!("Index file does not exist.");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_index_stats(&self) -> (usize, usize, usize, usize, usize, usize, usize) {
|
||||
let size = self.index.size();
|
||||
let capacity = self.index.capacity();
|
||||
let dimensions = self.index.dimensions();
|
||||
|
||||
let file_size = self.index.serialized_length();
|
||||
let memory_usage = self.index.memory_usage();
|
||||
|
||||
let expansion_add = self.index.expansion_add();
|
||||
let expansion_search = self.index.expansion_search();
|
||||
|
||||
(
|
||||
size,
|
||||
capacity,
|
||||
dimensions,
|
||||
file_size,
|
||||
memory_usage,
|
||||
expansion_add,
|
||||
expansion_search,
|
||||
)
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
||||
pub mod api;
|
||||
mod frb_generated;
|
||||
29
mobile/apps/photos/rust_builder/.gitignore
vendored
29
mobile/apps/photos/rust_builder/.gitignore
vendored
@@ -1,29 +0,0 @@
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||
/pubspec.lock
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
build/
|
||||
@@ -1 +0,0 @@
|
||||
Please ignore this folder, which is just glue to build Rust with Flutter.
|
||||
@@ -1,9 +0,0 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.cxx
|
||||
@@ -1,56 +0,0 @@
|
||||
// The Android Gradle Plugin builds the native code with the Android NDK.
|
||||
|
||||
group 'com.flutter_rust_bridge.rust_lib_photos'
|
||||
version '1.0'
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// The Android Gradle Plugin knows how to build native code with the NDK.
|
||||
classpath 'com.android.tools.build:gradle:7.3.0'
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
if (project.android.hasProperty("namespace")) {
|
||||
namespace 'com.flutter_rust_bridge.rust_lib_photos'
|
||||
}
|
||||
|
||||
// Bumping the plugin compileSdkVersion requires all clients of this plugin
|
||||
// to bump the version in their app.
|
||||
compileSdkVersion 33
|
||||
|
||||
// Use the NDK version
|
||||
// declared in /android/app/build.gradle file of the Flutter project.
|
||||
// Replace it with a version number if this plugin requires a specfic NDK version.
|
||||
// (e.g. ndkVersion "23.1.7779620")
|
||||
ndkVersion android.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 19
|
||||
}
|
||||
}
|
||||
|
||||
apply from: "../cargokit/gradle/plugin.gradle"
|
||||
cargokit {
|
||||
manifestDir = "../../rust"
|
||||
libname = "rust_lib_photos"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
rootProject.name = 'rust_lib_photos'
|
||||
@@ -1,3 +0,0 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.flutter_rust_bridge.rust_lib_photos">
|
||||
</manifest>
|
||||
@@ -1,4 +0,0 @@
|
||||
target
|
||||
.dart_tool
|
||||
*.iml
|
||||
!pubspec.lock
|
||||
@@ -1,42 +0,0 @@
|
||||
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||
|
||||
Copyright 2022 Matej Knopp
|
||||
|
||||
================================================================================
|
||||
|
||||
MIT LICENSE
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
||||
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
================================================================================
|
||||
|
||||
APACHE LICENSE, VERSION 2.0
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||
|
||||
Experimental repository to provide glue for seamlessly integrating cargo build
|
||||
with flutter plugins and packages.
|
||||
|
||||
See https://matejknopp.com/post/flutter_plugin_in_rust_with_no_prebuilt_binaries/
|
||||
for a tutorial on how to use Cargokit.
|
||||
|
||||
Example plugin available at https://github.com/irondash/hello_rust_ffi_plugin.
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
BASEDIR=$(dirname "$0")
|
||||
|
||||
# Workaround for https://github.com/dart-lang/pub/issues/4010
|
||||
BASEDIR=$(cd "$BASEDIR" ; pwd -P)
|
||||
|
||||
# Remove XCode SDK from path. Otherwise this breaks tool compilation when building iOS project
|
||||
NEW_PATH=`echo $PATH | tr ":" "\n" | grep -v "Contents/Developer/" | tr "\n" ":"`
|
||||
|
||||
export PATH=${NEW_PATH%?} # remove trailing :
|
||||
|
||||
env
|
||||
|
||||
# Platform name (macosx, iphoneos, iphonesimulator)
|
||||
export CARGOKIT_DARWIN_PLATFORM_NAME=$PLATFORM_NAME
|
||||
|
||||
# Arctive architectures (arm64, armv7, x86_64), space separated.
|
||||
export CARGOKIT_DARWIN_ARCHS=$ARCHS
|
||||
|
||||
# Current build configuration (Debug, Release)
|
||||
export CARGOKIT_CONFIGURATION=$CONFIGURATION
|
||||
|
||||
# Path to directory containing Cargo.toml.
|
||||
export CARGOKIT_MANIFEST_DIR=$PODS_TARGET_SRCROOT/$1
|
||||
|
||||
# Temporary directory for build artifacts.
|
||||
export CARGOKIT_TARGET_TEMP_DIR=$TARGET_TEMP_DIR
|
||||
|
||||
# Output directory for final artifacts.
|
||||
export CARGOKIT_OUTPUT_DIR=$PODS_CONFIGURATION_BUILD_DIR/$PRODUCT_NAME
|
||||
|
||||
# Directory to store built tool artifacts.
|
||||
export CARGOKIT_TOOL_TEMP_DIR=$TARGET_TEMP_DIR/build_tool
|
||||
|
||||
# Directory inside root project. Not necessarily the top level directory of root project.
|
||||
export CARGOKIT_ROOT_PROJECT_DIR=$SRCROOT
|
||||
|
||||
FLUTTER_EXPORT_BUILD_ENVIRONMENT=(
|
||||
"$PODS_ROOT/../Flutter/ephemeral/flutter_export_environment.sh" # macOS
|
||||
"$PODS_ROOT/../Flutter/flutter_export_environment.sh" # iOS
|
||||
)
|
||||
|
||||
for path in "${FLUTTER_EXPORT_BUILD_ENVIRONMENT[@]}"
|
||||
do
|
||||
if [[ -f "$path" ]]; then
|
||||
source "$path"
|
||||
fi
|
||||
done
|
||||
|
||||
sh "$BASEDIR/run_build_tool.sh" build-pod "$@"
|
||||
|
||||
# Make a symlink from built framework to phony file, which will be used as input to
|
||||
# build script. This should force rebuild (podspec currently doesn't support alwaysOutOfDate
|
||||
# attribute on custom build phase)
|
||||
ln -fs "$OBJROOT/XCBuildData/build.db" "${BUILT_PRODUCTS_DIR}/cargokit_phony"
|
||||
ln -fs "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}" "${BUILT_PRODUCTS_DIR}/cargokit_phony_out"
|
||||
@@ -1,5 +0,0 @@
|
||||
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||
|
||||
A sample command-line application with an entrypoint in `bin/`, library code
|
||||
in `lib/`, and example unit test in `test/`.
|
||||
@@ -1,34 +0,0 @@
|
||||
# This is copied from Cargokit (which is the official way to use it currently)
|
||||
# Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||
|
||||
# This file configures the static analysis results for your project (errors,
|
||||
# warnings, and lints).
|
||||
#
|
||||
# This enables the 'recommended' set of lints from `package:lints`.
|
||||
# This set helps identify many issues that may lead to problems when running
|
||||
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
|
||||
# style and format.
|
||||
#
|
||||
# If you want a smaller set of lints you can change this to specify
|
||||
# 'package:lints/core.yaml'. These are just the most critical lints
|
||||
# (the recommended set includes the core lints).
|
||||
# The core lints are also what is used by pub.dev for scoring packages.
|
||||
|
||||
include: package:lints/recommended.yaml
|
||||
|
||||
# Uncomment the following section to specify additional rules.
|
||||
|
||||
linter:
|
||||
rules:
|
||||
- prefer_relative_imports
|
||||
- directives_ordering
|
||||
|
||||
# analyzer:
|
||||
# exclude:
|
||||
# - path/to/excluded/files/**
|
||||
|
||||
# For more information about the core and recommended set of lints, see
|
||||
# https://dart.dev/go/core-lints
|
||||
|
||||
# For additional information about configuring this file, see
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
@@ -1,8 +0,0 @@
|
||||
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||
|
||||
import 'package:build_tool/build_tool.dart' as build_tool;
|
||||
|
||||
void main(List<String> arguments) {
|
||||
build_tool.runMain(arguments);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||
|
||||
import 'src/build_tool.dart' as build_tool;
|
||||
|
||||
Future<void> runMain(List<String> args) async {
|
||||
return build_tool.runMain(args);
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:version/version.dart';
|
||||
|
||||
import 'target.dart';
|
||||
import 'util.dart';
|
||||
|
||||
class AndroidEnvironment {
|
||||
AndroidEnvironment({
|
||||
required this.sdkPath,
|
||||
required this.ndkVersion,
|
||||
required this.minSdkVersion,
|
||||
required this.targetTempDir,
|
||||
required this.target,
|
||||
});
|
||||
|
||||
static void clangLinkerWrapper(List<String> args) {
|
||||
final clang = Platform.environment['_CARGOKIT_NDK_LINK_CLANG'];
|
||||
if (clang == null) {
|
||||
throw Exception(
|
||||
"cargo-ndk rustc linker: didn't find _CARGOKIT_NDK_LINK_CLANG env var");
|
||||
}
|
||||
final target = Platform.environment['_CARGOKIT_NDK_LINK_TARGET'];
|
||||
if (target == null) {
|
||||
throw Exception(
|
||||
"cargo-ndk rustc linker: didn't find _CARGOKIT_NDK_LINK_TARGET env var");
|
||||
}
|
||||
|
||||
runCommand(clang, [
|
||||
target,
|
||||
...args,
|
||||
]);
|
||||
}
|
||||
|
||||
/// Full path to Android SDK.
|
||||
final String sdkPath;
|
||||
|
||||
/// Full version of Android NDK.
|
||||
final String ndkVersion;
|
||||
|
||||
/// Minimum supported SDK version.
|
||||
final int minSdkVersion;
|
||||
|
||||
/// Target directory for build artifacts.
|
||||
final String targetTempDir;
|
||||
|
||||
/// Target being built.
|
||||
final Target target;
|
||||
|
||||
bool ndkIsInstalled() {
|
||||
final ndkPath = path.join(sdkPath, 'ndk', ndkVersion);
|
||||
final ndkPackageXml = File(path.join(ndkPath, 'package.xml'));
|
||||
return ndkPackageXml.existsSync();
|
||||
}
|
||||
|
||||
void installNdk({
|
||||
required String javaHome,
|
||||
}) {
|
||||
final sdkManagerExtension = Platform.isWindows ? '.bat' : '';
|
||||
final sdkManager = path.join(
|
||||
sdkPath,
|
||||
'cmdline-tools',
|
||||
'latest',
|
||||
'bin',
|
||||
'sdkmanager$sdkManagerExtension',
|
||||
);
|
||||
|
||||
log.info('Installing NDK $ndkVersion');
|
||||
runCommand(sdkManager, [
|
||||
'--install',
|
||||
'ndk;$ndkVersion',
|
||||
], environment: {
|
||||
'JAVA_HOME': javaHome,
|
||||
});
|
||||
}
|
||||
|
||||
Future<Map<String, String>> buildEnvironment() async {
|
||||
final hostArch = Platform.isMacOS
|
||||
? "darwin-x86_64"
|
||||
: (Platform.isLinux ? "linux-x86_64" : "windows-x86_64");
|
||||
|
||||
final ndkPath = path.join(sdkPath, 'ndk', ndkVersion);
|
||||
final toolchainPath = path.join(
|
||||
ndkPath,
|
||||
'toolchains',
|
||||
'llvm',
|
||||
'prebuilt',
|
||||
hostArch,
|
||||
'bin',
|
||||
);
|
||||
|
||||
final minSdkVersion =
|
||||
math.max(target.androidMinSdkVersion!, this.minSdkVersion);
|
||||
|
||||
final exe = Platform.isWindows ? '.exe' : '';
|
||||
|
||||
final arKey = 'AR_${target.rust}';
|
||||
final arValue = ['${target.rust}-ar', 'llvm-ar', 'llvm-ar.exe']
|
||||
.map((e) => path.join(toolchainPath, e))
|
||||
.firstWhereOrNull((element) => File(element).existsSync());
|
||||
if (arValue == null) {
|
||||
throw Exception('Failed to find ar for $target in $toolchainPath');
|
||||
}
|
||||
|
||||
final targetArg = '--target=${target.rust}$minSdkVersion';
|
||||
|
||||
final ccKey = 'CC_${target.rust}';
|
||||
final ccValue = path.join(toolchainPath, 'clang$exe');
|
||||
final cfFlagsKey = 'CFLAGS_${target.rust}';
|
||||
final cFlagsValue = targetArg;
|
||||
|
||||
final cxxKey = 'CXX_${target.rust}';
|
||||
final cxxValue = path.join(toolchainPath, 'clang++$exe');
|
||||
final cxxFlagsKey = 'CXXFLAGS_${target.rust}';
|
||||
final cxxFlagsValue = targetArg;
|
||||
|
||||
final linkerKey =
|
||||
'cargo_target_${target.rust.replaceAll('-', '_')}_linker'.toUpperCase();
|
||||
|
||||
final ranlibKey = 'RANLIB_${target.rust}';
|
||||
final ranlibValue = path.join(toolchainPath, 'llvm-ranlib$exe');
|
||||
|
||||
final ndkVersionParsed = Version.parse(ndkVersion);
|
||||
final rustFlagsKey = 'CARGO_ENCODED_RUSTFLAGS';
|
||||
final rustFlagsValue = _libGccWorkaround(targetTempDir, ndkVersionParsed);
|
||||
|
||||
final runRustTool =
|
||||
Platform.isWindows ? 'run_build_tool.cmd' : 'run_build_tool.sh';
|
||||
|
||||
final packagePath = (await Isolate.resolvePackageUri(
|
||||
Uri.parse('package:build_tool/buildtool.dart')))!
|
||||
.toFilePath();
|
||||
final selfPath = path.canonicalize(path.join(
|
||||
packagePath,
|
||||
'..',
|
||||
'..',
|
||||
'..',
|
||||
runRustTool,
|
||||
));
|
||||
|
||||
// Make sure that run_build_tool is working properly even initially launched directly
|
||||
// through dart run.
|
||||
final toolTempDir =
|
||||
Platform.environment['CARGOKIT_TOOL_TEMP_DIR'] ?? targetTempDir;
|
||||
|
||||
return {
|
||||
arKey: arValue,
|
||||
ccKey: ccValue,
|
||||
cfFlagsKey: cFlagsValue,
|
||||
cxxKey: cxxValue,
|
||||
cxxFlagsKey: cxxFlagsValue,
|
||||
ranlibKey: ranlibValue,
|
||||
rustFlagsKey: rustFlagsValue,
|
||||
linkerKey: selfPath,
|
||||
// Recognized by main() so we know when we're acting as a wrapper
|
||||
'_CARGOKIT_NDK_LINK_TARGET': targetArg,
|
||||
'_CARGOKIT_NDK_LINK_CLANG': ccValue,
|
||||
'CARGOKIT_TOOL_TEMP_DIR': toolTempDir,
|
||||
};
|
||||
}
|
||||
|
||||
// Workaround for libgcc missing in NDK23, inspired by cargo-ndk
|
||||
String _libGccWorkaround(String buildDir, Version ndkVersion) {
|
||||
final workaroundDir = path.join(
|
||||
buildDir,
|
||||
'cargokit',
|
||||
'libgcc_workaround',
|
||||
'${ndkVersion.major}',
|
||||
);
|
||||
Directory(workaroundDir).createSync(recursive: true);
|
||||
if (ndkVersion.major >= 23) {
|
||||
File(path.join(workaroundDir, 'libgcc.a'))
|
||||
.writeAsStringSync('INPUT(-lunwind)');
|
||||
} else {
|
||||
// Other way around, untested, forward libgcc.a from libunwind once Rust
|
||||
// gets updated for NDK23+.
|
||||
File(path.join(workaroundDir, 'libunwind.a'))
|
||||
.writeAsStringSync('INPUT(-lgcc)');
|
||||
}
|
||||
|
||||
var rustFlags = Platform.environment['CARGO_ENCODED_RUSTFLAGS'] ?? '';
|
||||
if (rustFlags.isNotEmpty) {
|
||||
rustFlags = '$rustFlags\x1f';
|
||||
}
|
||||
rustFlags = '$rustFlags-L\x1f$workaroundDir';
|
||||
return rustFlags;
|
||||
}
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:ed25519_edwards/ed25519_edwards.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'builder.dart';
|
||||
import 'crate_hash.dart';
|
||||
import 'options.dart';
|
||||
import 'precompile_binaries.dart';
|
||||
import 'rustup.dart';
|
||||
import 'target.dart';
|
||||
|
||||
class Artifact {
|
||||
/// File system location of the artifact.
|
||||
final String path;
|
||||
|
||||
/// Actual file name that the artifact should have in destination folder.
|
||||
final String finalFileName;
|
||||
|
||||
AritifactType get type {
|
||||
if (finalFileName.endsWith('.dll') ||
|
||||
finalFileName.endsWith('.dll.lib') ||
|
||||
finalFileName.endsWith('.pdb') ||
|
||||
finalFileName.endsWith('.so') ||
|
||||
finalFileName.endsWith('.dylib')) {
|
||||
return AritifactType.dylib;
|
||||
} else if (finalFileName.endsWith('.lib') || finalFileName.endsWith('.a')) {
|
||||
return AritifactType.staticlib;
|
||||
} else {
|
||||
throw Exception('Unknown artifact type for $finalFileName');
|
||||
}
|
||||
}
|
||||
|
||||
Artifact({
|
||||
required this.path,
|
||||
required this.finalFileName,
|
||||
});
|
||||
}
|
||||
|
||||
final _log = Logger('artifacts_provider');
|
||||
|
||||
class ArtifactProvider {
|
||||
ArtifactProvider({
|
||||
required this.environment,
|
||||
required this.userOptions,
|
||||
});
|
||||
|
||||
final BuildEnvironment environment;
|
||||
final CargokitUserOptions userOptions;
|
||||
|
||||
Future<Map<Target, List<Artifact>>> getArtifacts(List<Target> targets) async {
|
||||
final result = await _getPrecompiledArtifacts(targets);
|
||||
|
||||
final pendingTargets = List.of(targets);
|
||||
pendingTargets.removeWhere((element) => result.containsKey(element));
|
||||
|
||||
if (pendingTargets.isEmpty) {
|
||||
return result;
|
||||
}
|
||||
|
||||
final rustup = Rustup();
|
||||
for (final target in targets) {
|
||||
final builder = RustBuilder(target: target, environment: environment);
|
||||
builder.prepare(rustup);
|
||||
_log.info('Building ${environment.crateInfo.packageName} for $target');
|
||||
final targetDir = await builder.build();
|
||||
// For local build accept both static and dynamic libraries.
|
||||
final artifactNames = <String>{
|
||||
...getArtifactNames(
|
||||
target: target,
|
||||
libraryName: environment.crateInfo.packageName,
|
||||
aritifactType: AritifactType.dylib,
|
||||
remote: false,
|
||||
),
|
||||
...getArtifactNames(
|
||||
target: target,
|
||||
libraryName: environment.crateInfo.packageName,
|
||||
aritifactType: AritifactType.staticlib,
|
||||
remote: false,
|
||||
)
|
||||
};
|
||||
final artifacts = artifactNames
|
||||
.map((artifactName) => Artifact(
|
||||
path: path.join(targetDir, artifactName),
|
||||
finalFileName: artifactName,
|
||||
))
|
||||
.where((element) => File(element.path).existsSync())
|
||||
.toList();
|
||||
result[target] = artifacts;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<Map<Target, List<Artifact>>> _getPrecompiledArtifacts(
|
||||
List<Target> targets) async {
|
||||
if (userOptions.usePrecompiledBinaries == false) {
|
||||
_log.info('Precompiled binaries are disabled');
|
||||
return {};
|
||||
}
|
||||
if (environment.crateOptions.precompiledBinaries == null) {
|
||||
_log.fine('Precompiled binaries not enabled for this crate');
|
||||
return {};
|
||||
}
|
||||
|
||||
final start = Stopwatch()..start();
|
||||
final crateHash = CrateHash.compute(environment.manifestDir,
|
||||
tempStorage: environment.targetTempDir);
|
||||
_log.fine(
|
||||
'Computed crate hash $crateHash in ${start.elapsedMilliseconds}ms');
|
||||
|
||||
final downloadedArtifactsDir =
|
||||
path.join(environment.targetTempDir, 'precompiled', crateHash);
|
||||
Directory(downloadedArtifactsDir).createSync(recursive: true);
|
||||
|
||||
final res = <Target, List<Artifact>>{};
|
||||
|
||||
for (final target in targets) {
|
||||
final requiredArtifacts = getArtifactNames(
|
||||
target: target,
|
||||
libraryName: environment.crateInfo.packageName,
|
||||
remote: true,
|
||||
);
|
||||
final artifactsForTarget = <Artifact>[];
|
||||
|
||||
for (final artifact in requiredArtifacts) {
|
||||
final fileName = PrecompileBinaries.fileName(target, artifact);
|
||||
final downloadedPath = path.join(downloadedArtifactsDir, fileName);
|
||||
if (!File(downloadedPath).existsSync()) {
|
||||
final signatureFileName =
|
||||
PrecompileBinaries.signatureFileName(target, artifact);
|
||||
await _tryDownloadArtifacts(
|
||||
crateHash: crateHash,
|
||||
fileName: fileName,
|
||||
signatureFileName: signatureFileName,
|
||||
finalPath: downloadedPath,
|
||||
);
|
||||
}
|
||||
if (File(downloadedPath).existsSync()) {
|
||||
artifactsForTarget.add(Artifact(
|
||||
path: downloadedPath,
|
||||
finalFileName: artifact,
|
||||
));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Only provide complete set of artifacts.
|
||||
if (artifactsForTarget.length == requiredArtifacts.length) {
|
||||
_log.fine('Found precompiled artifacts for $target');
|
||||
res[target] = artifactsForTarget;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static Future<Response> _get(Uri url, {Map<String, String>? headers}) async {
|
||||
int attempt = 0;
|
||||
const maxAttempts = 10;
|
||||
while (true) {
|
||||
try {
|
||||
return await get(url, headers: headers);
|
||||
} on SocketException catch (e) {
|
||||
// Try to detect reset by peer error and retry.
|
||||
if (attempt++ < maxAttempts &&
|
||||
(e.osError?.errorCode == 54 || e.osError?.errorCode == 10054)) {
|
||||
_log.severe(
|
||||
'Failed to download $url: $e, attempt $attempt of $maxAttempts, will retry...');
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
continue;
|
||||
} else {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _tryDownloadArtifacts({
|
||||
required String crateHash,
|
||||
required String fileName,
|
||||
required String signatureFileName,
|
||||
required String finalPath,
|
||||
}) async {
|
||||
final precompiledBinaries = environment.crateOptions.precompiledBinaries!;
|
||||
final prefix = precompiledBinaries.uriPrefix;
|
||||
final url = Uri.parse('$prefix$crateHash/$fileName');
|
||||
final signatureUrl = Uri.parse('$prefix$crateHash/$signatureFileName');
|
||||
_log.fine('Downloading signature from $signatureUrl');
|
||||
final signature = await _get(signatureUrl);
|
||||
if (signature.statusCode == 404) {
|
||||
_log.warning(
|
||||
'Precompiled binaries not available for crate hash $crateHash ($fileName)');
|
||||
return;
|
||||
}
|
||||
if (signature.statusCode != 200) {
|
||||
_log.severe(
|
||||
'Failed to download signature $signatureUrl: status ${signature.statusCode}');
|
||||
return;
|
||||
}
|
||||
_log.fine('Downloading binary from $url');
|
||||
final res = await _get(url);
|
||||
if (res.statusCode != 200) {
|
||||
_log.severe('Failed to download binary $url: status ${res.statusCode}');
|
||||
return;
|
||||
}
|
||||
if (verify(
|
||||
precompiledBinaries.publicKey, res.bodyBytes, signature.bodyBytes)) {
|
||||
File(finalPath).writeAsBytesSync(res.bodyBytes);
|
||||
} else {
|
||||
_log.shout('Signature verification failed! Ignoring binary.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum AritifactType {
|
||||
staticlib,
|
||||
dylib,
|
||||
}
|
||||
|
||||
AritifactType artifactTypeForTarget(Target target) {
|
||||
if (target.darwinPlatform != null) {
|
||||
return AritifactType.staticlib;
|
||||
} else {
|
||||
return AritifactType.dylib;
|
||||
}
|
||||
}
|
||||
|
||||
List<String> getArtifactNames({
|
||||
required Target target,
|
||||
required String libraryName,
|
||||
required bool remote,
|
||||
AritifactType? aritifactType,
|
||||
}) {
|
||||
aritifactType ??= artifactTypeForTarget(target);
|
||||
if (target.darwinArch != null) {
|
||||
if (aritifactType == AritifactType.staticlib) {
|
||||
return ['lib$libraryName.a'];
|
||||
} else {
|
||||
return ['lib$libraryName.dylib'];
|
||||
}
|
||||
} else if (target.rust.contains('-windows-')) {
|
||||
if (aritifactType == AritifactType.staticlib) {
|
||||
return ['$libraryName.lib'];
|
||||
} else {
|
||||
return [
|
||||
'$libraryName.dll',
|
||||
'$libraryName.dll.lib',
|
||||
if (!remote) '$libraryName.pdb'
|
||||
];
|
||||
}
|
||||
} else if (target.rust.contains('-linux-')) {
|
||||
if (aritifactType == AritifactType.staticlib) {
|
||||
return ['lib$libraryName.a'];
|
||||
} else {
|
||||
return ['lib$libraryName.so'];
|
||||
}
|
||||
} else {
|
||||
throw Exception("Unsupported target: ${target.rust}");
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user