Merge branch 'mobile_face' of https://github.com/ente-io/auth into mobile_face
This commit is contained in:
commit
f459b1c2dd
40 changed files with 671 additions and 2031 deletions
|
@ -46,7 +46,7 @@ You can alternatively install the build from PlayStore or F-Droid.
|
|||
|
||||
## 🧑💻 Building from source
|
||||
|
||||
1. [Install Flutter v3.13.4](https://flutter.dev/docs/get-started/install).
|
||||
1. [Install Flutter v3.16.9](https://flutter.dev/docs/get-started/install).
|
||||
|
||||
2. Pull in all submodules with `git submodule update --init --recursive`
|
||||
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
unknown
|
||||
person
|
||||
bicycle
|
||||
car
|
||||
motorcycle
|
||||
airplane
|
||||
bus
|
||||
train
|
||||
truck
|
||||
boat
|
||||
traffic light
|
||||
fire hydrant
|
||||
unknown
|
||||
stop sign
|
||||
parking meter
|
||||
bench
|
||||
bird
|
||||
cat
|
||||
dog
|
||||
horse
|
||||
sheep
|
||||
cow
|
||||
elephant
|
||||
bear
|
||||
zebra
|
||||
giraffe
|
||||
unknown
|
||||
backpack
|
||||
umbrella
|
||||
unknown
|
||||
unknown
|
||||
handbag
|
||||
tie
|
||||
suitcase
|
||||
frisbee
|
||||
skis
|
||||
snowboard
|
||||
sports ball
|
||||
kite
|
||||
baseball bat
|
||||
baseball glove
|
||||
skateboard
|
||||
surfboard
|
||||
tennis racket
|
||||
bottle
|
||||
unknown
|
||||
wine glass
|
||||
cup
|
||||
fork
|
||||
knife
|
||||
spoon
|
||||
bowl
|
||||
banana
|
||||
apple
|
||||
sandwich
|
||||
orange
|
||||
broccoli
|
||||
carrot
|
||||
hot dog
|
||||
pizza
|
||||
donut
|
||||
cake
|
||||
chair
|
||||
couch
|
||||
potted plant
|
||||
bed
|
||||
unknown
|
||||
dining table
|
||||
unknown
|
||||
unknown
|
||||
toilet
|
||||
unknown
|
||||
tv
|
||||
laptop
|
||||
mouse
|
||||
remote
|
||||
keyboard
|
||||
cell phone
|
||||
microwave
|
||||
oven
|
||||
toaster
|
||||
sink
|
||||
refrigerator
|
||||
unknown
|
||||
book
|
||||
clock
|
||||
vase
|
||||
scissors
|
||||
teddy bear
|
||||
hair drier
|
||||
toothbrush
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
@ -1,30 +0,0 @@
|
|||
waterfall
|
||||
snow
|
||||
landscape
|
||||
underwater
|
||||
architecture
|
||||
sunset / sunrise
|
||||
blue sky
|
||||
cloudy sky
|
||||
greenery
|
||||
autumn leaves
|
||||
portrait
|
||||
flower
|
||||
night shot
|
||||
stage concert
|
||||
fireworks
|
||||
candle light
|
||||
neon lights
|
||||
indoor
|
||||
backlight
|
||||
text documents
|
||||
qr images
|
||||
group portrait
|
||||
computer screens
|
||||
kids
|
||||
dog
|
||||
cat
|
||||
macro
|
||||
food
|
||||
beach
|
||||
mountain
|
Binary file not shown.
Binary file not shown.
|
@ -1,8 +1,11 @@
|
|||
PODS:
|
||||
- background_fetch (1.2.1):
|
||||
- background_fetch (1.3.2):
|
||||
- Flutter
|
||||
- battery_info (0.0.1):
|
||||
- Flutter
|
||||
- bonsoir_darwin (3.0.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- connectivity_plus (0.0.1):
|
||||
- Flutter
|
||||
- ReachabilitySwift
|
||||
|
@ -10,38 +13,38 @@ PODS:
|
|||
- Flutter
|
||||
- file_saver (0.0.1):
|
||||
- Flutter
|
||||
- Firebase/CoreOnly (10.18.0):
|
||||
- FirebaseCore (= 10.18.0)
|
||||
- Firebase/Messaging (10.18.0):
|
||||
- Firebase/CoreOnly (10.22.0):
|
||||
- FirebaseCore (= 10.22.0)
|
||||
- Firebase/Messaging (10.22.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseMessaging (~> 10.18.0)
|
||||
- firebase_core (2.24.2):
|
||||
- Firebase/CoreOnly (= 10.18.0)
|
||||
- FirebaseMessaging (~> 10.22.0)
|
||||
- firebase_core (2.27.0):
|
||||
- Firebase/CoreOnly (= 10.22.0)
|
||||
- Flutter
|
||||
- firebase_messaging (14.7.10):
|
||||
- Firebase/Messaging (= 10.18.0)
|
||||
- firebase_messaging (14.7.19):
|
||||
- Firebase/Messaging (= 10.22.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- FirebaseCore (10.18.0):
|
||||
- FirebaseCore (10.22.0):
|
||||
- FirebaseCoreInternal (~> 10.0)
|
||||
- GoogleUtilities/Environment (~> 7.12)
|
||||
- GoogleUtilities/Logger (~> 7.12)
|
||||
- FirebaseCoreInternal (10.21.0):
|
||||
- FirebaseCoreInternal (10.24.0):
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.8)"
|
||||
- FirebaseInstallations (10.21.0):
|
||||
- FirebaseInstallations (10.24.0):
|
||||
- FirebaseCore (~> 10.0)
|
||||
- GoogleUtilities/Environment (~> 7.8)
|
||||
- GoogleUtilities/UserDefaults (~> 7.8)
|
||||
- PromisesObjC (~> 2.1)
|
||||
- FirebaseMessaging (10.18.0):
|
||||
- FirebaseMessaging (10.22.0):
|
||||
- FirebaseCore (~> 10.0)
|
||||
- FirebaseInstallations (~> 10.0)
|
||||
- GoogleDataTransport (~> 9.2)
|
||||
- GoogleDataTransport (~> 9.3)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.8)
|
||||
- GoogleUtilities/Environment (~> 7.8)
|
||||
- GoogleUtilities/Reachability (~> 7.8)
|
||||
- GoogleUtilities/UserDefaults (~> 7.8)
|
||||
- nanopb (< 2.30910.0, >= 2.30908.0)
|
||||
- nanopb (< 2.30911.0, >= 2.30908.0)
|
||||
- fk_user_agent (2.0.0):
|
||||
- Flutter
|
||||
- Flutter (1.0.0)
|
||||
|
@ -72,27 +75,35 @@ PODS:
|
|||
- fluttertoast (0.0.2):
|
||||
- Flutter
|
||||
- Toast
|
||||
- GoogleDataTransport (9.3.0):
|
||||
- GoogleDataTransport (9.4.1):
|
||||
- GoogleUtilities/Environment (~> 7.7)
|
||||
- nanopb (< 2.30910.0, >= 2.30908.0)
|
||||
- nanopb (< 2.30911.0, >= 2.30908.0)
|
||||
- PromisesObjC (< 3.0, >= 1.2)
|
||||
- GoogleUtilities/AppDelegateSwizzler (7.12.0):
|
||||
- GoogleUtilities/AppDelegateSwizzler (7.13.0):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network
|
||||
- GoogleUtilities/Environment (7.12.0):
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Environment (7.13.0):
|
||||
- GoogleUtilities/Privacy
|
||||
- PromisesObjC (< 3.0, >= 1.2)
|
||||
- GoogleUtilities/Logger (7.12.0):
|
||||
- GoogleUtilities/Logger (7.13.0):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Network (7.12.0):
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Network (7.13.0):
|
||||
- GoogleUtilities/Logger
|
||||
- "GoogleUtilities/NSData+zlib"
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Reachability
|
||||
- "GoogleUtilities/NSData+zlib (7.12.0)"
|
||||
- GoogleUtilities/Reachability (7.12.0):
|
||||
- "GoogleUtilities/NSData+zlib (7.13.0)":
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Privacy (7.13.0)
|
||||
- GoogleUtilities/Reachability (7.13.0):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/UserDefaults (7.12.0):
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/UserDefaults (7.13.0):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Privacy
|
||||
- home_widget (0.0.1):
|
||||
- Flutter
|
||||
- image_editor_common (1.0.0):
|
||||
|
@ -116,6 +127,8 @@ PODS:
|
|||
- libwebp/sharpyuv (1.3.2)
|
||||
- libwebp/webp (1.3.2):
|
||||
- libwebp/sharpyuv
|
||||
- local_auth_darwin (0.0.1):
|
||||
- Flutter
|
||||
- local_auth_ios (0.0.1):
|
||||
- Flutter
|
||||
- Mantle (2.2.0):
|
||||
|
@ -133,11 +146,11 @@ PODS:
|
|||
- Flutter
|
||||
- move_to_background (0.0.1):
|
||||
- Flutter
|
||||
- nanopb (2.30909.1):
|
||||
- nanopb/decode (= 2.30909.1)
|
||||
- nanopb/encode (= 2.30909.1)
|
||||
- nanopb/decode (2.30909.1)
|
||||
- nanopb/encode (2.30909.1)
|
||||
- nanopb (2.30910.0):
|
||||
- nanopb/decode (= 2.30910.0)
|
||||
- nanopb/encode (= 2.30910.0)
|
||||
- nanopb/decode (2.30910.0)
|
||||
- nanopb/encode (2.30910.0)
|
||||
- onnxruntime (0.0.1):
|
||||
- Flutter
|
||||
- onnxruntime-objc (= 1.15.1)
|
||||
|
@ -154,30 +167,30 @@ PODS:
|
|||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- permission_handler_apple (9.1.1):
|
||||
- permission_handler_apple (9.3.0):
|
||||
- Flutter
|
||||
- photo_manager (2.0.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- PromisesObjC (2.3.1)
|
||||
- ReachabilitySwift (5.0.0)
|
||||
- receive_sharing_intent (1.6.7):
|
||||
- PromisesObjC (2.4.0)
|
||||
- ReachabilitySwift (5.2.1)
|
||||
- receive_sharing_intent (1.6.8):
|
||||
- Flutter
|
||||
- screen_brightness_ios (0.1.0):
|
||||
- Flutter
|
||||
- SDWebImage (5.18.11):
|
||||
- SDWebImage/Core (= 5.18.11)
|
||||
- SDWebImage/Core (5.18.11)
|
||||
- SDWebImage (5.19.1):
|
||||
- SDWebImage/Core (= 5.19.1)
|
||||
- SDWebImage/Core (5.19.1)
|
||||
- SDWebImageWebPCoder (0.14.5):
|
||||
- libwebp (~> 1.0)
|
||||
- SDWebImage/Core (~> 5.17)
|
||||
- Sentry/HybridSDK (8.18.0):
|
||||
- SentryPrivate (= 8.18.0)
|
||||
- sentry_flutter (0.0.1):
|
||||
- Sentry/HybridSDK (8.21.0):
|
||||
- SentryPrivate (= 8.21.0)
|
||||
- sentry_flutter (7.19.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- Sentry/HybridSDK (= 8.18.0)
|
||||
- SentryPrivate (8.18.0)
|
||||
- Sentry/HybridSDK (= 8.21.0)
|
||||
- SentryPrivate (8.21.0)
|
||||
- share_plus (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
|
@ -201,29 +214,7 @@ PODS:
|
|||
- sqlite3/fts5
|
||||
- sqlite3/perf-threadsafe
|
||||
- sqlite3/rtree
|
||||
- TensorFlowLiteC (2.12.0):
|
||||
- TensorFlowLiteC/Core (= 2.12.0)
|
||||
- TensorFlowLiteC/Core (2.12.0)
|
||||
- TensorFlowLiteC/CoreML (2.12.0):
|
||||
- TensorFlowLiteC/Core
|
||||
- TensorFlowLiteC/Metal (2.12.0):
|
||||
- TensorFlowLiteC/Core
|
||||
- TensorFlowLiteSwift (2.12.0):
|
||||
- TensorFlowLiteSwift/Core (= 2.12.0)
|
||||
- TensorFlowLiteSwift/Core (2.12.0):
|
||||
- TensorFlowLiteC (= 2.12.0)
|
||||
- TensorFlowLiteSwift/CoreML (2.12.0):
|
||||
- TensorFlowLiteC/CoreML (= 2.12.0)
|
||||
- TensorFlowLiteSwift/Core (= 2.12.0)
|
||||
- TensorFlowLiteSwift/Metal (2.12.0):
|
||||
- TensorFlowLiteC/Metal (= 2.12.0)
|
||||
- TensorFlowLiteSwift/Core (= 2.12.0)
|
||||
- tflite_flutter (0.0.1):
|
||||
- Flutter
|
||||
- TensorFlowLiteSwift (= 2.12.0)
|
||||
- TensorFlowLiteSwift/CoreML (= 2.12.0)
|
||||
- TensorFlowLiteSwift/Metal (= 2.12.0)
|
||||
- Toast (4.1.0)
|
||||
- Toast (4.1.1)
|
||||
- uni_links (0.0.1):
|
||||
- Flutter
|
||||
- url_launcher_ios (0.0.1):
|
||||
|
@ -242,6 +233,7 @@ PODS:
|
|||
DEPENDENCIES:
|
||||
- background_fetch (from `.symlinks/plugins/background_fetch/ios`)
|
||||
- battery_info (from `.symlinks/plugins/battery_info/ios`)
|
||||
- bonsoir_darwin (from `.symlinks/plugins/bonsoir_darwin/darwin`)
|
||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||
- file_saver (from `.symlinks/plugins/file_saver/ios`)
|
||||
|
@ -263,6 +255,7 @@ DEPENDENCIES:
|
|||
- in_app_purchase_storekit (from `.symlinks/plugins/in_app_purchase_storekit/darwin`)
|
||||
- integration_test (from `.symlinks/plugins/integration_test/ios`)
|
||||
- isar_flutter_libs (from `.symlinks/plugins/isar_flutter_libs/ios`)
|
||||
- local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`)
|
||||
- local_auth_ios (from `.symlinks/plugins/local_auth_ios/ios`)
|
||||
- media_extension (from `.symlinks/plugins/media_extension/ios`)
|
||||
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
|
||||
|
@ -322,6 +315,8 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/background_fetch/ios"
|
||||
battery_info:
|
||||
:path: ".symlinks/plugins/battery_info/ios"
|
||||
bonsoir_darwin:
|
||||
:path: ".symlinks/plugins/bonsoir_darwin/darwin"
|
||||
connectivity_plus:
|
||||
:path: ".symlinks/plugins/connectivity_plus/ios"
|
||||
device_info_plus:
|
||||
|
@ -364,6 +359,8 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/integration_test/ios"
|
||||
isar_flutter_libs:
|
||||
:path: ".symlinks/plugins/isar_flutter_libs/ios"
|
||||
local_auth_darwin:
|
||||
:path: ".symlinks/plugins/local_auth_darwin/darwin"
|
||||
local_auth_ios:
|
||||
:path: ".symlinks/plugins/local_auth_ios/ios"
|
||||
media_extension:
|
||||
|
@ -420,20 +417,21 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
background_fetch: 896944864b038d2837fc750d470e9841e1e6a363
|
||||
background_fetch: 2319bf7e18237b4b269430b7f14d177c0df09c5a
|
||||
battery_info: 09f5c9ee65394f2291c8c6227bedff345b8a730c
|
||||
connectivity_plus: 53efb943fc2882c8512d84c45707bcabc4c36076
|
||||
bonsoir_darwin: 127bdc632fdc154ae2f277a4d5c86a6212bc75be
|
||||
connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a
|
||||
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
|
||||
file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808
|
||||
Firebase: 414ad272f8d02dfbf12662a9d43f4bba9bec2a06
|
||||
firebase_core: 0af4a2b24f62071f9bf283691c0ee41556dcb3f5
|
||||
firebase_messaging: 90e8a6db84b6e1e876cebce4f30f01dc495e7014
|
||||
FirebaseCore: 2322423314d92f946219c8791674d2f3345b598f
|
||||
FirebaseCoreInternal: 43c1788eaeee9d1b97caaa751af567ce11010d00
|
||||
FirebaseInstallations: 390ea1d10a4d02b20c965cbfd527ee9b3b412acb
|
||||
FirebaseMessaging: 9bc34a98d2e0237e1b121915120d4d48ddcf301e
|
||||
Firebase: 797fd7297b7e1be954432743a0b3f90038e45a71
|
||||
firebase_core: 100945864b4aedce3cfef0c62ab864858bf013cf
|
||||
firebase_messaging: e65050bf9b187511d80ea3a4de7cf5573d2c7543
|
||||
FirebaseCore: 0326ec9b05fbed8f8716cddbf0e36894a13837f7
|
||||
FirebaseCoreInternal: bcb5acffd4ea05e12a783ecf835f2210ce3dc6af
|
||||
FirebaseInstallations: 8f581fca6478a50705d2bd2abd66d306e0f5736e
|
||||
FirebaseMessaging: 9f71037fd9db3376a4caa54e5a3949d1027b4b6e
|
||||
fk_user_agent: 1f47ec39291e8372b1d692b50084b0d54103c545
|
||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_email_sender: 02d7443217d8c41483223627972bfdc09f74276b
|
||||
flutter_image_compress: 5a5e9aee05b6553048b8df1c3bc456d0afaac433
|
||||
flutter_inappwebview: 3d32228f1304635e7c028b0d4252937730bbc6cf
|
||||
|
@ -443,15 +441,16 @@ SPEC CHECKSUMS:
|
|||
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
|
||||
flutter_sodium: c84426b4de738514b5b66cfdeb8a06634e72fe0b
|
||||
fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265
|
||||
GoogleDataTransport: 57c22343ab29bc686febbf7cbb13bad167c2d8fe
|
||||
GoogleUtilities: 0759d1a57ebb953965c2dfe0ba4c82e95ccc2e34
|
||||
GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a
|
||||
GoogleUtilities: d053d902a8edaa9904e1bd00c37535385b8ed152
|
||||
home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57
|
||||
image_editor_common: d6f6644ae4a6de80481e89fe6d0a8c49e30b4b43
|
||||
in_app_purchase_storekit: 9e9931234f0adcf71ae323f8c83785b96030edf1
|
||||
in_app_purchase_storekit: 0e4b3c2e43ba1e1281f4f46dd71b0593ce529892
|
||||
integration_test: 13825b8a9334a850581300559b8839134b124670
|
||||
isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073
|
||||
libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009
|
||||
local_auth_ios: 1ba1475238daa33a6ffa2a29242558437be435ac
|
||||
local_auth_darwin: c7e464000a6a89e952235699e32b329457608d98
|
||||
local_auth_ios: 5046a18c018dd973247a0564496c8898dbb5adf9
|
||||
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
|
||||
media_extension: 6d30dc1431ebaa63f43c397c37917b1a0a597a4c
|
||||
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
|
||||
|
@ -459,7 +458,7 @@ SPEC CHECKSUMS:
|
|||
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
|
||||
motionphoto: d4a432b8c8f22fb3ad966258597c0103c9c5ff16
|
||||
move_to_background: 39a5b79b26d577b0372cbe8a8c55e7aa9fcd3a2d
|
||||
nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5
|
||||
nanopb: 438bc412db1928dac798aa6fd75726007be04262
|
||||
onnxruntime: e9346181d75b8dea8733bdae512a22c298962e00
|
||||
onnxruntime-c: ebdcfd8650bcbd10121c125262f99dea681b92a3
|
||||
onnxruntime-objc: ae7acec7a3d03eaf072d340afed7a35635c1c2a6
|
||||
|
@ -467,33 +466,30 @@ SPEC CHECKSUMS:
|
|||
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
|
||||
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
|
||||
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
|
||||
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
|
||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||
photo_manager: 4f6810b7dfc4feb03b461ac1a70dacf91fba7604
|
||||
PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4
|
||||
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
||||
receive_sharing_intent: 9ca20ae908f83c36ddaaaa8c9bd30ce4700495e8
|
||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||
ReachabilitySwift: 5ae15e16814b5f9ef568963fb2c87aeb49158c66
|
||||
receive_sharing_intent: 6837b01768e567fe8562182397bf43d63d8c6437
|
||||
screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
|
||||
SDWebImage: a3ba0b8faac7228c3c8eadd1a55c9c9fe5e16457
|
||||
SDWebImage: 40b0b4053e36c660a764958bff99eed16610acbb
|
||||
SDWebImageWebPCoder: c94f09adbca681822edad9e532ac752db713eabf
|
||||
Sentry: 8984a4ffb2b9bd2894d74fb36e6f5833865bc18e
|
||||
sentry_flutter: c87a0556eeb6cbf7f9f924d30e878bdedf22d364
|
||||
SentryPrivate: 2f0c9ba4c3fc993f70eab6ca95673509561e0085
|
||||
Sentry: ebc12276bd17613a114ab359074096b6b3725203
|
||||
sentry_flutter: 88ebea3f595b0bc16acc5bedacafe6d60c12dcd5
|
||||
SentryPrivate: d651efb234cf385ec9a1cdd3eff94b5e78a0e0fe
|
||||
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
|
||||
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
|
||||
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
||||
sqlite3: 73b7fc691fdc43277614250e04d183740cb15078
|
||||
sqlite3_flutter_libs: af0e8fe9bce48abddd1ffdbbf839db0302d72d80
|
||||
TensorFlowLiteC: 20785a69299185a379ba9852b6625f00afd7984a
|
||||
TensorFlowLiteSwift: 3a4928286e9e35bdd3e17970f48e53c80d25e793
|
||||
tflite_flutter: 9433d086a3060431bbc9f3c7c20d017db0e72d08
|
||||
Toast: ec33c32b8688982cecc6348adeae667c1b9938da
|
||||
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
|
||||
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
|
||||
url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812
|
||||
video_player_avfoundation: e9e6f9cae7d7a6d9b43519b0aab382bca60fcfd1
|
||||
url_launcher_ios: 6116280ddcfe98ab8820085d8d76ae7449447586
|
||||
video_player_avfoundation: 02011213dab73ae3687df27ce441fbbcc82b5579
|
||||
video_thumbnail: c4e2a3c539e247d4de13cd545344fd2d26ffafd1
|
||||
volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9
|
||||
wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47
|
||||
|
||||
PODFILE CHECKSUM: c1a8f198a245ed1f10e40b617efdb129b021b225
|
||||
|
||||
COCOAPODS: 1.14.3
|
||||
COCOAPODS: 1.15.2
|
||||
|
|
|
@ -174,6 +174,7 @@
|
|||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
ABF2FD2FD606DC6DD54BD9AB /* [CP] Embed Pods Frameworks */,
|
||||
F5BF2E85B889CF8483C26F35 /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
@ -292,6 +293,7 @@
|
|||
"${BUILT_PRODUCTS_DIR}/Toast/Toast.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/background_fetch/background_fetch.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/battery_info/battery_info.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/bonsoir_darwin/bonsoir_darwin.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/connectivity_plus/connectivity_plus.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/device_info_plus/device_info_plus.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/file_saver/file_saver.framework",
|
||||
|
@ -311,6 +313,7 @@
|
|||
"${BUILT_PRODUCTS_DIR}/integration_test/integration_test.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/isar_flutter_libs/isar_flutter_libs.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/libwebp/libwebp.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/local_auth_darwin/local_auth_darwin.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/local_auth_ios/local_auth_ios.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/media_extension/media_extension.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/media_kit_libs_ios_video/media_kit_libs_ios_video.framework",
|
||||
|
@ -375,6 +378,7 @@
|
|||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Toast.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/background_fetch.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/battery_info.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/bonsoir_darwin.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity_plus.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info_plus.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_saver.framework",
|
||||
|
@ -394,6 +398,7 @@
|
|||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/integration_test.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/isar_flutter_libs.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/local_auth_darwin.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/local_auth_ios.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/media_extension.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/media_kit_libs_ios_video.framework",
|
||||
|
@ -466,6 +471,24 @@
|
|||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
F5BF2E85B889CF8483C26F35 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/permission_handler_apple/permission_handler_apple_privacy.bundle",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/permission_handler_apple_privacy.bundle",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
|
|
|
@ -181,6 +181,7 @@ extension DeviceFiles on FilesDB {
|
|||
final Set<String> existingPathIds = await getDevicePathIDs();
|
||||
for (Tuple2<AssetPathEntity, String> tup in devicePathInfo) {
|
||||
final AssetPathEntity pathEntity = tup.item1;
|
||||
final assetCount = await pathEntity.assetCountAsync;
|
||||
final String localID = tup.item2;
|
||||
final bool shouldUpdate = existingPathIds.contains(pathEntity.id);
|
||||
if (shouldUpdate) {
|
||||
|
@ -190,11 +191,11 @@ extension DeviceFiles on FilesDB {
|
|||
[
|
||||
pathEntity.name,
|
||||
localID,
|
||||
pathEntity.assetCount,
|
||||
assetCount,
|
||||
pathEntity.id,
|
||||
pathEntity.name,
|
||||
localID,
|
||||
pathEntity.assetCount,
|
||||
assetCount,
|
||||
],
|
||||
);
|
||||
if (rowUpdated > 0) {
|
||||
|
@ -208,7 +209,7 @@ extension DeviceFiles on FilesDB {
|
|||
{
|
||||
"id": pathEntity.id,
|
||||
"name": pathEntity.name,
|
||||
"count": pathEntity.assetCount,
|
||||
"count": assetCount,
|
||||
"cover_id": localID,
|
||||
"should_backup": shouldBackup ? _sqlBoolTrue : _sqlBoolFalse,
|
||||
},
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
class YOLOFaceInterpreterInitializationException implements Exception {}
|
||||
|
||||
class YOLOFaceInterpreterRunException implements Exception {}
|
|
@ -11,9 +11,9 @@ import 'package:logging/logging.dart';
|
|||
import 'package:onnxruntime/onnxruntime.dart';
|
||||
import "package:photos/face/model/dimension.dart";
|
||||
import 'package:photos/services/machine_learning/face_ml/face_detection/detection.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_detection/face_detection_exceptions.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_detection/naive_non_max_suppression.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_detection/yolov5face/yolo_face_detection_exceptions.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_detection/yolov5face/yolo_filter_extract_detections.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_detection/yolo_filter_extract_detections.dart';
|
||||
import "package:photos/services/remote_assets_service.dart";
|
||||
import "package:photos/utils/image_ml_isolate.dart";
|
||||
import "package:photos/utils/image_ml_util.dart";
|
||||
|
@ -21,22 +21,26 @@ import "package:synchronized/synchronized.dart";
|
|||
|
||||
enum FaceDetectionOperation { yoloInferenceAndPostProcessing }
|
||||
|
||||
class YoloOnnxFaceDetection {
|
||||
/// This class is responsible for running the face detection model (YOLOv5Face) on ONNX runtime, and can be accessed through the singleton instance [FaceDetectionService.instance].
|
||||
class FaceDetectionService {
|
||||
static final _logger = Logger('YOLOFaceDetectionService');
|
||||
|
||||
final _computer = Computer.shared();
|
||||
|
||||
int sessionAddress = 0;
|
||||
|
||||
static const kModelBucketEndpoint = "https://models.ente.io/";
|
||||
static const kRemoteBucketModelPath = "yolov5s_face_640_640_dynamic.onnx";
|
||||
static const String kModelBucketEndpoint = "https://models.ente.io/";
|
||||
static const String kRemoteBucketModelPath =
|
||||
"yolov5s_face_640_640_dynamic.onnx";
|
||||
// static const kRemoteBucketModelPath = "yolov5n_face_640_640.onnx";
|
||||
static const modelRemotePath = kModelBucketEndpoint + kRemoteBucketModelPath;
|
||||
static const String modelRemotePath =
|
||||
kModelBucketEndpoint + kRemoteBucketModelPath;
|
||||
|
||||
static const kInputWidth = 640;
|
||||
static const kInputHeight = 640;
|
||||
static const kIouThreshold = 0.4;
|
||||
static const kMinScoreSigmoidThreshold = 0.7;
|
||||
static const int kInputWidth = 640;
|
||||
static const int kInputHeight = 640;
|
||||
static const double kIouThreshold = 0.4;
|
||||
static const double kMinScoreSigmoidThreshold = 0.7;
|
||||
static const int kNumKeypoints = 5;
|
||||
|
||||
bool isInitialized = false;
|
||||
|
||||
|
@ -55,7 +59,7 @@ class YoloOnnxFaceDetection {
|
|||
bool isRunning = false;
|
||||
|
||||
// singleton pattern
|
||||
YoloOnnxFaceDetection._privateConstructor();
|
||||
FaceDetectionService._privateConstructor();
|
||||
|
||||
/// Use this instance to access the FaceDetection service. Make sure to call `init()` before using it.
|
||||
/// e.g. `await FaceDetection.instance.init();`
|
||||
|
@ -63,9 +67,9 @@ class YoloOnnxFaceDetection {
|
|||
/// Then you can use `predict()` to get the bounding boxes of the faces, so `FaceDetection.instance.predict(imageData)`
|
||||
///
|
||||
/// config options: yoloV5FaceN //
|
||||
static final instance = YoloOnnxFaceDetection._privateConstructor();
|
||||
static final instance = FaceDetectionService._privateConstructor();
|
||||
|
||||
factory YoloOnnxFaceDetection() => instance;
|
||||
factory FaceDetectionService() => instance;
|
||||
|
||||
/// Check if the interpreter is initialized, if not initialize it with `loadModel()`
|
||||
Future<void> init() async {
|
||||
|
@ -178,7 +182,7 @@ class YoloOnnxFaceDetection {
|
|||
dev.log(
|
||||
'[YOLOFaceDetectionService] Error while running inference: $e \n $s',
|
||||
);
|
||||
throw YOLOInterpreterRunException();
|
||||
throw YOLOFaceInterpreterRunException();
|
||||
}
|
||||
stopwatchInterpreter.stop();
|
||||
dev.log(
|
||||
|
@ -297,7 +301,7 @@ class YoloOnnxFaceDetection {
|
|||
// runOptions.release();
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error while running inference: $e \n $s');
|
||||
throw YOLOInterpreterRunException();
|
||||
throw YOLOFaceInterpreterRunException();
|
||||
}
|
||||
stopwatchInterpreter.stop();
|
||||
_logger.info(
|
||||
|
@ -367,7 +371,7 @@ class YoloOnnxFaceDetection {
|
|||
// runOptions.release();
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error while running inference: $e \n $s');
|
||||
throw YOLOInterpreterRunException();
|
||||
throw YOLOFaceInterpreterRunException();
|
||||
}
|
||||
stopwatchInterpreter.stop();
|
||||
_logger.info(
|
||||
|
@ -585,7 +589,7 @@ class YoloOnnxFaceDetection {
|
|||
runOptions.release();
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error while running inference: $e \n $s');
|
||||
throw YOLOInterpreterRunException();
|
||||
throw YOLOFaceInterpreterRunException();
|
||||
}
|
||||
stopwatchInterpreter.stop();
|
||||
_logger.info(
|
||||
|
@ -770,7 +774,7 @@ class YoloOnnxFaceDetection {
|
|||
dev.log(
|
||||
'[YOLOFaceDetectionService] Error while running inference: $e \n $s',
|
||||
);
|
||||
throw YOLOInterpreterRunException();
|
||||
throw YOLOFaceInterpreterRunException();
|
||||
}
|
||||
stopwatchInterpreter.stop();
|
||||
dev.log(
|
|
@ -1,3 +0,0 @@
|
|||
class YOLOInterpreterInitializationException implements Exception {}
|
||||
|
||||
class YOLOInterpreterRunException implements Exception {}
|
|
@ -1,31 +0,0 @@
|
|||
import 'dart:math' as math show log;
|
||||
|
||||
class FaceDetectionOptionsYOLO {
|
||||
final double minScoreSigmoidThreshold;
|
||||
final double iouThreshold;
|
||||
final int inputWidth;
|
||||
final int inputHeight;
|
||||
final int numCoords;
|
||||
final int numKeypoints;
|
||||
final int numValuesPerKeypoint;
|
||||
final int maxNumFaces;
|
||||
final double scoreClippingThresh;
|
||||
final double inverseSigmoidMinScoreThreshold;
|
||||
final bool useSigmoidScore;
|
||||
final bool flipVertically;
|
||||
|
||||
FaceDetectionOptionsYOLO({
|
||||
required this.minScoreSigmoidThreshold,
|
||||
required this.iouThreshold,
|
||||
required this.inputWidth,
|
||||
required this.inputHeight,
|
||||
this.numCoords = 14,
|
||||
this.numKeypoints = 5,
|
||||
this.numValuesPerKeypoint = 2,
|
||||
this.maxNumFaces = 100,
|
||||
this.scoreClippingThresh = 100.0,
|
||||
this.useSigmoidScore = true,
|
||||
this.flipVertically = false,
|
||||
}) : inverseSigmoidMinScoreThreshold =
|
||||
math.log(minScoreSigmoidThreshold / (1 - minScoreSigmoidThreshold));
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
import 'package:photos/services/machine_learning/face_ml/face_detection/yolov5face/yolo_face_detection_options.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/model_file.dart';
|
||||
|
||||
class YOLOModelConfig {
|
||||
final String modelPath;
|
||||
final FaceDetectionOptionsYOLO faceOptions;
|
||||
|
||||
YOLOModelConfig({
|
||||
required this.modelPath,
|
||||
required this.faceOptions,
|
||||
});
|
||||
}
|
||||
|
||||
final YOLOModelConfig yoloV5FaceS640x640DynamicBatchonnx = YOLOModelConfig(
|
||||
modelPath: ModelFile.yoloV5FaceS640x640DynamicBatchonnx,
|
||||
faceOptions: FaceDetectionOptionsYOLO(
|
||||
minScoreSigmoidThreshold: 0.8,
|
||||
iouThreshold: 0.4,
|
||||
inputWidth: 640,
|
||||
inputHeight: 640,
|
||||
),
|
||||
);
|
|
@ -1,15 +0,0 @@
|
|||
class FaceEmbeddingOptions {
|
||||
final int inputWidth;
|
||||
final int inputHeight;
|
||||
final int embeddingLength;
|
||||
final int numChannels;
|
||||
final bool preWhiten;
|
||||
|
||||
FaceEmbeddingOptions({
|
||||
required this.inputWidth,
|
||||
required this.inputHeight,
|
||||
this.embeddingLength = 192,
|
||||
this.numChannels = 3,
|
||||
this.preWhiten = false,
|
||||
});
|
||||
}
|
|
@ -1,35 +1,37 @@
|
|||
import 'dart:io';
|
||||
import "dart:math" show min, max, sqrt;
|
||||
// import 'dart:math' as math show min, max;
|
||||
import 'dart:typed_data' show Uint8List;
|
||||
import "dart:io" show File;
|
||||
import 'dart:math' as math show max, min, sqrt;
|
||||
import 'dart:typed_data' show Float32List;
|
||||
|
||||
import "package:flutter/foundation.dart";
|
||||
import "package:logging/logging.dart";
|
||||
import 'package:photos/models/ml/ml_typedefs.dart';
|
||||
import 'package:computer/computer.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:onnxruntime/onnxruntime.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_detection/detection.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_embedding/face_embedding_exceptions.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_embedding/face_embedding_options.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_embedding/mobilefacenet_model_config.dart';
|
||||
import 'package:photos/utils/image_ml_isolate.dart';
|
||||
import 'package:photos/utils/image_ml_util.dart';
|
||||
import 'package:tflite_flutter/tflite_flutter.dart';
|
||||
import "package:photos/services/remote_assets_service.dart";
|
||||
import "package:photos/utils/image_ml_isolate.dart";
|
||||
import "package:synchronized/synchronized.dart";
|
||||
|
||||
/// This class is responsible for running the MobileFaceNet model, and can be accessed through the singleton `FaceEmbedding.instance`.
|
||||
class FaceEmbedding {
|
||||
Interpreter? _interpreter;
|
||||
IsolateInterpreter? _isolateInterpreter;
|
||||
int get getAddress => _interpreter!.address;
|
||||
/// This class is responsible for running the face embedding model (MobileFaceNet) on ONNX runtime, and can be accessed through the singleton instance [FaceEmbeddingService.instance].
|
||||
class FaceEmbeddingService {
|
||||
static const kModelBucketEndpoint = "https://models.ente.io/";
|
||||
static const kRemoteBucketModelPath = "mobilefacenet_opset15.onnx";
|
||||
static const modelRemotePath = kModelBucketEndpoint + kRemoteBucketModelPath;
|
||||
|
||||
final outputShapes = <List<int>>[];
|
||||
final outputTypes = <TensorType>[];
|
||||
static const int kInputSize = 112;
|
||||
static const int kEmbeddingSize = 192;
|
||||
static const int kNumChannels = 3;
|
||||
static const bool kPreWhiten = false;
|
||||
|
||||
final _logger = Logger("FaceEmbeddingService");
|
||||
static final _logger = Logger('FaceEmbeddingOnnx');
|
||||
|
||||
bool isInitialized = false;
|
||||
int sessionAddress = 0;
|
||||
|
||||
final _computer = Computer.shared();
|
||||
|
||||
final _computerLock = Lock();
|
||||
|
||||
final MobileFaceNetModelConfig config;
|
||||
final FaceEmbeddingOptions embeddingOptions;
|
||||
// singleton pattern
|
||||
FaceEmbedding._privateConstructor({required this.config})
|
||||
: embeddingOptions = config.faceEmbeddingOptions;
|
||||
FaceEmbeddingService._privateConstructor();
|
||||
|
||||
/// Use this instance to access the FaceEmbedding service. Make sure to call `init()` before using it.
|
||||
/// e.g. `await FaceEmbedding.instance.init();`
|
||||
|
@ -37,243 +39,211 @@ class FaceEmbedding {
|
|||
/// Then you can use `predict()` to get the embedding of a face, so `FaceEmbedding.instance.predict(imageData)`
|
||||
///
|
||||
/// config options: faceEmbeddingEnte
|
||||
static final instance =
|
||||
FaceEmbedding._privateConstructor(config: faceEmbeddingEnte);
|
||||
factory FaceEmbedding() => instance;
|
||||
static final instance = FaceEmbeddingService._privateConstructor();
|
||||
factory FaceEmbeddingService() => instance;
|
||||
|
||||
/// Check if the interpreter is initialized, if not initialize it with `loadModel()`
|
||||
Future<void> init() async {
|
||||
if (_interpreter == null || _isolateInterpreter == null) {
|
||||
await _loadModel();
|
||||
if (!isInitialized) {
|
||||
_logger.info('init is called');
|
||||
final model =
|
||||
await RemoteAssetsService.instance.getAsset(modelRemotePath);
|
||||
final startTime = DateTime.now();
|
||||
// Doing this from main isolate since `rootBundle` cannot be accessed outside it
|
||||
sessionAddress = await _computer.compute(
|
||||
_loadModel,
|
||||
param: {
|
||||
"modelPath": model.path,
|
||||
},
|
||||
);
|
||||
final endTime = DateTime.now();
|
||||
_logger.info(
|
||||
"Face embedding model loaded, took: ${(endTime.millisecondsSinceEpoch - startTime.millisecondsSinceEpoch).toString()}ms",
|
||||
);
|
||||
if (sessionAddress != -1) {
|
||||
isInitialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
_logger.info('dispose() is called');
|
||||
Future<void> release() async {
|
||||
if (isInitialized) {
|
||||
await _computer
|
||||
.compute(_releaseModel, param: {'address': sessionAddress});
|
||||
isInitialized = false;
|
||||
sessionAddress = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<int> _loadModel(Map args) async {
|
||||
final sessionOptions = OrtSessionOptions()
|
||||
..setInterOpNumThreads(1)
|
||||
..setIntraOpNumThreads(1)
|
||||
..setSessionGraphOptimizationLevel(GraphOptimizationLevel.ortEnableAll);
|
||||
try {
|
||||
// _logger.info('Loading face embedding model');
|
||||
final session =
|
||||
OrtSession.fromFile(File(args["modelPath"]), sessionOptions);
|
||||
// _logger.info('Face embedding model loaded');
|
||||
return session.address;
|
||||
} catch (e, _) {
|
||||
// _logger.severe('Face embedding model not loaded', e, s);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static Future<void> _releaseModel(Map args) async {
|
||||
final address = args['address'] as int;
|
||||
if (address == 0) {
|
||||
return;
|
||||
}
|
||||
final session = OrtSession.fromAddress(address);
|
||||
session.release();
|
||||
return;
|
||||
}
|
||||
|
||||
Future<(List<double>, bool, double)> predictFromImageDataInComputer(
|
||||
String imagePath,
|
||||
FaceDetectionRelative face,
|
||||
) async {
|
||||
assert(sessionAddress != 0 && sessionAddress != -1 && isInitialized);
|
||||
|
||||
try {
|
||||
_interpreter?.close();
|
||||
_interpreter = null;
|
||||
await _isolateInterpreter?.close();
|
||||
_isolateInterpreter = null;
|
||||
final stopwatchDecoding = Stopwatch()..start();
|
||||
final (inputImageList, _, isBlur, blurValue, _) =
|
||||
await ImageMlIsolate.instance.preprocessMobileFaceNetOnnx(
|
||||
imagePath,
|
||||
[face],
|
||||
);
|
||||
stopwatchDecoding.stop();
|
||||
_logger.info(
|
||||
'MobileFaceNet image decoding and preprocessing is finished, in ${stopwatchDecoding.elapsedMilliseconds}ms',
|
||||
);
|
||||
|
||||
final stopwatch = Stopwatch()..start();
|
||||
_logger.info('MobileFaceNet interpreter.run is called');
|
||||
final embedding = await _computer.compute(
|
||||
inferFromMap,
|
||||
param: {
|
||||
'input': inputImageList,
|
||||
'address': sessionAddress,
|
||||
'inputSize': kInputSize,
|
||||
},
|
||||
taskName: 'createFaceEmbedding',
|
||||
) as List<double>;
|
||||
stopwatch.stop();
|
||||
_logger.info(
|
||||
'MobileFaceNet interpreter.run is finished, in ${stopwatch.elapsedMilliseconds}ms',
|
||||
);
|
||||
|
||||
_logger.info(
|
||||
'MobileFaceNet results (only first few numbers): embedding ${embedding.sublist(0, 5)}',
|
||||
);
|
||||
_logger.info(
|
||||
'Mean of embedding: ${embedding.reduce((a, b) => a + b) / embedding.length}',
|
||||
);
|
||||
_logger.info(
|
||||
'Max of embedding: ${embedding.reduce(math.max)}',
|
||||
);
|
||||
_logger.info(
|
||||
'Min of embedding: ${embedding.reduce(math.min)}',
|
||||
);
|
||||
|
||||
return (embedding, isBlur[0], blurValue[0]);
|
||||
} catch (e) {
|
||||
_logger.severe('Error while closing interpreter: $e');
|
||||
_logger.info('MobileFaceNet Error while running inference: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// WARNING: This function only works for one face at a time. it's better to use [predict], which can handle both single and multiple faces.
|
||||
Future<List<double>> predictSingle(
|
||||
Uint8List imageData,
|
||||
FaceDetectionRelative face,
|
||||
) async {
|
||||
assert(_interpreter != null && _isolateInterpreter != null);
|
||||
Future<List<List<double>>> predictInComputer(Float32List input) async {
|
||||
assert(sessionAddress != 0 && sessionAddress != -1 && isInitialized);
|
||||
return await _computerLock.synchronized(() async {
|
||||
try {
|
||||
final stopwatch = Stopwatch()..start();
|
||||
_logger.info('MobileFaceNet interpreter.run is called');
|
||||
final embeddings = await _computer.compute(
|
||||
inferFromMap,
|
||||
param: {
|
||||
'input': input,
|
||||
'address': sessionAddress,
|
||||
'inputSize': kInputSize,
|
||||
},
|
||||
taskName: 'createFaceEmbedding',
|
||||
) as List<List<double>>;
|
||||
stopwatch.stop();
|
||||
_logger.info(
|
||||
'MobileFaceNet interpreter.run is finished, in ${stopwatch.elapsedMilliseconds}ms',
|
||||
);
|
||||
|
||||
final stopwatch = Stopwatch()..start();
|
||||
|
||||
// Image decoding and preprocessing
|
||||
List<List<List<List<num>>>> input;
|
||||
List output;
|
||||
try {
|
||||
final stopwatchDecoding = Stopwatch()..start();
|
||||
final (inputImageMatrix, _, _, _, _) =
|
||||
await ImageMlIsolate.instance.preprocessMobileFaceNet(
|
||||
imageData,
|
||||
[face],
|
||||
);
|
||||
input = inputImageMatrix;
|
||||
stopwatchDecoding.stop();
|
||||
_logger.info(
|
||||
'Image decoding and preprocessing is finished, in ${stopwatchDecoding.elapsedMilliseconds}ms',
|
||||
);
|
||||
|
||||
output = createEmptyOutputMatrix(outputShapes[0]);
|
||||
} catch (e) {
|
||||
_logger.severe('Error while decoding and preprocessing image: $e');
|
||||
throw MobileFaceNetImagePreprocessingException();
|
||||
}
|
||||
|
||||
_logger.info('interpreter.run is called');
|
||||
// Run inference
|
||||
try {
|
||||
await _isolateInterpreter!.run(input, output);
|
||||
// _interpreter!.run(input, output);
|
||||
// ignore: avoid_catches_without_on_clauses
|
||||
} catch (e) {
|
||||
_logger.severe('Error while running inference: $e');
|
||||
throw MobileFaceNetInterpreterRunException();
|
||||
}
|
||||
_logger.info('interpreter.run is finished');
|
||||
|
||||
// Get output tensors
|
||||
final embedding = output[0] as List<double>;
|
||||
|
||||
// Normalize the embedding
|
||||
final norm = sqrt(embedding.map((e) => e * e).reduce((a, b) => a + b));
|
||||
for (int i = 0; i < embedding.length; i++) {
|
||||
embedding[i] /= norm;
|
||||
}
|
||||
|
||||
stopwatch.stop();
|
||||
_logger.info(
|
||||
'predict() executed in ${stopwatch.elapsedMilliseconds}ms',
|
||||
);
|
||||
|
||||
// _logger.info(
|
||||
// 'results (only first few numbers): embedding ${embedding.sublist(0, 5)}',
|
||||
// );
|
||||
// _logger.info(
|
||||
// 'Mean of embedding: ${embedding.reduce((a, b) => a + b) / embedding.length}',
|
||||
// );
|
||||
// _logger.info(
|
||||
// 'Max of embedding: ${embedding.reduce(math.max)}',
|
||||
// );
|
||||
// _logger.info(
|
||||
// 'Min of embedding: ${embedding.reduce(math.min)}',
|
||||
// );
|
||||
|
||||
return embedding;
|
||||
return embeddings;
|
||||
} catch (e) {
|
||||
_logger.info('MobileFaceNet Error while running inference: $e');
|
||||
rethrow;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<List<List<double>>> predict(
|
||||
List<Num3DInputMatrix> inputImageMatrix,
|
||||
static Future<List<List<double>>> predictSync(
|
||||
Float32List input,
|
||||
int sessionAddress,
|
||||
) async {
|
||||
assert(_interpreter != null && _isolateInterpreter != null);
|
||||
|
||||
final stopwatch = Stopwatch()..start();
|
||||
|
||||
_checkPreprocessedInput(inputImageMatrix); // [inputHeight, inputWidth, 3]
|
||||
final input = [inputImageMatrix];
|
||||
// await encodeAndSaveData(inputImageMatrix, 'input_mobilefacenet');
|
||||
|
||||
final output = <int, Object>{};
|
||||
final outputShape = outputShapes[0];
|
||||
outputShape[0] = inputImageMatrix.length;
|
||||
output[0] = createEmptyOutputMatrix(outputShape);
|
||||
// for (int i = 0; i < faces.length; i++) {
|
||||
// output[i] = createEmptyOutputMatrix(outputShapes[0]);
|
||||
// }
|
||||
|
||||
_logger.info('interpreter.run is called');
|
||||
// Run inference
|
||||
final stopwatchInterpreter = Stopwatch()..start();
|
||||
assert(sessionAddress != 0 && sessionAddress != -1);
|
||||
try {
|
||||
await _isolateInterpreter!.runForMultipleInputs(input, output);
|
||||
// _interpreter!.runForMultipleInputs(input, output);
|
||||
// ignore: avoid_catches_without_on_clauses
|
||||
final stopwatch = Stopwatch()..start();
|
||||
_logger.info('MobileFaceNet interpreter.run is called');
|
||||
final embeddings = await infer(
|
||||
input,
|
||||
sessionAddress,
|
||||
kInputSize,
|
||||
);
|
||||
stopwatch.stop();
|
||||
_logger.info(
|
||||
'MobileFaceNet interpreter.run is finished, in ${stopwatch.elapsedMilliseconds}ms',
|
||||
);
|
||||
|
||||
return embeddings;
|
||||
} catch (e) {
|
||||
_logger.severe('Error while running inference: $e');
|
||||
throw MobileFaceNetInterpreterRunException();
|
||||
_logger.info('MobileFaceNet Error while running inference: $e');
|
||||
rethrow;
|
||||
}
|
||||
stopwatchInterpreter.stop();
|
||||
_logger.info(
|
||||
'interpreter.run is finished, in ${stopwatchInterpreter.elapsedMilliseconds}ms',
|
||||
}
|
||||
|
||||
static Future<List<List<double>>> inferFromMap(Map args) async {
|
||||
final inputImageList = args['input'] as Float32List;
|
||||
final address = args['address'] as int;
|
||||
final inputSize = args['inputSize'] as int;
|
||||
return await infer(inputImageList, address, inputSize);
|
||||
}
|
||||
|
||||
static Future<List<List<double>>> infer(
|
||||
Float32List inputImageList,
|
||||
int address,
|
||||
int inputSize,
|
||||
) async {
|
||||
final runOptions = OrtRunOptions();
|
||||
final int numberOfFaces =
|
||||
inputImageList.length ~/ (inputSize * inputSize * 3);
|
||||
final inputOrt = OrtValueTensor.createTensorWithDataList(
|
||||
inputImageList,
|
||||
[numberOfFaces, inputSize, inputSize, 3],
|
||||
);
|
||||
// _logger.info('output: $output');
|
||||
final inputs = {'img_inputs': inputOrt};
|
||||
final session = OrtSession.fromAddress(address);
|
||||
final List<OrtValue?> outputs = session.run(runOptions, inputs);
|
||||
final embeddings = outputs[0]?.value as List<List<double>>;
|
||||
|
||||
// Get output tensors
|
||||
final embeddings = <List<double>>[];
|
||||
final outerEmbedding = output[0]! as Iterable<dynamic>;
|
||||
for (int i = 0; i < inputImageMatrix.length; i++) {
|
||||
final embedding = List<double>.from(outerEmbedding.toList()[i]);
|
||||
// _logger.info("The $i-th embedding: $embedding");
|
||||
embeddings.add(embedding);
|
||||
}
|
||||
// await encodeAndSaveData(embeddings, 'output_mobilefacenet');
|
||||
|
||||
// Normalize the embedding
|
||||
for (int i = 0; i < embeddings.length; i++) {
|
||||
final embedding = embeddings[i];
|
||||
final norm = sqrt(embedding.map((e) => e * e).reduce((a, b) => a + b));
|
||||
for (int j = 0; j < embedding.length; j++) {
|
||||
embedding[j] /= norm;
|
||||
for (final embedding in embeddings) {
|
||||
double normalization = 0;
|
||||
for (int i = 0; i < kEmbeddingSize; i++) {
|
||||
normalization += embedding[i] * embedding[i];
|
||||
}
|
||||
final double sqrtNormalization = math.sqrt(normalization);
|
||||
for (int i = 0; i < kEmbeddingSize; i++) {
|
||||
embedding[i] = embedding[i] / sqrtNormalization;
|
||||
}
|
||||
}
|
||||
|
||||
stopwatch.stop();
|
||||
_logger.info(
|
||||
'predictBatch() executed in ${stopwatch.elapsedMilliseconds}ms',
|
||||
);
|
||||
|
||||
return embeddings;
|
||||
}
|
||||
|
||||
Future<void> _loadModel() async {
|
||||
_logger.info('loadModel is called');
|
||||
|
||||
try {
|
||||
final interpreterOptions = InterpreterOptions();
|
||||
|
||||
// Android Delegates
|
||||
// TODO: Make sure this works on both platforms: Android and iOS
|
||||
if (Platform.isAndroid) {
|
||||
// Use GPU Delegate (GPU). WARNING: It doesn't work on emulator
|
||||
// if (!kDebugMode) {
|
||||
// interpreterOptions.addDelegate(GpuDelegateV2());
|
||||
// }
|
||||
// Use XNNPACK Delegate (CPU)
|
||||
interpreterOptions.addDelegate(XNNPackDelegate());
|
||||
}
|
||||
|
||||
// iOS Delegates
|
||||
if (Platform.isIOS) {
|
||||
// Use Metal Delegate (GPU)
|
||||
interpreterOptions.addDelegate(GpuDelegate());
|
||||
}
|
||||
|
||||
// Load model from assets
|
||||
_interpreter ??= await Interpreter.fromAsset(
|
||||
config.modelPath,
|
||||
options: interpreterOptions,
|
||||
);
|
||||
_isolateInterpreter ??=
|
||||
await IsolateInterpreter.create(address: _interpreter!.address);
|
||||
|
||||
_logger.info('Interpreter created from asset: ${config.modelPath}');
|
||||
|
||||
// Get tensor input shape [1, 112, 112, 3]
|
||||
final inputTensors = _interpreter!.getInputTensors().first;
|
||||
_logger.info('Input Tensors: $inputTensors');
|
||||
// Get tensour output shape [1, 192]
|
||||
final outputTensors = _interpreter!.getOutputTensors();
|
||||
final outputTensor = outputTensors.first;
|
||||
_logger.info('Output Tensors: $outputTensor');
|
||||
|
||||
for (var tensor in outputTensors) {
|
||||
outputShapes.add(tensor.shape);
|
||||
outputTypes.add(tensor.type);
|
||||
}
|
||||
_logger.info('outputShapes: $outputShapes');
|
||||
_logger.info('loadModel is finished');
|
||||
// ignore: avoid_catches_without_on_clauses
|
||||
} catch (e) {
|
||||
_logger.severe('Error while creating interpreter: $e');
|
||||
throw MobileFaceNetInterpreterInitializationException();
|
||||
}
|
||||
}
|
||||
|
||||
void _checkPreprocessedInput(
|
||||
List<Num3DInputMatrix> inputMatrix,
|
||||
) {
|
||||
final embeddingOptions = config.faceEmbeddingOptions;
|
||||
|
||||
if (inputMatrix.isEmpty) {
|
||||
// Check if the input is empty
|
||||
throw MobileFaceNetEmptyInput();
|
||||
}
|
||||
|
||||
// Check if the input is the correct size
|
||||
if (inputMatrix[0].length != embeddingOptions.inputHeight ||
|
||||
inputMatrix[0][0].length != embeddingOptions.inputWidth) {
|
||||
throw MobileFaceNetWrongInputSize();
|
||||
}
|
||||
|
||||
final flattened = inputMatrix[0].expand((i) => i).expand((i) => i);
|
||||
final minValue = flattened.reduce(min);
|
||||
final maxValue = flattened.reduce(max);
|
||||
|
||||
if (minValue < -1 || maxValue > 1) {
|
||||
throw MobileFaceNetWrongInputRange();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
import 'package:photos/services/machine_learning/face_ml/face_embedding/face_embedding_options.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/model_file.dart';
|
||||
|
||||
class MobileFaceNetModelConfig {
|
||||
final String modelPath;
|
||||
final FaceEmbeddingOptions faceEmbeddingOptions;
|
||||
|
||||
MobileFaceNetModelConfig({
|
||||
required this.modelPath,
|
||||
required this.faceEmbeddingOptions,
|
||||
});
|
||||
}
|
||||
|
||||
final MobileFaceNetModelConfig faceEmbeddingEnte = MobileFaceNetModelConfig(
|
||||
modelPath: ModelFile.faceEmbeddingEnte,
|
||||
faceEmbeddingOptions: FaceEmbeddingOptions(
|
||||
inputWidth: 112,
|
||||
inputHeight: 112,
|
||||
),
|
||||
);
|
|
@ -1,246 +0,0 @@
|
|||
import "dart:io" show File;
|
||||
import 'dart:math' as math show max, min, sqrt;
|
||||
import 'dart:typed_data' show Float32List;
|
||||
|
||||
import 'package:computer/computer.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:onnxruntime/onnxruntime.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_detection/detection.dart';
|
||||
import "package:photos/services/remote_assets_service.dart";
|
||||
import "package:photos/utils/image_ml_isolate.dart";
|
||||
import "package:synchronized/synchronized.dart";
|
||||
|
||||
class FaceEmbeddingOnnx {
|
||||
static const kModelBucketEndpoint = "https://models.ente.io/";
|
||||
static const kRemoteBucketModelPath = "mobilefacenet_opset15.onnx";
|
||||
static const modelRemotePath = kModelBucketEndpoint + kRemoteBucketModelPath;
|
||||
|
||||
static const int kInputSize = 112;
|
||||
static const int kEmbeddingSize = 192;
|
||||
|
||||
static final _logger = Logger('FaceEmbeddingOnnx');
|
||||
|
||||
bool isInitialized = false;
|
||||
int sessionAddress = 0;
|
||||
|
||||
final _computer = Computer.shared();
|
||||
|
||||
final _computerLock = Lock();
|
||||
|
||||
// singleton pattern
|
||||
FaceEmbeddingOnnx._privateConstructor();
|
||||
|
||||
/// Use this instance to access the FaceEmbedding service. Make sure to call `init()` before using it.
|
||||
/// e.g. `await FaceEmbedding.instance.init();`
|
||||
///
|
||||
/// Then you can use `predict()` to get the embedding of a face, so `FaceEmbedding.instance.predict(imageData)`
|
||||
///
|
||||
/// config options: faceEmbeddingEnte
|
||||
static final instance = FaceEmbeddingOnnx._privateConstructor();
|
||||
factory FaceEmbeddingOnnx() => instance;
|
||||
|
||||
/// Check if the interpreter is initialized, if not initialize it with `loadModel()`
|
||||
Future<void> init() async {
|
||||
if (!isInitialized) {
|
||||
_logger.info('init is called');
|
||||
final model =
|
||||
await RemoteAssetsService.instance.getAsset(modelRemotePath);
|
||||
final startTime = DateTime.now();
|
||||
// Doing this from main isolate since `rootBundle` cannot be accessed outside it
|
||||
sessionAddress = await _computer.compute(
|
||||
_loadModel,
|
||||
param: {
|
||||
"modelPath": model.path,
|
||||
},
|
||||
);
|
||||
final endTime = DateTime.now();
|
||||
_logger.info(
|
||||
"Face embedding model loaded, took: ${(endTime.millisecondsSinceEpoch - startTime.millisecondsSinceEpoch).toString()}ms",
|
||||
);
|
||||
if (sessionAddress != -1) {
|
||||
isInitialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> release() async {
|
||||
if (isInitialized) {
|
||||
await _computer
|
||||
.compute(_releaseModel, param: {'address': sessionAddress});
|
||||
isInitialized = false;
|
||||
sessionAddress = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<int> _loadModel(Map args) async {
|
||||
final sessionOptions = OrtSessionOptions()
|
||||
..setInterOpNumThreads(1)
|
||||
..setIntraOpNumThreads(1)
|
||||
..setSessionGraphOptimizationLevel(GraphOptimizationLevel.ortEnableAll);
|
||||
try {
|
||||
// _logger.info('Loading face embedding model');
|
||||
final session =
|
||||
OrtSession.fromFile(File(args["modelPath"]), sessionOptions);
|
||||
// _logger.info('Face embedding model loaded');
|
||||
return session.address;
|
||||
} catch (e, _) {
|
||||
// _logger.severe('Face embedding model not loaded', e, s);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static Future<void> _releaseModel(Map args) async {
|
||||
final address = args['address'] as int;
|
||||
if (address == 0) {
|
||||
return;
|
||||
}
|
||||
final session = OrtSession.fromAddress(address);
|
||||
session.release();
|
||||
return;
|
||||
}
|
||||
|
||||
Future<(List<double>, bool, double)> predictFromImageDataInComputer(
|
||||
String imagePath,
|
||||
FaceDetectionRelative face,
|
||||
) async {
|
||||
assert(sessionAddress != 0 && sessionAddress != -1 && isInitialized);
|
||||
|
||||
try {
|
||||
final stopwatchDecoding = Stopwatch()..start();
|
||||
final (inputImageList, _, isBlur, blurValue, _) =
|
||||
await ImageMlIsolate.instance.preprocessMobileFaceNetOnnx(
|
||||
imagePath,
|
||||
[face],
|
||||
);
|
||||
stopwatchDecoding.stop();
|
||||
_logger.info(
|
||||
'MobileFaceNet image decoding and preprocessing is finished, in ${stopwatchDecoding.elapsedMilliseconds}ms',
|
||||
);
|
||||
|
||||
final stopwatch = Stopwatch()..start();
|
||||
_logger.info('MobileFaceNet interpreter.run is called');
|
||||
final embedding = await _computer.compute(
|
||||
inferFromMap,
|
||||
param: {
|
||||
'input': inputImageList,
|
||||
'address': sessionAddress,
|
||||
'inputSize': kInputSize,
|
||||
},
|
||||
taskName: 'createFaceEmbedding',
|
||||
) as List<double>;
|
||||
stopwatch.stop();
|
||||
_logger.info(
|
||||
'MobileFaceNet interpreter.run is finished, in ${stopwatch.elapsedMilliseconds}ms',
|
||||
);
|
||||
|
||||
_logger.info(
|
||||
'MobileFaceNet results (only first few numbers): embedding ${embedding.sublist(0, 5)}',
|
||||
);
|
||||
_logger.info(
|
||||
'Mean of embedding: ${embedding.reduce((a, b) => a + b) / embedding.length}',
|
||||
);
|
||||
_logger.info(
|
||||
'Max of embedding: ${embedding.reduce(math.max)}',
|
||||
);
|
||||
_logger.info(
|
||||
'Min of embedding: ${embedding.reduce(math.min)}',
|
||||
);
|
||||
|
||||
return (embedding, isBlur[0], blurValue[0]);
|
||||
} catch (e) {
|
||||
_logger.info('MobileFaceNet Error while running inference: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<List<double>>> predictInComputer(Float32List input) async {
|
||||
assert(sessionAddress != 0 && sessionAddress != -1 && isInitialized);
|
||||
return await _computerLock.synchronized(() async {
|
||||
try {
|
||||
final stopwatch = Stopwatch()..start();
|
||||
_logger.info('MobileFaceNet interpreter.run is called');
|
||||
final embeddings = await _computer.compute(
|
||||
inferFromMap,
|
||||
param: {
|
||||
'input': input,
|
||||
'address': sessionAddress,
|
||||
'inputSize': kInputSize,
|
||||
},
|
||||
taskName: 'createFaceEmbedding',
|
||||
) as List<List<double>>;
|
||||
stopwatch.stop();
|
||||
_logger.info(
|
||||
'MobileFaceNet interpreter.run is finished, in ${stopwatch.elapsedMilliseconds}ms',
|
||||
);
|
||||
|
||||
return embeddings;
|
||||
} catch (e) {
|
||||
_logger.info('MobileFaceNet Error while running inference: $e');
|
||||
rethrow;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static Future<List<List<double>>> predictSync(
|
||||
Float32List input,
|
||||
int sessionAddress,
|
||||
) async {
|
||||
assert(sessionAddress != 0 && sessionAddress != -1);
|
||||
try {
|
||||
final stopwatch = Stopwatch()..start();
|
||||
_logger.info('MobileFaceNet interpreter.run is called');
|
||||
final embeddings = await infer(
|
||||
input,
|
||||
sessionAddress,
|
||||
kInputSize,
|
||||
);
|
||||
stopwatch.stop();
|
||||
_logger.info(
|
||||
'MobileFaceNet interpreter.run is finished, in ${stopwatch.elapsedMilliseconds}ms',
|
||||
);
|
||||
|
||||
return embeddings;
|
||||
} catch (e) {
|
||||
_logger.info('MobileFaceNet Error while running inference: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<List<List<double>>> inferFromMap(Map args) async {
|
||||
final inputImageList = args['input'] as Float32List;
|
||||
final address = args['address'] as int;
|
||||
final inputSize = args['inputSize'] as int;
|
||||
return await infer(inputImageList, address, inputSize);
|
||||
}
|
||||
|
||||
static Future<List<List<double>>> infer(
|
||||
Float32List inputImageList,
|
||||
int address,
|
||||
int inputSize,
|
||||
) async {
|
||||
final runOptions = OrtRunOptions();
|
||||
final int numberOfFaces =
|
||||
inputImageList.length ~/ (inputSize * inputSize * 3);
|
||||
final inputOrt = OrtValueTensor.createTensorWithDataList(
|
||||
inputImageList,
|
||||
[numberOfFaces, inputSize, inputSize, 3],
|
||||
);
|
||||
final inputs = {'img_inputs': inputOrt};
|
||||
final session = OrtSession.fromAddress(address);
|
||||
final List<OrtValue?> outputs = session.run(runOptions, inputs);
|
||||
final embeddings = outputs[0]?.value as List<List<double>>;
|
||||
|
||||
for (final embedding in embeddings) {
|
||||
double normalization = 0;
|
||||
for (int i = 0; i < kEmbeddingSize; i++) {
|
||||
normalization += embedding[i] * embedding[i];
|
||||
}
|
||||
final double sqrtNormalization = math.sqrt(normalization);
|
||||
for (int i = 0; i < kEmbeddingSize; i++) {
|
||||
embedding[i] = embedding[i] / sqrtNormalization;
|
||||
}
|
||||
}
|
||||
|
||||
return embeddings;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:photos/services/machine_learning/face_ml/face_detection/yolov5face/onnx_face_detection.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_detection/face_detection_service.dart';
|
||||
|
||||
/// Blur detection threshold
|
||||
const kLaplacianThreshold = 15;
|
||||
|
@ -10,4 +10,4 @@ const kLapacianDefault = 10000.0;
|
|||
const kMinHighQualityFaceScore = 0.80;
|
||||
|
||||
/// The minimum score for a face to be detected, regardless of quality. Use [kMinHighQualityFaceScore] for high quality faces.
|
||||
const kMinFaceDetectionScore = YoloOnnxFaceDetection.kMinScoreSigmoidThreshold;
|
||||
const kMinFaceDetectionScore = FaceDetectionService.kMinScoreSigmoidThreshold;
|
||||
|
|
|
@ -28,10 +28,10 @@ import "package:photos/models/file/file_type.dart";
|
|||
import "package:photos/models/ml/ml_versions.dart";
|
||||
import 'package:photos/services/machine_learning/face_ml/face_clustering/linear_clustering_service.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_detection/detection.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_detection/yolov5face/onnx_face_detection.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_detection/yolov5face/yolo_face_detection_exceptions.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_detection/face_detection_exceptions.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_detection/face_detection_service.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_embedding/face_embedding_exceptions.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_embedding/onnx_face_embedding.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_embedding/face_embedding_service.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_ml_exceptions.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_ml_result.dart';
|
||||
|
@ -90,7 +90,7 @@ class FaceMlService {
|
|||
_logger.info("init called");
|
||||
await _computer.compute(initOrtEnv);
|
||||
try {
|
||||
await YoloOnnxFaceDetection.instance.init();
|
||||
await FaceDetectionService.instance.init();
|
||||
} catch (e, s) {
|
||||
_logger.severe("Could not initialize yolo onnx", e, s);
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ class FaceMlService {
|
|||
}
|
||||
}
|
||||
try {
|
||||
await FaceEmbeddingOnnx.instance.init();
|
||||
await FaceEmbeddingService.instance.init();
|
||||
} catch (e, s) {
|
||||
_logger.severe("Could not initialize mobilefacenet", e, s);
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ class FaceMlService {
|
|||
return;
|
||||
}
|
||||
try {
|
||||
await YoloOnnxFaceDetection.instance.release();
|
||||
await FaceDetectionService.instance.release();
|
||||
} catch (e, s) {
|
||||
_logger.severe("Could not dispose yolo onnx", e, s);
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ class FaceMlService {
|
|||
_logger.severe("Could not dispose image ml isolate", e, s);
|
||||
}
|
||||
try {
|
||||
await FaceEmbeddingOnnx.instance.release();
|
||||
await FaceEmbeddingService.instance.release();
|
||||
} catch (e, s) {
|
||||
_logger.severe("Could not dispose mobilefacenet", e, s);
|
||||
}
|
||||
|
@ -894,8 +894,9 @@ class FaceMlService {
|
|||
"enteFileID": enteFile.uploadedFileID ?? -1,
|
||||
"filePath": filePath,
|
||||
"faceDetectionAddress":
|
||||
YoloOnnxFaceDetection.instance.sessionAddress,
|
||||
"faceEmbeddingAddress": FaceEmbeddingOnnx.instance.sessionAddress,
|
||||
FaceDetectionService.instance.sessionAddress,
|
||||
"faceEmbeddingAddress":
|
||||
FaceEmbeddingService.instance.sessionAddress,
|
||||
}
|
||||
),
|
||||
) as String?;
|
||||
|
@ -1042,7 +1043,7 @@ class FaceMlService {
|
|||
try {
|
||||
// Get the bounding boxes of the faces
|
||||
final (List<FaceDetectionRelative> faces, dataSize) =
|
||||
await YoloOnnxFaceDetection.instance.predictInComputer(imagePath);
|
||||
await FaceDetectionService.instance.predictInComputer(imagePath);
|
||||
|
||||
// Add detected faces to the resultBuilder
|
||||
if (resultBuilder != null) {
|
||||
|
@ -1050,9 +1051,9 @@ class FaceMlService {
|
|||
}
|
||||
|
||||
return faces;
|
||||
} on YOLOInterpreterInitializationException {
|
||||
} on YOLOFaceInterpreterInitializationException {
|
||||
throw CouldNotInitializeFaceDetector();
|
||||
} on YOLOInterpreterRunException {
|
||||
} on YOLOFaceInterpreterRunException {
|
||||
throw CouldNotRunFaceDetector();
|
||||
} catch (e) {
|
||||
_logger.severe('Face detection failed: $e');
|
||||
|
@ -1076,7 +1077,7 @@ class FaceMlService {
|
|||
try {
|
||||
// Get the bounding boxes of the faces
|
||||
final (List<FaceDetectionRelative> faces, dataSize) =
|
||||
await YoloOnnxFaceDetection.predictSync(
|
||||
await FaceDetectionService.predictSync(
|
||||
image,
|
||||
imageByteData,
|
||||
interpreterAddress,
|
||||
|
@ -1088,9 +1089,9 @@ class FaceMlService {
|
|||
}
|
||||
|
||||
return faces;
|
||||
} on YOLOInterpreterInitializationException {
|
||||
} on YOLOFaceInterpreterInitializationException {
|
||||
throw CouldNotInitializeFaceDetector();
|
||||
} on YOLOInterpreterRunException {
|
||||
} on YOLOFaceInterpreterRunException {
|
||||
throw CouldNotRunFaceDetector();
|
||||
} catch (e) {
|
||||
dev.log('[SEVERE] Face detection failed: $e');
|
||||
|
@ -1185,7 +1186,7 @@ class FaceMlService {
|
|||
try {
|
||||
// Get the embedding of the faces
|
||||
final List<List<double>> embeddings =
|
||||
await FaceEmbeddingOnnx.instance.predictInComputer(facesList);
|
||||
await FaceEmbeddingService.instance.predictInComputer(facesList);
|
||||
|
||||
// Add the embeddings to the resultBuilder
|
||||
if (resultBuilder != null) {
|
||||
|
@ -1218,7 +1219,7 @@ class FaceMlService {
|
|||
try {
|
||||
// Get the embedding of the faces
|
||||
final List<List<double>> embeddings =
|
||||
await FaceEmbeddingOnnx.predictSync(facesList, interpreterAddress);
|
||||
await FaceEmbeddingService.predictSync(facesList, interpreterAddress);
|
||||
|
||||
// Add the embeddings to the resultBuilder
|
||||
if (resultBuilder != null) {
|
||||
|
|
|
@ -375,7 +375,10 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
|
|||
textInputAction: TextInputAction.next,
|
||||
),
|
||||
),
|
||||
const Divider(thickness: 1),
|
||||
Divider(
|
||||
thickness: 1,
|
||||
color: getEnteColorScheme(context).strokeFaint,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_getAgreement(),
|
||||
const SizedBox(height: 40),
|
||||
|
|
|
@ -8,6 +8,7 @@ import "package:photos/generated/l10n.dart";
|
|||
import "package:photos/l10n/l10n.dart";
|
||||
import "package:photos/models/api/user/srp.dart";
|
||||
import 'package:photos/services/user_service.dart';
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import "package:photos/ui/account/login_pwd_verification_page.dart";
|
||||
import 'package:photos/ui/common/dynamic_fab.dart';
|
||||
import 'package:photos/ui/common/web_page.dart';
|
||||
|
@ -159,10 +160,11 @@ class _LoginPageState extends State<LoginPage> {
|
|||
autofocus: true,
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 18),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 18),
|
||||
child: Divider(
|
||||
thickness: 1,
|
||||
color: getEnteColorScheme(context).strokeFaint,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
|
|
|
@ -282,10 +282,11 @@ class _LoginPasswordVerificationPageState
|
|||
},
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 18),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 18),
|
||||
child: Divider(
|
||||
thickness: 1,
|
||||
color: getEnteColorScheme(context).strokeFaint,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:photos/ente_theme_data.dart';
|
||||
import "package:photos/generated/l10n.dart";
|
||||
import 'package:photos/services/user_service.dart';
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import 'package:photos/ui/common/dynamic_fab.dart';
|
||||
import 'package:step_progress_indicator/step_progress_indicator.dart';
|
||||
import "package:styled_text/styled_text.dart";
|
||||
|
@ -16,7 +17,7 @@ class OTTVerificationPage extends StatefulWidget {
|
|||
this.email, {
|
||||
this.isChangeEmail = false,
|
||||
this.isCreateAccountScreen = false,
|
||||
this.isResetPasswordScreen = false,
|
||||
this.isResetPasswordScreen = false,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
|
@ -78,9 +79,11 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
|
|||
_verificationCodeController.text,
|
||||
);
|
||||
} else {
|
||||
UserService.instance
|
||||
.verifyEmail(context, _verificationCodeController.text,
|
||||
isResettingPasswordScreen: widget.isResetPasswordScreen,);
|
||||
UserService.instance.verifyEmail(
|
||||
context,
|
||||
_verificationCodeController.text,
|
||||
isResettingPasswordScreen: widget.isResetPasswordScreen,
|
||||
);
|
||||
}
|
||||
FocusScope.of(context).unfocus();
|
||||
},
|
||||
|
@ -130,21 +133,21 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
|
|||
},
|
||||
),
|
||||
),
|
||||
widget.isResetPasswordScreen ?
|
||||
Text(
|
||||
S.of(context).toResetVerifyEmail,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleMedium!
|
||||
.copyWith(fontSize: 14),
|
||||
):
|
||||
Text(
|
||||
S.of(context).checkInboxAndSpamFolder,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleMedium!
|
||||
.copyWith(fontSize: 14),
|
||||
),
|
||||
widget.isResetPasswordScreen
|
||||
? Text(
|
||||
S.of(context).toResetVerifyEmail,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleMedium!
|
||||
.copyWith(fontSize: 14),
|
||||
)
|
||||
: Text(
|
||||
S.of(context).checkInboxAndSpamFolder,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleMedium!
|
||||
.copyWith(fontSize: 14),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -178,8 +181,9 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
|
|||
},
|
||||
),
|
||||
),
|
||||
const Divider(
|
||||
Divider(
|
||||
thickness: 1,
|
||||
color: getEnteColorScheme(context).strokeFaint,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
|
|
|
@ -9,6 +9,7 @@ import 'package:photos/core/event_bus.dart';
|
|||
import 'package:photos/events/subscription_purchased_event.dart';
|
||||
import "package:photos/generated/l10n.dart";
|
||||
import "package:photos/services/user_service.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import 'package:photos/ui/account/recovery_page.dart';
|
||||
import 'package:photos/ui/common/dynamic_fab.dart';
|
||||
import 'package:photos/ui/components/buttons/button_widget.dart';
|
||||
|
@ -257,10 +258,11 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
|
|||
},
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 18),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 18),
|
||||
child: Divider(
|
||||
thickness: 1,
|
||||
color: getEnteColorScheme(context).strokeFaint,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:ui';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:photos/core/configuration.dart';
|
||||
import "package:photos/generated/l10n.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import 'package:photos/ui/account/password_entry_page.dart';
|
||||
import 'package:photos/ui/common/dynamic_fab.dart';
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
|
@ -123,10 +124,11 @@ class _RecoveryPageState extends State<RecoveryPage> {
|
|||
},
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 18),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 18),
|
||||
child: Divider(
|
||||
thickness: 1,
|
||||
color: getEnteColorScheme(context).strokeFaint,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
|
|
|
@ -210,10 +210,11 @@ class _RequestPasswordVerificationPageState
|
|||
},
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 18),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 18),
|
||||
child: Divider(
|
||||
thickness: 1,
|
||||
color: getEnteColorScheme(context).strokeFaint,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:photos/ente_theme_data.dart';
|
|||
import "package:photos/generated/l10n.dart";
|
||||
import 'package:photos/models/sessions.dart';
|
||||
import 'package:photos/services/user_service.dart';
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import 'package:photos/ui/common/loading_widget.dart';
|
||||
import "package:photos/utils/date_time_util.dart";
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
|
@ -106,7 +107,9 @@ class _SessionsPageState extends State<SessionsPage> {
|
|||
),
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
Divider(
|
||||
color: getEnteColorScheme(context).strokeFaint,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ class _ToggleSwitchWidgetState extends State<ToggleSwitchWidget> {
|
|||
|
||||
@override
|
||||
void initState() {
|
||||
toggleValue = widget.value.call();
|
||||
super.initState();
|
||||
toggleValue = widget.value.call();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -50,8 +50,13 @@ class _ToggleSwitchWidgetState extends State<ToggleSwitchWidget> {
|
|||
child: FittedBox(
|
||||
fit: BoxFit.contain,
|
||||
child: Switch.adaptive(
|
||||
activeColor: enteColorScheme.primary400,
|
||||
inactiveTrackColor: enteColorScheme.fillMuted,
|
||||
inactiveTrackColor: Colors.transparent,
|
||||
activeTrackColor: enteColorScheme.primary500,
|
||||
activeColor: Colors.white,
|
||||
inactiveThumbColor: enteColorScheme.primary500,
|
||||
trackOutlineColor: MaterialStateColor.resolveWith(
|
||||
(states) => enteColorScheme.primary500,
|
||||
),
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
value: toggleValue ?? false,
|
||||
onChanged: (negationOfToggleValue) async {
|
||||
|
|
|
@ -10,6 +10,7 @@ import 'package:photos/events/sync_status_update_event.dart';
|
|||
import "package:photos/generated/l10n.dart";
|
||||
import 'package:photos/services/sync_service.dart';
|
||||
import 'package:photos/services/user_remote_flag_service.dart';
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import 'package:photos/theme/text_style.dart';
|
||||
import 'package:photos/ui/account/verify_recovery_page.dart';
|
||||
import 'package:photos/ui/components/home_header_widget.dart';
|
||||
|
@ -93,8 +94,9 @@ class _StatusBarWidgetState extends State<StatusBarWidget> {
|
|||
: const Text("ente", style: brandStyleMedium),
|
||||
),
|
||||
_showErrorBanner
|
||||
? const Divider(
|
||||
? Divider(
|
||||
height: 8,
|
||||
color: getEnteColorScheme(context).strokeFaint,
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
_showErrorBanner
|
||||
|
|
|
@ -284,7 +284,7 @@ class _HomeWidgetState extends State<HomeWidget> {
|
|||
void _initMediaShareSubscription() {
|
||||
// For sharing images coming from outside the app while the app is in the memory
|
||||
_intentDataStreamSubscription =
|
||||
ReceiveSharingIntent.getMediaStream().listen(
|
||||
ReceiveSharingIntent.instance.getMediaStream().listen(
|
||||
(List<SharedMediaFile> value) {
|
||||
setState(() {
|
||||
_shouldRenderCreateCollectionSheet = true;
|
||||
|
@ -296,7 +296,9 @@ class _HomeWidgetState extends State<HomeWidget> {
|
|||
},
|
||||
);
|
||||
// For sharing images coming from outside the app while the app is closed
|
||||
ReceiveSharingIntent.getInitialMedia().then((List<SharedMediaFile> value) {
|
||||
ReceiveSharingIntent.instance
|
||||
.getInitialMedia()
|
||||
.then((List<SharedMediaFile> value) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_sharedFiles = value;
|
||||
|
@ -380,7 +382,7 @@ class _HomeWidgetState extends State<HomeWidget> {
|
|||
//So to stop showing multiple CreateCollectionSheets, this flag
|
||||
//needs to be set to false the first time it is rendered.
|
||||
_shouldRenderCreateCollectionSheet = false;
|
||||
ReceiveSharingIntent.reset();
|
||||
ReceiveSharingIntent.instance.reset();
|
||||
Future.delayed(const Duration(milliseconds: 10), () {
|
||||
showCollectionActionSheet(
|
||||
context,
|
||||
|
|
|
@ -10,6 +10,7 @@ import 'package:photos/events/user_logged_out_event.dart';
|
|||
import "package:photos/generated/l10n.dart";
|
||||
import 'package:photos/models/collection/collection.dart';
|
||||
import 'package:photos/services/collections_service.dart';
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import "package:photos/ui/collections/button/archived_button.dart";
|
||||
import "package:photos/ui/collections/button/hidden_button.dart";
|
||||
import "package:photos/ui/collections/button/trash_button.dart";
|
||||
|
@ -184,7 +185,11 @@ class _UserCollectionsTabState extends State<UserCollectionsTab>
|
|||
),
|
||||
)
|
||||
: const SliverToBoxAdapter(child: SizedBox.shrink()),
|
||||
const SliverToBoxAdapter(child: Divider()),
|
||||
SliverToBoxAdapter(
|
||||
child: Divider(
|
||||
color: getEnteColorScheme(context).strokeFaint,
|
||||
),
|
||||
),
|
||||
const SliverToBoxAdapter(child: SizedBox(height: 12)),
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
|
|
|
@ -13,18 +13,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: _flutterfire_internals
|
||||
sha256: f5628cd9c92ed11083f425fd1f8f1bc60ecdda458c81d73b143aeda036c35fe7
|
||||
sha256: "4eec93681221723a686ad580c2e7d960e1017cf1a4e0a263c2573c2c6b0bf5cd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.16"
|
||||
version: "1.3.25"
|
||||
adaptive_theme:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: adaptive_theme
|
||||
sha256: b0c4c35b22ef8226757881fe4dce38c40a06c551bca83236022ec7613e157c83
|
||||
sha256: f4ee609b464e5efc68131d9d15ba9aa1de4e3b5ede64be17781c6e19a52d637d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.5.0"
|
||||
version: "3.6.0"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -93,10 +93,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: background_fetch
|
||||
sha256: f70b28a0f7a3156195e9742229696f004ea3bf10f74039b7bf4c78a74fbda8a4
|
||||
sha256: dbffec0317ccdef6e2014cb543e147f52441e29c4fcb53dfd23558c4d92ddece
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
version: "1.3.2"
|
||||
battery_info:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -113,6 +113,38 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
bonsoir:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: bonsoir
|
||||
sha256: "800d77c0581fff06cc43ef2b7723dfe5ee9b899ab0fdf80fb1c7b8829a5deb5c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0+1"
|
||||
bonsoir_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: bonsoir_android
|
||||
sha256: "7207c36fd7e0f3c7c2d8cf353f02bd640d96e2387d575837f8ac051c9cbf4aa7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0+1"
|
||||
bonsoir_darwin:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: bonsoir_darwin
|
||||
sha256: "7211042c85da2d6efa80c0976bbd9568f2b63624097779847548ed4530675ade"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
bonsoir_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: bonsoir_platform_interface
|
||||
sha256: "64d57cd52bd477b4891e9b9d419e6408da171ed9e0efc8aa716e7e343d5d93ad"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -157,18 +189,18 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21"
|
||||
sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.8"
|
||||
version: "2.4.9"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
sha256: c9e32d21dd6626b5c163d48b037ce906bbe428bc23ab77bcd77bb21e593b6185
|
||||
sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.2.11"
|
||||
version: "7.3.0"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -181,10 +213,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: built_value
|
||||
sha256: a3ec2e0f967bc47f69f95009bb93db936288d61d5343b9436e378b28a2f830c6
|
||||
sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.9.0"
|
||||
version: "8.9.2"
|
||||
cached_network_image:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -209,6 +241,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
cast:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cast
|
||||
sha256: b70f6be547a53481dffec93ad3cc4974fae5ed707f0b677d4a50c329d7299b98
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -269,10 +309,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: collection
|
||||
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
|
||||
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.17.2"
|
||||
version: "1.18.0"
|
||||
computer:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -285,11 +325,10 @@ packages:
|
|||
connectivity_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "packages/connectivity_plus/connectivity_plus"
|
||||
ref: check_mobile_first
|
||||
resolved-ref: "452aa4b6448adbd3a9e592b82da3e9d355af2125"
|
||||
url: "https://github.com/ente-io/plus_plugins.git"
|
||||
source: git
|
||||
name: connectivity_plus
|
||||
sha256: "77a180d6938f78ca7d2382d2240eb626c0f6a735d0bfdce227d8ffb80f95c48b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
connectivity_plus_platform_interface:
|
||||
dependency: transitive
|
||||
|
@ -311,18 +350,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: coverage
|
||||
sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097"
|
||||
sha256: "595a29b55ce82d53398e1bcc2cba525d7bd7c59faeb2d2540e9d42c390cfeeeb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.6.3"
|
||||
version: "1.6.4"
|
||||
cross_file:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cross_file
|
||||
sha256: "2f9d2cbccb76127ba28528cb3ae2c2326a122446a83de5a056aaa3880d3882c5"
|
||||
sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.3+7"
|
||||
version: "0.3.3+8"
|
||||
crypto:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -383,10 +422,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: device_info_plus
|
||||
sha256: "0042cb3b2a76413ea5f8a2b40cec2a33e01d0c937e91f0f7c211fde4f7739ba6"
|
||||
sha256: "77f757b789ff68e4eaf9c56d1752309bd9f7ad557cb105b938a7f8eb89e59110"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.1.1"
|
||||
version: "9.1.2"
|
||||
device_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -479,18 +518,18 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: extended_image
|
||||
sha256: b4d72a27851751cfadaf048936d42939db7cd66c08fdcfe651eeaa1179714ee6
|
||||
sha256: d7f091d068fcac7246c4b22a84b8dac59a62e04d29a5c172710c696e67a22f94
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.1.1"
|
||||
version: "8.2.0"
|
||||
extended_image_library:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: extended_image_library
|
||||
sha256: "8bf87c0b14dcb59200c923a9a3952304e4732a0901e40811428834ef39018ee1"
|
||||
sha256: "9b55fc5ebc65fad984de66b8f177a1bef2a84d79203c9c213f75ff83c2c29edd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.6.0"
|
||||
version: "4.0.1"
|
||||
fade_indexed_stack:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -552,10 +591,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_core
|
||||
sha256: "96607c0e829a581c2a483c658f04e8b159964c3bae2730f73297070bc85d40bb"
|
||||
sha256: "53316975310c8af75a96e365f9fccb67d1c544ef0acdbf0d88bbe30eedd1c4f9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.24.2"
|
||||
version: "2.27.0"
|
||||
firebase_core_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -568,34 +607,34 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_web
|
||||
sha256: d585bdf3c656c3f7821ba1bd44da5f13365d22fcecaf5eb75c4295246aaa83c0
|
||||
sha256: c8e1d59385eee98de63c92f961d2a7062c5d9a65e7f45bdc7f1b0b205aab2492
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.10.0"
|
||||
version: "2.11.5"
|
||||
firebase_messaging:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_messaging
|
||||
sha256: "980259425fa5e2afc03e533f33723335731d21a56fd255611083bceebf4373a8"
|
||||
sha256: e41586e0fd04fe9a40424f8b0053d0832e6d04f49e020cdaf9919209a28497e9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.7.10"
|
||||
version: "14.7.19"
|
||||
firebase_messaging_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_messaging_platform_interface
|
||||
sha256: "54e283a0e41d81d854636ad0dad73066adc53407a60a7c3189c9656e2f1b6107"
|
||||
sha256: f7a9d74ff7fc588a924f6b2eaeaa148b0db521b13a9db55f6ad45864fa98c06e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.5.18"
|
||||
version: "4.5.27"
|
||||
firebase_messaging_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_messaging_web
|
||||
sha256: "90dc7ed885e90a24bb0e56d661d4d2b5f84429697fd2cbb9e5890a0ca370e6f4"
|
||||
sha256: fc21e771166860c55b103701c5ac7cdb2eec28897b97c42e6e5703cbedf9e02e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.5.18"
|
||||
version: "3.6.8"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -621,10 +660,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_animate
|
||||
sha256: cabe33af6201144be052352d53572a1b8a4f5782b46080be7520d95abe763715
|
||||
sha256: "7c8a6594a9252dad30cc2ef16e33270b6248c4dedc3b3d06c86c4f3f4dc05ae5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.4.1"
|
||||
version: "4.5.0"
|
||||
flutter_cache_manager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -767,10 +806,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_native_splash
|
||||
sha256: "17d9671396fb8ec45ad10f4a975eb8a0f70bedf0fdaf0720b31ea9de6da8c4da"
|
||||
sha256: "558f10070f03ee71f850a78f7136ab239a67636a294a44a06b6b7345178edb1e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.7"
|
||||
version: "2.3.10"
|
||||
flutter_password_strength:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -783,10 +822,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: flutter_plugin_android_lifecycle
|
||||
sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da
|
||||
sha256: "592dc01a18961a51c24ae5d963b724b2b7fa4a95c100fe8eb6ca8a5a4732cadf"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.17"
|
||||
version: "2.0.18"
|
||||
flutter_secure_storage:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -835,6 +874,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
flutter_shaders:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_shaders
|
||||
sha256: "02750b545c01ff4d8e9bbe8f27a7731aa3778402506c67daa1de7f5fc3f4befe"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.2"
|
||||
flutter_sodium:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -847,10 +894,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: flutter_spinkit
|
||||
sha256: b39c753e909d4796906c5696a14daf33639a76e017136c8d82bf3e620ce5bb8e
|
||||
sha256: d2696eed13732831414595b98863260e33e8882fc069ee80ec35d4ac9ddb0472
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.2.0"
|
||||
version: "5.2.1"
|
||||
flutter_staggered_grid_view:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -881,10 +928,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: freezed
|
||||
sha256: "6c5031daae12c7072b3a87eff98983076434b4889ef2a44384d0cae3f82372ba"
|
||||
sha256: "91bce569d4805ea5bad6619a3e8690df8ad062a235165af4c0c5d928dda15eaf"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.6"
|
||||
version: "2.5.1"
|
||||
freezed_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -966,10 +1013,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
|
||||
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.2.0"
|
||||
http_client_helper:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -998,18 +1045,18 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: image
|
||||
sha256: "004a2e90ce080f8627b5a04aecb4cdfac87d2c3f3b520aa291260be5a32c033d"
|
||||
sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.4"
|
||||
version: "4.1.7"
|
||||
image_editor:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: image_editor
|
||||
sha256: "9877a057b0cd2fafcd9a3dce5279948bd850d53ce76231a83c9678a2c9f186e9"
|
||||
sha256: "6401a431ef1e988e35a8b19ff02cb7d31bd881fd7db0d39261ac8236683ef1c1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.4.0"
|
||||
image_editor_common:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1018,6 +1065,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
image_editor_ohos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_editor_ohos
|
||||
sha256: "55c08871814efdd19b3927327b5913649dd1ea36e0a83aa77ab668dad3160dcc"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.6"
|
||||
image_editor_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1038,10 +1093,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: in_app_purchase_android
|
||||
sha256: "28164faac635a6cc357c96f47813e675eec7622a8f41e829b501573dbbce2cce"
|
||||
sha256: "6863bf74335ccbd80829e8c3d16176f90794f0f8593a4505a7ab79d17334a0bf"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.0+17"
|
||||
version: "0.3.3"
|
||||
in_app_purchase_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1054,10 +1109,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: in_app_purchase_storekit
|
||||
sha256: c4b17a7f2ca8ddc7fd7996a8c32a3af6beddf91d651997c8675a5f23c103c9bc
|
||||
sha256: e0f860e760488dbd666e0f27e239d128cba744607fc62434dc76c19d1c292439
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.8+1"
|
||||
version: "0.3.13+1"
|
||||
integration_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
|
@ -1131,10 +1186,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: latlong2
|
||||
sha256: "18712164760cee655bc790122b0fd8f3d5b3c36da2cb7bf94b68a197fbb0811b"
|
||||
sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.0"
|
||||
version: "0.9.1"
|
||||
like_button:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -1171,26 +1226,34 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: local_auth
|
||||
sha256: "27679ed8e0d7daab2357db6bb7076359e083a56b295c0c59723845301da6aed9"
|
||||
sha256: "280421b416b32de31405b0a25c3bd42dfcef2538dfbb20c03019e02a5ed55ed0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.8"
|
||||
version: "2.2.0"
|
||||
local_auth_android:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: local_auth_android
|
||||
sha256: "54e9c35ce52c06333355ab0d0f41e4c06dbca354b23426765ba41dfb1de27598"
|
||||
sha256: "3bcd732dda7c75fcb7ddaef12e131230f53dcc8c00790d0d6efb3aa0fbbeda57"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.36"
|
||||
version: "1.0.37"
|
||||
local_auth_darwin:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: local_auth_darwin
|
||||
sha256: "33381a15b0de2279523eca694089393bb146baebdce72a404555d03174ebc1e9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.2"
|
||||
local_auth_ios:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: local_auth_ios
|
||||
sha256: eb283b530029b334698918f1e282d4483737cbca972ff21b9193be3d6de8e2b8
|
||||
sha256: "6dde47dc852bc0c8343cb58e66a46efb16b62eddf389ce103d4dacb0c6c40c71"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.6"
|
||||
version: "1.1.7"
|
||||
local_auth_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1323,10 +1386,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
|
||||
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.1"
|
||||
version: "1.10.0"
|
||||
mgrs_dart:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1339,10 +1402,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: mime
|
||||
sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
|
||||
sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
version: "1.0.5"
|
||||
ml_linalg:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -1351,6 +1414,7 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "13.11.31"
|
||||
version: "1.0.5"
|
||||
modal_bottom_sheet:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -1510,10 +1574,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668"
|
||||
sha256: "51f0d2c554cfbc9d6a312ab35152fc77e2f0b758ce9f1a444a3a1e5b8f3c6b7f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
version: "2.2.3"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1558,58 +1622,74 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: permission_handler
|
||||
sha256: "284a66179cabdf942f838543e10413246f06424d960c92ba95c84439154fcac8"
|
||||
sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "11.0.1"
|
||||
version: "11.3.1"
|
||||
permission_handler_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_android
|
||||
sha256: f9fddd3b46109bd69ff3f9efa5006d2d309b7aec0f3c1c5637a60a2d5659e76e
|
||||
sha256: "1acac6bae58144b442f11e66621c062aead9c99841093c38f5bcdcc24c1c3474"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "11.1.0"
|
||||
version: "12.0.5"
|
||||
permission_handler_apple:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_apple
|
||||
sha256: "99e220bce3f8877c78e4ace901082fb29fa1b4ebde529ad0932d8d664b34f3f5"
|
||||
sha256: e9ad66020b89ff1b63908f247c2c6f931c6e62699b756ef8b3c4569350cd8662
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.1.4"
|
||||
version: "9.4.4"
|
||||
permission_handler_html:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_html
|
||||
sha256: "54bf176b90f6eddd4ece307e2c06cf977fb3973719c35a93b85cc7093eb6070d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.1"
|
||||
permission_handler_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_platform_interface
|
||||
sha256: "6760eb5ef34589224771010805bea6054ad28453906936f843a8cc4d3a55c4a4"
|
||||
sha256: "48d4fcf201a1dad93ee869ab0d4101d084f49136ec82a8a06ed9cfeacab9fd20"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.12.0"
|
||||
version: "4.2.1"
|
||||
permission_handler_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_windows
|
||||
sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098
|
||||
sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.3"
|
||||
version: "0.2.1"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: petitparser
|
||||
sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
|
||||
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.4.0"
|
||||
version: "6.0.2"
|
||||
photo_manager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: photo_manager
|
||||
sha256: "2d698826421ebd045ecc0df60422e9dd24bd22b178310b68444385f783735b55"
|
||||
sha256: df594f989f0c31cdb3ed48f3d49cb9ffadf11cc3700d2c3460b1912c93432621
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.8.1"
|
||||
version: "3.0.0"
|
||||
photo_manager_image_provider:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: photo_manager_image_provider
|
||||
sha256: "38ef1023dc11de3a8669f16e7c981673b3c5cfee715d17120f4b87daa2cdd0af"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
photo_view:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -1630,10 +1710,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
|
||||
sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "3.1.2"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1646,10 +1726,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: pointycastle
|
||||
sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29"
|
||||
sha256: "70fe966348fe08c34bf929582f1d8247d9d9408130723206472b4687227e4333"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.7.4"
|
||||
version: "3.8.0"
|
||||
polylabel:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1694,10 +1774,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: provider
|
||||
sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096"
|
||||
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.1"
|
||||
version: "6.1.2"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1726,10 +1806,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: receive_sharing_intent
|
||||
sha256: "8fdf5927934041264becf65199ef8057b8b176e879d95ffa0420cd2a6219c0fd"
|
||||
sha256: fe02f858ac9f8d44d62e1964dadded000bb48dea424085ed280d542a61c4e8ba
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.6.7"
|
||||
version: "1.7.0"
|
||||
rxdart:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1806,18 +1886,18 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: sentry
|
||||
sha256: "5686ed515bb620dc52b4ae99a6586fe720d443591183cf1f620ec5d1f0eec100"
|
||||
sha256: fe99a06970b909a491b7f89d54c9b5119772e3a48a400308a6e129625b333f5b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.15.0"
|
||||
version: "7.19.0"
|
||||
sentry_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sentry_flutter
|
||||
sha256: "505dec3b6810562785d2c34ae871c73ff2cba6cf436c32c188f0464df226ba8f"
|
||||
sha256: fc013d4a753447320f62989b1871fdc1f20c77befcc8be3e38774dd7402e7a62
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.15.0"
|
||||
version: "7.19.0"
|
||||
share_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -1846,10 +1926,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: share_plus_platform_interface
|
||||
sha256: df08bc3a07d01f5ea47b45d03ffcba1fa9cd5370fb44b3f38c70e42cced0f956
|
||||
sha256: "251eb156a8b5fa9ce033747d73535bf53911071f8d3b6f4f0b578505ce0d4496"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.3.1"
|
||||
version: "3.4.0"
|
||||
share_plus_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1910,10 +1990,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_web
|
||||
sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf
|
||||
sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
version: "2.2.2"
|
||||
shared_preferences_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -2043,10 +2123,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: sqlite3
|
||||
sha256: db65233e6b99e99b2548932f55a987961bc06d82a31a0665451fa0b4fff4c3fb
|
||||
sha256: "072128763f1547e3e9b4735ce846bfd226d68019ccda54db4cd427b12dfdedc9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.4.0"
|
||||
sqlite3_flutter_libs:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -2067,10 +2147,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
||||
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.0"
|
||||
version: "1.11.1"
|
||||
step_progress_indicator:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -2083,10 +2163,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
||||
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.2"
|
||||
stream_transform:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -2155,34 +2235,26 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: test
|
||||
sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46"
|
||||
sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.24.3"
|
||||
version: "1.24.9"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
|
||||
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.0"
|
||||
version: "0.6.1"
|
||||
test_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_core
|
||||
sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e"
|
||||
sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.3"
|
||||
tflite_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: tflite_flutter
|
||||
sha256: ffb8651fdb116ab0131d6dc47ff73883e0f634ad1ab12bb2852eef1bbeab4a6a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.10.4"
|
||||
version: "0.5.9"
|
||||
time:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -2283,26 +2355,26 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: url_launcher
|
||||
sha256: c512655380d241a337521703af62d2c122bf7b77a46ff7dd750092aa9433499c
|
||||
sha256: "0ecc004c62fd3ed36a2ffcbe0dd9700aee63bd7532d0b642a488b1ec310f492e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.4"
|
||||
version: "6.2.5"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
sha256: "507dc655b1d9cb5ebc756032eb785f114e415f91557b73bf60b7e201dfedeb2f"
|
||||
sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.2"
|
||||
version: "6.3.0"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03"
|
||||
sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.4"
|
||||
version: "6.2.5"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -2323,18 +2395,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_platform_interface
|
||||
sha256: a932c3a8082e118f80a475ce692fde89dc20fddb24c57360b96bc56f7035de1f
|
||||
sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.1"
|
||||
version: "2.3.2"
|
||||
url_launcher_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_web
|
||||
sha256: "7fd2f55fe86cea2897b963e864dc01a7eb0719ecc65fcef4c1cc3d686d718bb2"
|
||||
sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "2.2.3"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -2372,18 +2444,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: video_player_android
|
||||
sha256: "7f8f25d7ad56819a82b2948357f3c3af071f6a678db33833b26ec36bbc221316"
|
||||
sha256: "4dd9b8b86d70d65eecf3dcabfcdfbb9c9115d244d022654aba49a00336d540c2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.11"
|
||||
version: "2.4.12"
|
||||
video_player_avfoundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: video_player_avfoundation
|
||||
sha256: bc923884640d6dc403050586eb40713cdb8d1d84e6886d8aca50ab04c59124c2
|
||||
sha256: "309e3962795e761be010869bae65c0b0e45b5230c5cee1bec72197ca7db040ed"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.2"
|
||||
version: "2.5.6"
|
||||
video_player_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -2420,10 +2492,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: c620a6f783fa22436da68e42db7ebbf18b8c44b9a46ab911f666ff09ffd9153f
|
||||
sha256: c538be99af830f478718b51630ec1b6bee5e74e52c8a802d328d9e71d35d2583
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "11.7.1"
|
||||
version: "11.10.0"
|
||||
volume_controller:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -2468,10 +2540,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
|
||||
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.4-beta"
|
||||
version: "0.3.0"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -2500,10 +2572,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: wechat_assets_picker
|
||||
sha256: f78c7797dc88e3c9170d318acc9f535ca104ab648cc69ab3b7745f1ceac29910
|
||||
sha256: "9934724a45fdb2b12e332d8190c58713e6675c37c630d53608e0f50167215c9f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.8.1+1"
|
||||
version: "8.9.0-dev.1"
|
||||
widgets_to_image:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -2516,10 +2588,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574
|
||||
sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.1"
|
||||
version: "5.2.0"
|
||||
win32_registry:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -2548,10 +2620,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: xml
|
||||
sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84"
|
||||
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.0"
|
||||
version: "6.5.0"
|
||||
xmlstream:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -2577,5 +2649,5 @@ packages:
|
|||
source: hosted
|
||||
version: "3.1.2"
|
||||
sdks:
|
||||
dart: ">=3.1.0 <4.0.0"
|
||||
flutter: ">=3.13.0"
|
||||
dart: ">=3.2.3 <4.0.0"
|
||||
flutter: ">=3.16.6"
|
||||
|
|
|
@ -27,6 +27,7 @@ dependencies:
|
|||
battery_info: ^1.1.1
|
||||
bip39: ^1.0.6
|
||||
cached_network_image: ^3.0.0
|
||||
cast: ^2.0.0
|
||||
chewie:
|
||||
git:
|
||||
url: https://github.com/ente-io/chewie.git
|
||||
|
@ -59,7 +60,6 @@ dependencies:
|
|||
extended_image: ^8.1.1
|
||||
fade_indexed_stack: ^0.2.2
|
||||
fast_base58: ^0.2.1
|
||||
|
||||
figma_squircle: ^0.5.3
|
||||
file_saver:
|
||||
# Use forked version till this PR is merged: https://github.com/incrediblezayed/file_saver/pull/87
|
||||
|
@ -133,7 +133,7 @@ dependencies:
|
|||
path_provider: ^2.1.1
|
||||
pedantic: ^1.9.2
|
||||
permission_handler: ^11.0.1
|
||||
photo_manager: ^2.8.1
|
||||
photo_manager: ^3.0.0
|
||||
photo_view: ^0.14.0
|
||||
pinput: ^1.2.2
|
||||
pointycastle: ^3.7.3
|
||||
|
@ -141,7 +141,7 @@ dependencies:
|
|||
protobuf: ^3.1.0
|
||||
provider: ^6.0.0
|
||||
quiver: ^3.0.1
|
||||
receive_sharing_intent: ^1.6.7
|
||||
receive_sharing_intent: ^1.7.0
|
||||
scrollable_positioned_list: ^0.3.5
|
||||
sentry: ^7.9.0
|
||||
sentry_flutter: ^7.9.0
|
||||
|
@ -158,10 +158,6 @@ dependencies:
|
|||
syncfusion_flutter_core: ^19.2.49
|
||||
syncfusion_flutter_sliders: ^19.2.49
|
||||
synchronized: ^3.1.0
|
||||
tflite_flutter: ^0.10.1
|
||||
# tflite_flutter_helper:
|
||||
# git:
|
||||
# url: https://github.com/pnyompen/tflite_flutter_helper.git # Fixes https://github.com/am15h/tflite_flutter_helper/issues/57
|
||||
tuple: ^2.0.0
|
||||
uni_links: ^0.5.1
|
||||
url_launcher: ^6.0.3
|
||||
|
@ -179,10 +175,11 @@ dependencies:
|
|||
widgets_to_image: ^0.0.2
|
||||
|
||||
dependency_overrides:
|
||||
# current fork of tfite_flutter_helper depends on ffi: ^1.x.x
|
||||
# but we need ffi: ^2.0.1 for newer packages. The original tfite_flutter_helper
|
||||
#
|
||||
ffi: ^2.1.0
|
||||
connectivity_plus: ^4.0.0
|
||||
|
||||
#Remove this after upgrading to flutter v3.19x
|
||||
#Build fails when resolving to latest version of ffi on flutter v3.16.x
|
||||
ffi: 2.1.0
|
||||
video_player:
|
||||
git:
|
||||
url: https://github.com/ente-io/packages.git
|
||||
|
|
Loading…
Add table
Reference in a new issue