瀏覽代碼

Merge branch 'mobile_face' of https://github.com/ente-io/auth into mobile_face

Neeraj Gupta 1 年之前
父節點
當前提交
f459b1c2dd
共有 40 個文件被更改,包括 657 次插入2017 次删除
  1. 1 1
      mobile/README.md
  2. 0 91
      mobile/assets/models/cocossd/labels.txt
  3. 二進制
      mobile/assets/models/cocossd/model.tflite
  4. 二進制
      mobile/assets/models/mobilefacenet/mobilefacenet_ente_web.tflite
  5. 二進制
      mobile/assets/models/mobilefacenet/mobilefacenet_opset15.onnx
  6. 二進制
      mobile/assets/models/mobilefacenet/mobilefacenet_unq_TF211.tflite
  7. 0 1001
      mobile/assets/models/mobilenet/labels_mobilenet_quant_v1_224.txt
  8. 二進制
      mobile/assets/models/mobilenet/mobilenet_v1_1.0_224_quant.tflite
  9. 0 30
      mobile/assets/models/scenes/labels.txt
  10. 二進制
      mobile/assets/models/scenes/model.tflite
  11. 二進制
      mobile/assets/models/yolov5face/yolov5s_face_640_640_dynamic.onnx
  12. 90 94
      mobile/ios/Podfile.lock
  13. 23 0
      mobile/ios/Runner.xcodeproj/project.pbxproj
  14. 4 3
      mobile/lib/db/device_files_db.dart
  15. 3 0
      mobile/lib/services/machine_learning/face_ml/face_detection/face_detection_exceptions.dart
  16. 22 18
      mobile/lib/services/machine_learning/face_ml/face_detection/face_detection_service.dart
  17. 0 0
      mobile/lib/services/machine_learning/face_ml/face_detection/yolo_filter_extract_detections.dart
  18. 0 3
      mobile/lib/services/machine_learning/face_ml/face_detection/yolov5face/yolo_face_detection_exceptions.dart
  19. 0 31
      mobile/lib/services/machine_learning/face_ml/face_detection/yolov5face/yolo_face_detection_options.dart
  20. 0 22
      mobile/lib/services/machine_learning/face_ml/face_detection/yolov5face/yolo_model_config.dart
  21. 0 15
      mobile/lib/services/machine_learning/face_ml/face_embedding/face_embedding_options.dart
  22. 193 223
      mobile/lib/services/machine_learning/face_ml/face_embedding/face_embedding_service.dart
  23. 0 20
      mobile/lib/services/machine_learning/face_ml/face_embedding/mobilefacenet_model_config.dart
  24. 0 246
      mobile/lib/services/machine_learning/face_ml/face_embedding/onnx_face_embedding.dart
  25. 2 2
      mobile/lib/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart
  26. 18 17
      mobile/lib/services/machine_learning/face_ml/face_ml_service.dart
  27. 4 1
      mobile/lib/ui/account/email_entry_page.dart
  28. 4 2
      mobile/lib/ui/account/login_page.dart
  29. 3 2
      mobile/lib/ui/account/login_pwd_verification_page.dart
  30. 24 20
      mobile/lib/ui/account/ott_verification_page.dart
  31. 4 2
      mobile/lib/ui/account/password_reentry_page.dart
  32. 4 2
      mobile/lib/ui/account/recovery_page.dart
  33. 3 2
      mobile/lib/ui/account/request_pwd_verification_page.dart
  34. 4 1
      mobile/lib/ui/account/sessions_page.dart
  35. 8 3
      mobile/lib/ui/components/toggle_switch_widget.dart
  36. 3 1
      mobile/lib/ui/home/status_bar_widget.dart
  37. 5 3
      mobile/lib/ui/tabs/home_widget.dart
  38. 6 1
      mobile/lib/ui/tabs/user_collections_tab.dart
  39. 221 149
      mobile/pubspec.lock
  40. 8 11
      mobile/pubspec.yaml

+ 1 - 1
mobile/README.md

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

+ 0 - 91
mobile/assets/models/cocossd/labels.txt

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

二進制
mobile/assets/models/cocossd/model.tflite


二進制
mobile/assets/models/mobilefacenet/mobilefacenet_ente_web.tflite


二進制
mobile/assets/models/mobilefacenet/mobilefacenet_opset15.onnx


二進制
mobile/assets/models/mobilefacenet/mobilefacenet_unq_TF211.tflite


+ 0 - 1001
mobile/assets/models/mobilenet/labels_mobilenet_quant_v1_224.txt

@@ -1,1001 +0,0 @@
-background
-tench
-goldfish
-great white shark
-tiger shark
-hammerhead
-electric ray
-stingray
-cock
-hen
-ostrich
-brambling
-goldfinch
-house finch
-junco
-indigo bunting
-robin
-bulbul
-jay
-magpie
-chickadee
-water ouzel
-kite
-bald eagle
-vulture
-great grey owl
-European fire salamander
-common newt
-eft
-spotted salamander
-axolotl
-bullfrog
-tree frog
-tailed frog
-loggerhead
-leatherback turtle
-mud turtle
-terrapin
-box turtle
-banded gecko
-common iguana
-American chameleon
-whiptail
-agama
-frilled lizard
-alligator lizard
-Gila monster
-green lizard
-African chameleon
-Komodo dragon
-African crocodile
-American alligator
-triceratops
-thunder snake
-ringneck snake
-hognose snake
-green snake
-king snake
-garter snake
-water snake
-vine snake
-night snake
-boa constrictor
-rock python
-Indian cobra
-green mamba
-sea snake
-horned viper
-diamondback
-sidewinder
-trilobite
-harvestman
-scorpion
-black and gold garden spider
-barn spider
-garden spider
-black widow
-tarantula
-wolf spider
-tick
-centipede
-black grouse
-ptarmigan
-ruffed grouse
-prairie chicken
-peacock
-quail
-partridge
-African grey
-macaw
-sulphur-crested cockatoo
-lorikeet
-coucal
-bee eater
-hornbill
-hummingbird
-jacamar
-toucan
-drake
-red-breasted merganser
-goose
-black swan
-tusker
-echidna
-platypus
-wallaby
-koala
-wombat
-jellyfish
-sea anemone
-brain coral
-flatworm
-nematode
-conch
-snail
-slug
-sea slug
-chiton
-chambered nautilus
-Dungeness crab
-rock crab
-fiddler crab
-king crab
-American lobster
-spiny lobster
-crayfish
-hermit crab
-isopod
-white stork
-black stork
-spoonbill
-flamingo
-little blue heron
-American egret
-bittern
-crane
-limpkin
-European gallinule
-American coot
-bustard
-ruddy turnstone
-red-backed sandpiper
-redshank
-dowitcher
-oystercatcher
-pelican
-king penguin
-albatross
-grey whale
-killer whale
-dugong
-sea lion
-Chihuahua
-Japanese spaniel
-Maltese dog
-Pekinese
-Shih-Tzu
-Blenheim spaniel
-papillon
-toy terrier
-Rhodesian ridgeback
-Afghan hound
-basset
-beagle
-bloodhound
-bluetick
-black-and-tan coonhound
-Walker hound
-English foxhound
-redbone
-borzoi
-Irish wolfhound
-Italian greyhound
-whippet
-Ibizan hound
-Norwegian elkhound
-otterhound
-Saluki
-Scottish deerhound
-Weimaraner
-Staffordshire bullterrier
-American Staffordshire terrier
-Bedlington terrier
-Border terrier
-Kerry blue terrier
-Irish terrier
-Norfolk terrier
-Norwich terrier
-Yorkshire terrier
-wire-haired fox terrier
-Lakeland terrier
-Sealyham terrier
-Airedale
-cairn
-Australian terrier
-Dandie Dinmont
-Boston bull
-miniature schnauzer
-giant schnauzer
-standard schnauzer
-Scotch terrier
-Tibetan terrier
-silky terrier
-soft-coated wheaten terrier
-West Highland white terrier
-Lhasa
-flat-coated retriever
-curly-coated retriever
-golden retriever
-Labrador retriever
-Chesapeake Bay retriever
-German short-haired pointer
-vizsla
-English setter
-Irish setter
-Gordon setter
-Brittany spaniel
-clumber
-English springer
-Welsh springer spaniel
-cocker spaniel
-Sussex spaniel
-Irish water spaniel
-kuvasz
-schipperke
-groenendael
-malinois
-briard
-kelpie
-komondor
-Old English sheepdog
-Shetland sheepdog
-collie
-Border collie
-Bouvier des Flandres
-Rottweiler
-German shepherd
-Doberman
-miniature pinscher
-Greater Swiss Mountain dog
-Bernese mountain dog
-Appenzeller
-EntleBucher
-boxer
-bull mastiff
-Tibetan mastiff
-French bulldog
-Great Dane
-Saint Bernard
-Eskimo dog
-malamute
-Siberian husky
-dalmatian
-affenpinscher
-basenji
-pug
-Leonberg
-Newfoundland
-Great Pyrenees
-Samoyed
-Pomeranian
-chow
-keeshond
-Brabancon griffon
-Pembroke
-Cardigan
-toy poodle
-miniature poodle
-standard poodle
-Mexican hairless
-timber wolf
-white wolf
-red wolf
-coyote
-dingo
-dhole
-African hunting dog
-hyena
-red fox
-kit fox
-Arctic fox
-grey fox
-tabby
-tiger cat
-Persian cat
-Siamese cat
-Egyptian cat
-cougar
-lynx
-leopard
-snow leopard
-jaguar
-lion
-tiger
-cheetah
-brown bear
-American black bear
-ice bear
-sloth bear
-mongoose
-meerkat
-tiger beetle
-ladybug
-ground beetle
-long-horned beetle
-leaf beetle
-dung beetle
-rhinoceros beetle
-weevil
-fly
-bee
-ant
-grasshopper
-cricket
-walking stick
-cockroach
-mantis
-cicada
-leafhopper
-lacewing
-dragonfly
-damselfly
-admiral
-ringlet
-monarch
-cabbage butterfly
-sulphur butterfly
-lycaenid
-starfish
-sea urchin
-sea cucumber
-wood rabbit
-hare
-Angora
-hamster
-porcupine
-fox squirrel
-marmot
-beaver
-guinea pig
-sorrel
-zebra
-hog
-wild boar
-warthog
-hippopotamus
-ox
-water buffalo
-bison
-ram
-bighorn
-ibex
-hartebeest
-impala
-gazelle
-Arabian camel
-llama
-weasel
-mink
-polecat
-black-footed ferret
-otter
-skunk
-badger
-armadillo
-three-toed sloth
-orangutan
-gorilla
-chimpanzee
-gibbon
-siamang
-guenon
-patas
-baboon
-macaque
-langur
-colobus
-proboscis monkey
-marmoset
-capuchin
-howler monkey
-titi
-spider monkey
-squirrel monkey
-Madagascar cat
-indri
-Indian elephant
-African elephant
-lesser panda
-giant panda
-barracouta
-eel
-coho
-rock beauty
-anemone fish
-sturgeon
-gar
-lionfish
-puffer
-abacus
-abaya
-academic gown
-accordion
-acoustic guitar
-aircraft carrier
-airliner
-airship
-altar
-ambulance
-amphibian
-analog clock
-apiary
-apron
-ashcan
-assault rifle
-backpack
-bakery
-balance beam
-balloon
-ballpoint
-Band Aid
-banjo
-bannister
-barbell
-barber chair
-barbershop
-barn
-barometer
-barrel
-barrow
-baseball
-basketball
-bassinet
-bassoon
-bathing cap
-bath towel
-bathtub
-beach wagon
-beacon
-beaker
-bearskin
-beer bottle
-beer glass
-bell cote
-bib
-bicycle-built-for-two
-bikini
-binder
-binoculars
-birdhouse
-boathouse
-bobsled
-bolo tie
-bonnet
-bookcase
-bookshop
-bottlecap
-bow
-bow tie
-brass
-brassiere
-breakwater
-breastplate
-broom
-bucket
-buckle
-bulletproof vest
-bullet train
-butcher shop
-cab
-caldron
-candle
-cannon
-canoe
-can opener
-cardigan
-car mirror
-carousel
-carpenter's kit
-carton
-car wheel
-cash machine
-cassette
-cassette player
-castle
-catamaran
-CD player
-cello
-cellular telephone
-chain
-chainlink fence
-chain mail
-chain saw
-chest
-chiffonier
-chime
-china cabinet
-Christmas stocking
-church
-cinema
-cleaver
-cliff dwelling
-cloak
-clog
-cocktail shaker
-coffee mug
-coffeepot
-coil
-combination lock
-computer keyboard
-confectionery
-container ship
-convertible
-corkscrew
-cornet
-cowboy boot
-cowboy hat
-cradle
-crane
-crash helmet
-crate
-crib
-Crock Pot
-croquet ball
-crutch
-cuirass
-dam
-desk
-desktop computer
-dial telephone
-diaper
-digital clock
-digital watch
-dining table
-dishrag
-dishwasher
-disk brake
-dock
-dogsled
-dome
-doormat
-drilling platform
-drum
-drumstick
-dumbbell
-Dutch oven
-electric fan
-electric guitar
-electric locomotive
-entertainment center
-envelope
-espresso maker
-face powder
-feather boa
-file
-fireboat
-fire engine
-fire screen
-flagpole
-flute
-folding chair
-football helmet
-forklift
-fountain
-fountain pen
-four-poster
-freight car
-French horn
-frying pan
-fur coat
-garbage truck
-gasmask
-gas pump
-goblet
-go-kart
-golf ball
-golfcart
-gondola
-gong
-gown
-grand piano
-greenhouse
-grille
-grocery store
-guillotine
-hair slide
-hair spray
-half track
-hammer
-hamper
-hand blower
-hand-held computer
-handkerchief
-hard disc
-harmonica
-harp
-harvester
-hatchet
-holster
-home theater
-honeycomb
-hook
-hoopskirt
-horizontal bar
-horse cart
-hourglass
-iPod
-iron
-jack-o'-lantern
-jean
-jeep
-jersey
-jigsaw puzzle
-jinrikisha
-joystick
-kimono
-knee pad
-knot
-lab coat
-ladle
-lampshade
-laptop
-lawn mower
-lens cap
-letter opener
-library
-lifeboat
-lighter
-limousine
-liner
-lipstick
-Loafer
-lotion
-loudspeaker
-loupe
-lumbermill
-magnetic compass
-mailbag
-mailbox
-maillot
-maillot
-manhole cover
-maraca
-marimba
-mask
-matchstick
-maypole
-maze
-measuring cup
-medicine chest
-megalith
-microphone
-microwave
-military uniform
-milk can
-minibus
-miniskirt
-minivan
-missile
-mitten
-mixing bowl
-mobile home
-Model T
-modem
-monastery
-monitor
-moped
-mortar
-mortarboard
-mosque
-mosquito net
-motor scooter
-mountain bike
-mountain tent
-mouse
-mousetrap
-moving van
-muzzle
-nail
-neck brace
-necklace
-nipple
-notebook
-obelisk
-oboe
-ocarina
-odometer
-oil filter
-organ
-oscilloscope
-overskirt
-oxcart
-oxygen mask
-packet
-paddle
-paddlewheel
-padlock
-paintbrush
-pajama
-palace
-panpipe
-paper towel
-parachute
-parallel bars
-park bench
-parking meter
-passenger car
-patio
-pay-phone
-pedestal
-pencil box
-pencil sharpener
-perfume
-Petri dish
-photocopier
-pick
-pickelhaube
-picket fence
-pickup
-pier
-piggy bank
-pill bottle
-pillow
-ping-pong ball
-pinwheel
-pirate
-pitcher
-plane
-planetarium
-plastic bag
-plate rack
-plow
-plunger
-Polaroid camera
-pole
-police van
-poncho
-pool table
-pop bottle
-pot
-potter's wheel
-power drill
-prayer rug
-printer
-prison
-projectile
-projector
-puck
-punching bag
-purse
-quill
-quilt
-racer
-racket
-radiator
-radio
-radio telescope
-rain barrel
-recreational vehicle
-reel
-reflex camera
-refrigerator
-remote control
-restaurant
-revolver
-rifle
-rocking chair
-rotisserie
-rubber eraser
-rugby ball
-rule
-running shoe
-safe
-safety pin
-saltshaker
-sandal
-sarong
-sax
-scabbard
-scale
-school bus
-schooner
-scoreboard
-screen
-screw
-screwdriver
-seat belt
-sewing machine
-shield
-shoe shop
-shoji
-shopping basket
-shopping cart
-shovel
-shower cap
-shower curtain
-ski
-ski mask
-sleeping bag
-slide rule
-sliding door
-slot
-snorkel
-snowmobile
-snowplow
-soap dispenser
-soccer ball
-sock
-solar dish
-sombrero
-soup bowl
-space bar
-space heater
-space shuttle
-spatula
-speedboat
-spider web
-spindle
-sports car
-spotlight
-stage
-steam locomotive
-steel arch bridge
-steel drum
-stethoscope
-stole
-stone wall
-stopwatch
-stove
-strainer
-streetcar
-stretcher
-studio couch
-stupa
-submarine
-suit
-sundial
-sunglass
-sunglasses
-sunscreen
-suspension bridge
-swab
-sweatshirt
-swimming trunks
-swing
-switch
-syringe
-table lamp
-tank
-tape player
-teapot
-teddy
-television
-tennis ball
-thatch
-theater curtain
-thimble
-thresher
-throne
-tile roof
-toaster
-tobacco shop
-toilet seat
-torch
-totem pole
-tow truck
-toyshop
-tractor
-trailer truck
-tray
-trench coat
-tricycle
-trimaran
-tripod
-triumphal arch
-trolleybus
-trombone
-tub
-turnstile
-typewriter keyboard
-umbrella
-unicycle
-upright
-vacuum
-vase
-vault
-velvet
-vending machine
-vestment
-viaduct
-violin
-volleyball
-waffle iron
-wall clock
-wallet
-wardrobe
-warplane
-washbasin
-washer
-water bottle
-water jug
-water tower
-whiskey jug
-whistle
-wig
-window screen
-window shade
-Windsor tie
-wine bottle
-wing
-wok
-wooden spoon
-wool
-worm fence
-wreck
-yawl
-yurt
-web site
-comic book
-crossword puzzle
-street sign
-traffic light
-book jacket
-menu
-plate
-guacamole
-consomme
-hot pot
-trifle
-ice cream
-ice lolly
-French loaf
-bagel
-pretzel
-cheeseburger
-hotdog
-mashed potato
-head cabbage
-broccoli
-cauliflower
-zucchini
-spaghetti squash
-acorn squash
-butternut squash
-cucumber
-artichoke
-bell pepper
-cardoon
-mushroom
-Granny Smith
-strawberry
-orange
-lemon
-fig
-pineapple
-banana
-jackfruit
-custard apple
-pomegranate
-hay
-carbonara
-chocolate sauce
-dough
-meat loaf
-pizza
-potpie
-burrito
-red wine
-espresso
-cup
-eggnog
-alp
-bubble
-cliff
-coral reef
-geyser
-lakeside
-promontory
-sandbar
-seashore
-valley
-volcano
-ballplayer
-groom
-scuba diver
-rapeseed
-daisy
-yellow lady's slipper
-corn
-acorn
-hip
-buckeye
-coral fungus
-agaric
-gyromitra
-stinkhorn
-earthstar
-hen-of-the-woods
-bolete
-ear
-toilet tissue

二進制
mobile/assets/models/mobilenet/mobilenet_v1_1.0_224_quant.tflite


+ 0 - 30
mobile/assets/models/scenes/labels.txt

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

二進制
mobile/assets/models/scenes/model.tflite


二進制
mobile/assets/models/yolov5face/yolov5s_face_640_640_dynamic.onnx


+ 90 - 94
mobile/ios/Podfile.lock

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

+ 23 - 0
mobile/ios/Runner.xcodeproj/project.pbxproj

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

+ 4 - 3
mobile/lib/db/device_files_db.dart

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

+ 3 - 0
mobile/lib/services/machine_learning/face_ml/face_detection/face_detection_exceptions.dart

@@ -0,0 +1,3 @@
+class YOLOFaceInterpreterInitializationException implements Exception {}
+
+class YOLOFaceInterpreterRunException implements Exception {}

+ 22 - 18
mobile/lib/services/machine_learning/face_ml/face_detection/yolov5face/onnx_face_detection.dart → mobile/lib/services/machine_learning/face_ml/face_detection/face_detection_service.dart

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

+ 0 - 0
mobile/lib/services/machine_learning/face_ml/face_detection/yolov5face/yolo_filter_extract_detections.dart → mobile/lib/services/machine_learning/face_ml/face_detection/yolo_filter_extract_detections.dart


+ 0 - 3
mobile/lib/services/machine_learning/face_ml/face_detection/yolov5face/yolo_face_detection_exceptions.dart

@@ -1,3 +0,0 @@
-class YOLOInterpreterInitializationException implements Exception {}
-
-class YOLOInterpreterRunException implements Exception {}

+ 0 - 31
mobile/lib/services/machine_learning/face_ml/face_detection/yolov5face/yolo_face_detection_options.dart

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

+ 0 - 22
mobile/lib/services/machine_learning/face_ml/face_detection/yolov5face/yolo_model_config.dart

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

+ 0 - 15
mobile/lib/services/machine_learning/face_ml/face_embedding/face_embedding_options.dart

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

+ 193 - 223
mobile/lib/services/machine_learning/face_ml/face_embedding/face_embedding_service.dart

@@ -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 {
-      _interpreter?.close();
-      _interpreter = null;
-      await _isolateInterpreter?.close();
-      _isolateInterpreter = null;
-    } catch (e) {
-      _logger.severe('Error while closing interpreter: $e');
-      rethrow;
+      // _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;
   }
 
-  /// 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,
+  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(_interpreter != null && _isolateInterpreter != null);
-
-    final stopwatch = Stopwatch()..start();
+    assert(sessionAddress != 0 && sessionAddress != -1 && isInitialized);
 
-    // Image decoding and preprocessing
-    List<List<List<List<num>>>> input;
-    List output;
     try {
       final stopwatchDecoding = Stopwatch()..start();
-      final (inputImageMatrix, _, _, _, _) =
-          await ImageMlIsolate.instance.preprocessMobileFaceNet(
-        imageData,
+      final (inputImageList, _, isBlur, blurValue, _) =
+          await ImageMlIsolate.instance.preprocessMobileFaceNetOnnx(
+        imagePath,
         [face],
       );
-      input = inputImageMatrix;
       stopwatchDecoding.stop();
       _logger.info(
-        'Image decoding and preprocessing is finished, in ${stopwatchDecoding.elapsedMilliseconds}ms',
+        'MobileFaceNet 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;
-  }
-
-  Future<List<List<double>>> predict(
-    List<Num3DInputMatrix> inputImageMatrix,
-  ) async {
-    assert(_interpreter != null && _isolateInterpreter != null);
-
-    final stopwatch = Stopwatch()..start();
-
-    _checkPreprocessedInput(inputImageMatrix); // [inputHeight, inputWidth, 3]
-    final input = [inputImageMatrix];
-    // await encodeAndSaveData(inputImageMatrix, 'input_mobilefacenet');
+      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',
+      );
 
-    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(
+        '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)}',
+      );
 
-    _logger.info('interpreter.run is called');
-    // Run inference
-    final stopwatchInterpreter = Stopwatch()..start();
-    try {
-      await _isolateInterpreter!.runForMultipleInputs(input, output);
-      // _interpreter!.runForMultipleInputs(input, output);
-      // ignore: avoid_catches_without_on_clauses
+      return (embedding, isBlur[0], blurValue[0]);
     } catch (e) {
-      _logger.severe('Error while running inference: $e');
-      throw MobileFaceNetInterpreterRunException();
-    }
-    stopwatchInterpreter.stop();
-    _logger.info(
-      'interpreter.run is finished, in ${stopwatchInterpreter.elapsedMilliseconds}ms',
-    );
-    // _logger.info('output: $output');
-
-    // 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);
+      _logger.info('MobileFaceNet Error while running inference: $e');
+      rethrow;
     }
-    // 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;
+  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;
       }
-    }
-
-    stopwatch.stop();
-    _logger.info(
-      'predictBatch() executed in ${stopwatch.elapsedMilliseconds}ms',
-    );
-
-    return embeddings;
+    });
   }
 
-  Future<void> _loadModel() async {
-    _logger.info('loadModel is called');
-
+  static Future<List<List<double>>> predictSync(
+    Float32List input,
+    int sessionAddress,
+  ) async {
+    assert(sessionAddress != 0 && sessionAddress != -1);
     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,
+      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',
       );
-      _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
+      return embeddings;
     } catch (e) {
-      _logger.severe('Error while creating interpreter: $e');
-      throw MobileFaceNetInterpreterInitializationException();
+      _logger.info('MobileFaceNet Error while running inference: $e');
+      rethrow;
     }
   }
 
-  void _checkPreprocessedInput(
-    List<Num3DInputMatrix> inputMatrix,
-  ) {
-    final embeddingOptions = config.faceEmbeddingOptions;
-
-    if (inputMatrix.isEmpty) {
-      // Check if the input is empty
-      throw MobileFaceNetEmptyInput();
-    }
+  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);
+  }
 
-    // Check if the input is the correct size
-    if (inputMatrix[0].length != embeddingOptions.inputHeight ||
-        inputMatrix[0][0].length != embeddingOptions.inputWidth) {
-      throw MobileFaceNetWrongInputSize();
+  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;
+      }
     }
 
-    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();
-    }
+    return embeddings;
   }
 }

+ 0 - 20
mobile/lib/services/machine_learning/face_ml/face_embedding/mobilefacenet_model_config.dart

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

+ 0 - 246
mobile/lib/services/machine_learning/face_ml/face_embedding/onnx_face_embedding.dart

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

+ 2 - 2
mobile/lib/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart

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

+ 18 - 17
mobile/lib/services/machine_learning/face_ml/face_ml_service.dart

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

+ 4 - 1
mobile/lib/ui/account/email_entry_page.dart

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

+ 4 - 2
mobile/lib/ui/account/login_page.dart

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

+ 3 - 2
mobile/lib/ui/account/login_pwd_verification_page.dart

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

+ 24 - 20
mobile/lib/ui/account/ott_verification_page.dart

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

+ 4 - 2
mobile/lib/ui/account/password_reentry_page.dart

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

+ 4 - 2
mobile/lib/ui/account/recovery_page.dart

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

+ 3 - 2
mobile/lib/ui/account/request_pwd_verification_page.dart

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

+ 4 - 1
mobile/lib/ui/account/sessions_page.dart

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

+ 8 - 3
mobile/lib/ui/components/toggle_switch_widget.dart

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

+ 3 - 1
mobile/lib/ui/home/status_bar_widget.dart

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

+ 5 - 3
mobile/lib/ui/tabs/home_widget.dart

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

+ 6 - 1
mobile/lib/ui/tabs/user_collections_tab.dart

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

+ 221 - 149
mobile/pubspec.lock

@@ -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.37"
+  local_auth_darwin:
+    dependency: transitive
+    description:
+      name: local_auth_darwin
+      sha256: "33381a15b0de2279523eca694089393bb146baebdce72a404555d03174ebc1e9"
       url: "https://pub.dev"
     source: hosted
-    version: "1.0.36"
+    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"

+ 8 - 11
mobile/pubspec.yaml

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