Compare commits

..

10 Commits

Author SHA1 Message Date
Neeraj
b5d725e139 [auth] Bump version (#6592)
## Description

## Tests
2025-07-21 11:48:37 +05:30
Neeraj Gupta
5750d72c5a [auth] Bump version 2025-07-21 11:48:10 +05:30
Neeraj
00a430927f [mobile/photos] New translations (#6590)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-app)
2025-07-21 10:55:11 +05:30
Neeraj
ab57a1f8fe [auth] New translations (#6591)
New translations from
[Crowdin](https://crowdin.com/project/ente-authenticator-app)
2025-07-21 10:46:39 +05:30
Manav Rathi
cfdeb475ef [web] New translations (#6589)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-07-21 08:22:34 +05:30
Crowdin Bot
1f0f240f97 New Crowdin translations by GitHub Action 2025-07-21 01:18:10 +00:00
Crowdin Bot
2ff5058a3e New Crowdin translations by GitHub Action 2025-07-21 01:05:20 +00:00
Crowdin Bot
641dfdd11e New Crowdin translations by GitHub Action 2025-07-21 00:45:09 +00:00
Aman Raj Singh Mourya
b3827dd812 [auth] Add MangaDex icon (#6571)
This PR adds the MangaDex icon for auth
2025-07-19 11:51:52 +05:30
Sven
087ba629e0 add MangaDex icon and metadata to custom icons 2025-07-18 22:33:24 +02:00
137 changed files with 420 additions and 9010 deletions

Submodule auth/assets/simple-icons deleted from 6dcfdc2f58

Submodule auth/flutter deleted from 5874a72aa4

View File

@@ -739,6 +739,10 @@
"lu.ma"
]
},
{
"title": "MangaDex",
"slug": "mangadex"
},
{
"title": "Marketplace.tf",
"slug": "marketplacedottf"

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -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": "Тып",

View File

@@ -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"
}

View File

@@ -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",

View File

@@ -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>",

View File

@@ -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" />

View File

@@ -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:

View File

@@ -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>
```

View File

@@ -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

View File

@@ -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

View File

@@ -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();
// }
// }
// }

View File

@@ -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);
});
}

View File

@@ -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:

View File

@@ -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",

View File

@@ -1,3 +1,4 @@
import "dart:io";
import 'package:photos/core/cache/lru_map.dart';

View File

@@ -58,7 +58,7 @@ bool isHandledSyncError(Object errObj) {
class LockAlreadyAcquiredError extends Error {}
class LockFreedError extends Error {}
class LockFreedError extends Error{}
class UnauthorizedError extends Error {}

View File

@@ -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)";
}
}

View File

@@ -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());
}

View File

@@ -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');

View File

@@ -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

View File

@@ -35,3 +35,4 @@ final $typed_data.Uint8List centerBoxDescriptor = $convert.base64Decode(
'CglDZW50ZXJCb3gSEQoBeBgBIAEoAkgAUgF4iAEBEhEKAXkYAiABKAJIAVIBeYgBARIbCgZoZW'
'lnaHQYAyABKAJIAlIGaGVpZ2h0iAEBEhkKBXdpZHRoGAQgASgCSANSBXdpZHRoiAEBQgQKAl94'
'QgQKAl95QgkKB19oZWlnaHRCCAoGX3dpZHRo');

View File

@@ -11,3 +11,4 @@
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
export 'box.pb.dart';

View File

@@ -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');

View File

@@ -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

View File

@@ -30,3 +30,4 @@ const EPoint$json = {
final $typed_data.Uint8List ePointDescriptor = $convert.base64Decode(
'CgZFUG9pbnQSEQoBeBgBIAEoAkgAUgF4iAEBEhEKAXkYAiABKAJIAVIBeYgBAUIECgJfeEIECg'
'JfeQ==');

View File

@@ -11,3 +11,4 @@
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
export 'point.pb.dart';

View File

@@ -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');

View File

@@ -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

View File

@@ -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');

View File

@@ -11,3 +11,4 @@
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
export 'vector.pb.dart';

View File

@@ -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');

View File

@@ -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

View File

@@ -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=');

View File

@@ -11,3 +11,4 @@
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
export 'face.pb.dart';

View File

@@ -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');

View File

@@ -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

View File

@@ -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==');

View File

@@ -11,3 +11,4 @@
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
export 'fileml.pb.dart';

View File

@@ -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"
}

View File

@@ -1788,5 +1788,7 @@
"cLDesc5": "Теперь вы будете получать уведомления о всех днях рождениях, которые вы сохранили на Ente, а также коллекцию их лучших фотографий.",
"cLTitle6": "Возобновляемые загрузки и скачивания",
"cLDesc6": "Больше не нужно ждать завершения загрузки/скачивания, прежде чем закрыть приложение. Все загрузки и скачивания теперь можно приостановить и возобновить с того места, где вы остановились.",
"indexingPausedStatusDescription": "Индексирование приостановлено. Оно автоматически возобновится, когда устройство будет готово. Устройство считается готовым, когда уровень заряда батареи, её состояние и температура находятся в пределах нормы."
"indexingPausedStatusDescription": "Индексирование приостановлено. Оно автоматически возобновится, когда устройство будет готово. Устройство считается готовым, когда уровень заряда батареи, её состояние и температура находятся в пределах нормы.",
"faceThumbnailGenerationFailed": "Не удалось создать миниатюры лиц",
"fileAnalysisFailed": "Не удалось проанализировать файл"
}

View File

@@ -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 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",

View File

@@ -1788,5 +1788,7 @@
"cLDesc5": "您现在将收到 Ente 上保存的所有生日的可选退出通知,同时附上他们最佳照片的合集。",
"cLTitle6": "可恢复的上传和下载",
"cLDesc6": "无需等待上传/下载完成即可关闭应用程序。所有上传和下载现在都可以中途暂停,并从中断处继续。",
"indexingPausedStatusDescription": "索引已暂停。待设备准备就绪后,索引将自动恢复。当设备的电池电量、电池健康度和温度状态处于健康范围内时,设备即被视为准备就绪。"
"indexingPausedStatusDescription": "索引已暂停。待设备准备就绪后,索引将自动恢复。当设备的电池电量、电池健康度和温度状态处于健康范围内时,设备即被视为准备就绪。",
"faceThumbnailGenerationFailed": "无法生成人脸缩略图",
"fileAnalysisFailed": "无法分析文件"
}

View File

@@ -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();

View File

@@ -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;

View File

@@ -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)],
),
);
}

View File

@@ -1 +1 @@
const imageEmbeddingsKey = "imageEmbeddings";
const imageEmbeddingsKey = "imageEmbeddings";

View File

@@ -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 {}

View File

@@ -3,4 +3,4 @@ class QueryResult {
final double score;
QueryResult(this.id, this.score);
}
}

View File

@@ -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 " +

View File

@@ -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);

View File

@@ -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

View File

@@ -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>)>();
}

View File

@@ -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(

View File

@@ -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.
///

View File

@@ -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) {

View File

@@ -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(),

View File

@@ -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",

View File

@@ -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";

View File

@@ -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";

View File

@@ -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,

View File

@@ -1,3 +1,4 @@
import 'package:flutter/material.dart';
import "package:photos/generated/l10n.dart";
import 'package:photos/models/file/file.dart';

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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";

View File

@@ -58,8 +58,6 @@ class FlagService {
bool get enableMobMultiPart => flags.enableMobMultiPart || internalUser;
bool get enableVectorDb => flags.internalUser;
String get castUrl => flags.castUrl;
bool hasSyncedAccountFlags() {

View File

@@ -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:

View File

@@ -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

View File

@@ -1 +0,0 @@
/target

View File

@@ -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"

View File

@@ -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)'] }

View File

@@ -1,2 +0,0 @@
pub mod simple;
pub mod usearch_api;

View File

@@ -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();
}

View File

@@ -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

View File

@@ -1,2 +0,0 @@
pub mod api;
mod frb_generated;

View File

@@ -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/

View File

@@ -1 +0,0 @@
Please ignore this folder, which is just glue to build Rust with Flutter.

View File

@@ -1,9 +0,0 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.cxx

View File

@@ -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"
}

View File

@@ -1 +0,0 @@
rootProject.name = 'rust_lib_photos'

View File

@@ -1,3 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.flutter_rust_bridge.rust_lib_photos">
</manifest>

View File

@@ -1,4 +0,0 @@
target
.dart_tool
*.iml
!pubspec.lock

View File

@@ -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.

View File

@@ -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.

View File

@@ -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"

View File

@@ -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/`.

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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