From d19041f334efb6e536a91e9893583e6395e2cefa Mon Sep 17 00:00:00 2001 From: Jiten Basnet Date: Thu, 30 Oct 2025 15:14:13 +0545 Subject: [PATCH 1/7] :up: update packages --- android/build.gradle | 28 ++++++-- example/android/app/build.gradle | 4 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- example/android/settings.gradle | 4 +- example/pubspec.lock | 64 +++++++++++-------- pubspec.yaml | 13 ++-- 6 files changed, 73 insertions(+), 42 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 16acf69..e0de5ea 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,14 +2,13 @@ group 'com.conezi.face_camera' version '1.0-SNAPSHOT' buildscript { - ext.kotlin_version = '1.6.10' + ext.kotlin_version = '1.8.22' repositories { google() mavenCentral() } - dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' + classpath 'com.android.tools.build:gradle:7.3.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -30,7 +29,8 @@ android { namespace 'com.conezi.face_camera' } compileSdkVersion 34 - + + // Enable Java 8 features compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -50,5 +50,23 @@ android { } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + implementation 'androidx.annotation:annotation:1.6.0' + implementation 'androidx.core:core-ktx:1.10.1' + implementation 'com.google.android.gms:play-services-mlkit-face-detection:17.1.0' + + // CameraX dependencies + def camerax_version = '1.3.0' + implementation "androidx.camera:camera-core:${camerax_version}" + implementation "androidx.camera:camera-camera2:${camerax_version}" + implementation "androidx.camera:camera-lifecycle:${camerax_version}" + implementation "androidx.camera:camera-view:${camerax_version}" + implementation "androidx.camera:camera-extensions:${camerax_version}" + + // Lifecycle components + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1' + implementation 'androidx.lifecycle:lifecycle-common-java8:2.6.1' + + // CameraX View class + implementation 'androidx.camera:camera-view:1.3.0' } diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 6279628..5e18be5 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -25,7 +25,7 @@ if (flutterVersionName == null) { android { namespace "com.conezi.face_camera_example" - compileSdkVersion flutter.compileSdkVersion + compileSdkVersion 36 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -43,7 +43,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.conezi.face_camera_example" - minSdkVersion 21 + minSdkVersion flutter.minSdkVersion targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index e6b38c2..8f3239a 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle index db7675c..0aa3bfd 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -18,8 +18,8 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.1.0" apply false - id "org.jetbrains.kotlin.android" version "1.8.22" apply false + id "com.android.application" version "8.13.0" apply false + id "org.jetbrains.kotlin.android" version "2.2.20" apply false } include ":app" \ No newline at end of file diff --git a/example/pubspec.lock b/example/pubspec.lock index d5e2924..455d505 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -21,34 +21,42 @@ packages: dependency: transitive description: name: camera - sha256: "26ff41045772153f222ffffecba711a206f670f5834d40ebf5eed3811692f167" + sha256: dfa8fc5a1adaeb95e7a54d86a5bd56f4bb0e035515354c8ac6d262e35cec2ec8 url: "https://pub.dev" source: hosted - version: "0.11.0+2" + version: "0.10.6" + camera_android: + dependency: transitive + description: + name: camera_android + sha256: "8397c4fcec4f4dbafdeff994adc6ed16dcaa4a25f02e70e3b8fbe59c9a88807f" + url: "https://pub.dev" + source: hosted + version: "0.10.10+11" camera_android_camerax: dependency: transitive description: name: camera_android_camerax - sha256: "59967e6d80df9d682a33b86f228cc524e6b52d6184b84f6ac62151dd98bd1ea0" + sha256: b68b638e5e0ede21155e670493ac568981a8f56c5f636d720935a916a1c5a0ef url: "https://pub.dev" source: hosted - version: "0.6.5+2" + version: "0.6.24" camera_avfoundation: dependency: transitive description: name: camera_avfoundation - sha256: "7d021e8cd30d9b71b8b92b4ad669e80af432d722d18d6aac338572754a786c15" + sha256: "34bcd5db30e52414f1f0783c5e3f566909fab14141a21b3b576c78bd35382bf6" url: "https://pub.dev" source: hosted - version: "0.9.16" + version: "0.9.22+4" camera_platform_interface: dependency: transitive description: name: camera_platform_interface - sha256: a250314a48ea337b35909a4c9d5416a208d736dcb01d0b02c6af122be66660b0 + sha256: ea1ef6ba79cdbed93df2d3eeef11542a90dec24dbcd9cde574926b86d7a09a10 url: "https://pub.dev" source: hosted - version: "2.7.4" + version: "2.11.0" camera_web: dependency: transitive description: @@ -108,10 +116,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.3" flutter: dependency: "direct main" description: flutter @@ -129,10 +137,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f" + sha256: "306f0596590e077338312f38837f595c04f28d6cdeeac392d3d74df2f0003687" url: "https://pub.dev" source: hosted - version: "2.0.19" + version: "2.0.32" flutter_test: dependency: "direct dev" description: flutter @@ -147,18 +155,18 @@ packages: dependency: transitive description: name: google_mlkit_commons - sha256: "7e9a6d6e66b44aa8cfe944bda9bc3346c52486dd890ca49e5bc98845cda40d7f" + sha256: "8f40fbac10685cad4715d11e6a0d86837d9ad7168684dfcad29610282a88e67a" url: "https://pub.dev" source: hosted - version: "0.9.0" + version: "0.11.0" google_mlkit_face_detection: dependency: transitive description: name: google_mlkit_face_detection - sha256: "65988405c884fd84a4ccc8bded7b5e3e4c33362f6f4eaaa94818bdaaba7bab7d" + sha256: f336737d5b8a86797fd4368f42a5c26aeaa9c6dcc5243f0a16b5f6f663cfb70a url: "https://pub.dev" source: hosted - version: "0.12.0" + version: "0.13.1" js: dependency: transitive description: @@ -171,26 +179,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "11.0.2" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: @@ -296,18 +304,18 @@ packages: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.6" vector_math: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: @@ -317,5 +325,5 @@ packages: source: hosted version: "14.3.1" sdks: - dart: ">=3.7.0-0 <4.0.0" - flutter: ">=3.19.0" + dart: ">=3.9.0 <4.0.0" + flutter: ">=3.35.0" diff --git a/pubspec.yaml b/pubspec.yaml index acc3f06..2581f19 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,14 +4,19 @@ version: 0.1.4 homepage: https://github.com/Conezi/face_camera environment: - sdk: '>=2.18.4 <4.0.0' - flutter: ">=2.5.0" + sdk: ">=3.8.0 <=4.0.0" + flutter: ">=3.0.0" dependencies: flutter: sdk: flutter - camera: ^0.11.0+2 - google_mlkit_face_detection: ^0.12.0 + camera: ^0.10.5+3 + google_mlkit_face_detection: ^0.13.1 + flutter_plugin_android_lifecycle: ^2.0.16 + camera_android_camerax: ^0.6.24 + +dependency_overrides: + camera_platform_interface: ^2.8.1 dev_dependencies: flutter_test: From 26b4b9af11173cef66b23cc7a9d3e8bc5edc4b5f Mon Sep 17 00:00:00 2001 From: Jiten Basnet Date: Fri, 31 Oct 2025 11:42:37 +0545 Subject: [PATCH 2/7] :up: update to use intial widget --- example/pubspec.lock | 12 +- lib/src/smart_face_camera.dart | 266 +++++++++++++++++++-------------- pubspec.yaml | 4 +- 3 files changed, 160 insertions(+), 122 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index 455d505..2df3d66 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -21,18 +21,10 @@ packages: dependency: transitive description: name: camera - sha256: dfa8fc5a1adaeb95e7a54d86a5bd56f4bb0e035515354c8ac6d262e35cec2ec8 + sha256: eefad89f262a873f38d21e5eec853461737ea074d7c9ede39f3ceb135d201cab url: "https://pub.dev" source: hosted - version: "0.10.6" - camera_android: - dependency: transitive - description: - name: camera_android - sha256: "8397c4fcec4f4dbafdeff994adc6ed16dcaa4a25f02e70e3b8fbe59c9a88807f" - url: "https://pub.dev" - source: hosted - version: "0.10.10+11" + version: "0.11.3" camera_android_camerax: dependency: transitive description: diff --git a/lib/src/smart_face_camera.dart b/lib/src/smart_face_camera.dart index 9ff4b49..26d0c47 100644 --- a/lib/src/smart_face_camera.dart +++ b/lib/src/smart_face_camera.dart @@ -8,6 +8,10 @@ import 'paints/hole_painter.dart'; import 'res/builders.dart'; class SmartFaceCamera extends StatefulWidget { + ///Initial widget to show when camera is initializing + + final Widget? initialWidget; + /// Set false to hide all controls. final bool showControls; @@ -53,29 +57,33 @@ class SmartFaceCamera extends StatefulWidget { /// The controller for the [SmartFaceCamera] widget. final FaceCameraController controller; - const SmartFaceCamera( - {required this.controller, - this.showControls = true, - this.showCaptureControl = true, - this.showFlashControl = true, - this.showCameraLensControl = true, - this.message, - this.messageStyle = const TextStyle( - fontSize: 14, height: 1.5, fontWeight: FontWeight.w400), - this.captureControlBuilder, - this.lensControlIcon, - this.flashControlBuilder, - this.messageBuilder, - this.indicatorShape = IndicatorShape.defaultShape, - this.indicatorAssetImage, - this.indicatorBuilder, - this.autoDisableCaptureControl = false, - Key? key}) - : assert( - indicatorShape != IndicatorShape.image || - indicatorAssetImage != null, - 'IndicatorAssetImage must be provided when IndicatorShape is set to image.'), - super(key: key); + const SmartFaceCamera({ + required this.controller, + this.showControls = true, + this.showCaptureControl = true, + this.showFlashControl = true, + this.showCameraLensControl = true, + this.message, + this.messageStyle = const TextStyle( + fontSize: 14, + height: 1.5, + fontWeight: FontWeight.w400, + ), + this.captureControlBuilder, + this.lensControlIcon, + this.flashControlBuilder, + this.messageBuilder, + this.indicatorShape = IndicatorShape.defaultShape, + this.indicatorAssetImage, + this.indicatorBuilder, + this.autoDisableCaptureControl = false, + this.initialWidget, + Key? key, + }) : assert( + indicatorShape != IndicatorShape.image || indicatorAssetImage != null, + 'IndicatorAssetImage must be provided when IndicatorShape is set to image.', + ), + super(key: key); @override State createState() => _SmartFaceCameraState(); @@ -139,52 +147,70 @@ class _SmartFaceCameraState extends State widget.indicatorShape != IndicatorShape.none) ...[ SizedBox( - width: - cameraController.value.previewSize!.width, - height: cameraController - .value.previewSize!.height, - child: widget.indicatorBuilder?.call( - context, - value.detectedFace, - Size( - cameraController - .value.previewSize!.height, - cameraController - .value.previewSize!.width, - )) ?? - CustomPaint( - painter: FacePainter( - face: value.detectedFace!.face, - indicatorShape: - widget.indicatorShape, - indicatorAssetImage: - widget.indicatorAssetImage, - imageSize: Size( - cameraController - .value.previewSize!.height, - cameraController - .value.previewSize!.width, - )), - )) - ] + width: + cameraController.value.previewSize!.width, + height: + cameraController.value.previewSize!.height, + child: + widget.indicatorBuilder?.call( + context, + value.detectedFace, + Size( + cameraController + .value + .previewSize! + .height, + cameraController + .value + .previewSize! + .width, + ), + ) ?? + CustomPaint( + painter: FacePainter( + face: value.detectedFace!.face, + indicatorShape: widget.indicatorShape, + indicatorAssetImage: + widget.indicatorAssetImage, + imageSize: Size( + cameraController + .value + .previewSize! + .height, + cameraController + .value + .previewSize! + .width, + ), + ), + ), + ), + ], ], ), ), ), ), ), - ) + ), ] else ...[ - const Text('No Camera Detected', - style: TextStyle( - fontSize: 18.0, - fontWeight: FontWeight.w500, - )), - CustomPaint( - size: size, - painter: HolePainter(), - ) + widget.initialWidget != null + ? widget.initialWidget! + : Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + 'No Camera Detected', + style: TextStyle( + fontSize: 18.0, + fontWeight: FontWeight.w500, + ), + ), + CustomPaint(size: size, painter: HolePainter()), + ], + ), ], + if (widget.showControls) ...[ Align( alignment: Alignment.bottomCenter, @@ -194,21 +220,21 @@ class _SmartFaceCameraState extends State mainAxisSize: MainAxisSize.min, children: [ if (widget.showFlashControl) ...[ - _flashControlWidget(value) + _flashControlWidget(value), ], if (widget.showCaptureControl) ...[ const SizedBox(width: 15), _captureControlWidget(value), - const SizedBox(width: 15) + const SizedBox(width: 15), ], if (widget.showCameraLensControl) ...[ - _lensControlWidget() + _lensControlWidget(), ], ], ), ), - ) - ] + ), + ], ], ); }, @@ -219,19 +245,30 @@ class _SmartFaceCameraState extends State Widget _cameraDisplayWidget(FaceCameraState value) { final CameraController? cameraController = value.cameraController; if (cameraController != null && cameraController.value.isInitialized) { - return CameraPreview(cameraController, child: Builder(builder: (context) { - if (widget.messageBuilder != null) { - return widget.messageBuilder!.call(context, value.detectedFace); - } - if (widget.message != null) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 55, vertical: 15), - child: Text(widget.message!, - textAlign: TextAlign.center, style: widget.messageStyle), - ); - } - return const SizedBox.shrink(); - })); + return CameraPreview( + cameraController, + child: Builder( + builder: (context) { + if (widget.messageBuilder != null) { + return widget.messageBuilder!.call(context, value.detectedFace); + } + if (widget.message != null) { + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 55, + vertical: 15, + ), + child: Text( + widget.message!, + textAlign: TextAlign.center, + style: widget.messageStyle, + ), + ); + } + return const SizedBox.shrink(); + }, + ), + ); } return const SizedBox.shrink(); } @@ -248,17 +285,19 @@ class _SmartFaceCameraState extends State /// Display the control buttons to take pictures. Widget _captureControlWidget(FaceCameraState value) { return IconButton( - icon: widget.captureControlBuilder?.call(context, value.detectedFace) ?? + icon: + widget.captureControlBuilder?.call(context, value.detectedFace) ?? CircleAvatar( - radius: 35, - foregroundColor: - widget.controller.enableControls && !_disableCapture - ? null - : Theme.of(context).disabledColor, - child: const Padding( - padding: EdgeInsets.all(8.0), - child: Icon(Icons.camera_alt, size: 35), - )), + radius: 35, + foregroundColor: + widget.controller.enableControls && !_disableCapture + ? null + : Theme.of(context).disabledColor, + child: const Padding( + padding: EdgeInsets.all(8.0), + child: Icon(Icons.camera_alt, size: 35), + ), + ), onPressed: widget.controller.enableControls && !_disableCapture ? widget.controller.captureImage : null, @@ -272,19 +311,23 @@ class _SmartFaceCameraState extends State final icon = availableFlashMode[currentFlashMode] == CameraFlashMode.always ? Icons.flash_on : availableFlashMode[currentFlashMode] == CameraFlashMode.off - ? Icons.flash_off - : Icons.flash_auto; + ? Icons.flash_off + : Icons.flash_auto; return IconButton( - icon: widget.flashControlBuilder - ?.call(context, availableFlashMode[currentFlashMode]) ?? + icon: + widget.flashControlBuilder?.call( + context, + availableFlashMode[currentFlashMode], + ) ?? CircleAvatar( - radius: 25, - foregroundColor: iconColor, - child: Padding( - padding: const EdgeInsets.all(2.0), - child: Icon(icon, size: 25), - )), + radius: 25, + foregroundColor: iconColor, + child: Padding( + padding: const EdgeInsets.all(2.0), + child: Icon(icon, size: 25), + ), + ), onPressed: widget.controller.enableControls ? widget.controller.changeFlashMode : null, @@ -294,16 +337,19 @@ class _SmartFaceCameraState extends State /// Display the control buttons to switch between camera lens. Widget _lensControlWidget() { return IconButton( - icon: widget.lensControlIcon ?? - CircleAvatar( - radius: 25, - foregroundColor: iconColor, - child: const Padding( - padding: EdgeInsets.all(2.0), - child: Icon(Icons.switch_camera_sharp, size: 25), - )), - onPressed: widget.controller.enableControls - ? widget.controller.changeCameraLens - : null); + icon: + widget.lensControlIcon ?? + CircleAvatar( + radius: 25, + foregroundColor: iconColor, + child: const Padding( + padding: EdgeInsets.all(2.0), + child: Icon(Icons.switch_camera_sharp, size: 25), + ), + ), + onPressed: widget.controller.enableControls + ? widget.controller.changeCameraLens + : null, + ); } } diff --git a/pubspec.yaml b/pubspec.yaml index 2581f19..28bc855 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,9 +10,9 @@ environment: dependencies: flutter: sdk: flutter - camera: ^0.10.5+3 + camera: ^0.11.3 google_mlkit_face_detection: ^0.13.1 - flutter_plugin_android_lifecycle: ^2.0.16 + flutter_plugin_android_lifecycle: ^2.0.32 camera_android_camerax: ^0.6.24 dependency_overrides: From 9c57c9ef542679a4d4308a82720a0d6ee567015e Mon Sep 17 00:00:00 2001 From: Jiten Basnet Date: Fri, 31 Oct 2025 13:48:25 +0545 Subject: [PATCH 3/7] :up: update example code and use imageFormatGroup in android to ImageFormatGroup.yuv420 --- android/build.gradle | 2 +- example/.gitignore | 9 +- example/.metadata | 39 ++- example/README.md | 12 +- example/analysis_options.yaml | 3 +- example/android/.gitignore | 3 +- example/android/app/build.gradle | 63 ----- example/android/app/build.gradle.kts | 44 ++++ .../android/app/src/debug/AndroidManifest.xml | 6 +- .../android/app/src/main/AndroidManifest.xml | 19 +- .../face_camera_example/MainActivity.kt | 6 - .../com/example/example/MainActivity.kt | 5 + .../app/src/main/res/values-night/styles.xml | 2 +- .../app/src/main/res/values/styles.xml | 2 +- .../app/src/profile/AndroidManifest.xml | 6 +- example/android/build.gradle | 30 --- example/android/build.gradle.kts | 24 ++ example/android/gradle.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 3 +- example/android/settings.gradle | 25 -- example/android/settings.gradle.kts | 26 ++ example/assets/images/face_net.png | Bin 9258 -> 0 bytes example/ios/Flutter/AppFrameworkInfo.plist | 2 +- example/ios/Podfile | 24 +- example/ios/Podfile.lock | 114 -------- example/ios/Runner.xcodeproj/project.pbxproj | 243 ++++++++++-------- .../xcshareddata/xcschemes/Runner.xcscheme | 13 + .../contents.xcworkspacedata | 3 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 + example/ios/Runner/AppDelegate.swift | 2 +- .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 295 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 406 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 450 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 282 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 462 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 704 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 406 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 586 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 1674 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 762 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 1226 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 1418 bytes example/ios/Runner/Info.plist | 18 +- example/ios/RunnerTests/RunnerTests.swift | 12 + example/lib/main.dart | 78 +++--- example/pubspec.lock | 50 ++-- example/pubspec.yaml | 36 ++- example/test/widget_test.dart | 25 +- .../controllers/face_camera_controller.dart | 108 ++++++-- lib/src/extension/nv21_converter.dart | 11 +- lib/src/handlers/face_identifier.dart | 66 +++-- lib/src/smart_face_camera.dart | 8 +- lib/src/utils/logger.dart | 4 +- 55 files changed, 606 insertions(+), 550 deletions(-) delete mode 100644 example/android/app/build.gradle create mode 100644 example/android/app/build.gradle.kts delete mode 100644 example/android/app/src/main/kotlin/com/conezi/face_camera_example/MainActivity.kt create mode 100644 example/android/app/src/main/kotlin/com/example/example/MainActivity.kt delete mode 100644 example/android/build.gradle create mode 100644 example/android/build.gradle.kts delete mode 100644 example/android/settings.gradle create mode 100644 example/android/settings.gradle.kts delete mode 100644 example/assets/images/face_net.png delete mode 100644 example/ios/Podfile.lock create mode 100644 example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 example/ios/RunnerTests/RunnerTests.swift diff --git a/android/build.gradle b/android/build.gradle index e0de5ea..c3b469e 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -28,7 +28,7 @@ android { if (project.android.hasProperty("namespace")) { namespace 'com.conezi.face_camera' } - compileSdkVersion 34 + compileSdkVersion 36 // Enable Java 8 features compileOptions { diff --git a/example/.gitignore b/example/.gitignore index 0fa6b67..3820a95 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -5,9 +5,12 @@ *.swp .DS_Store .atom/ +.build/ .buildlog/ .history .svn/ +.swiftpm/ +migrate_working_dir/ # IntelliJ related *.iml @@ -24,15 +27,11 @@ **/doc/api/ **/ios/Flutter/.last_build_id .dart_tool/ -.flutter-plugins .flutter-plugins-dependencies -.packages .pub-cache/ .pub/ /build/ - -# Web related -lib/generated_plugin_registrant.dart +/coverage/ # Symbolication related app.*.symbols diff --git a/example/.metadata b/example/.metadata index 3c3e4b5..5f4336f 100644 --- a/example/.metadata +++ b/example/.metadata @@ -4,7 +4,42 @@ # This file should be version controlled and should not be manually edited. version: - revision: 5464c5bac742001448fe4fc0597be939379f88ea - channel: stable + revision: "adc901062556672b4138e18a4dc62a4be8f4b3c2" + channel: "stable" project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2 + base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2 + - platform: android + create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2 + base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2 + - platform: ios + create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2 + base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2 + - platform: linux + create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2 + base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2 + - platform: macos + create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2 + base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2 + - platform: web + create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2 + base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2 + - platform: windows + create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2 + base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/example/README.md b/example/README.md index 5f6021e..2b3fce4 100644 --- a/example/README.md +++ b/example/README.md @@ -1,6 +1,6 @@ -# face_camera_example +# example -Demonstrates how to use the face_camera plugin. +A new Flutter project. ## Getting Started @@ -8,9 +8,9 @@ This project is a starting point for a Flutter application. A few resources to get you started if this is your first Flutter project: -- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) -For help getting started with Flutter, view our -[online documentation](https://flutter.dev/docs), which offers tutorials, +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, samples, guidance on mobile development, and a full API reference. diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml index 61b6c4d..0d29021 100644 --- a/example/analysis_options.yaml +++ b/example/analysis_options.yaml @@ -13,8 +13,7 @@ linter: # The lint rules applied to this project can be customized in the # section below to disable rules from the `package:flutter_lints/flutter.yaml` # included above or to enable additional rules. A list of all available lints - # and their documentation is published at - # https://dart-lang.github.io/linter/lints/index.html. + # and their documentation is published at https://dart.dev/lints. # # Instead of disabling a lint rule for the entire project in the # section below, it can also be suppressed for a single line of code diff --git a/example/android/.gitignore b/example/android/.gitignore index 6f56801..be3943c 100644 --- a/example/android/.gitignore +++ b/example/android/.gitignore @@ -5,9 +5,10 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java +.cxx/ # Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +# See https://flutter.dev/to/reference-keystore key.properties **/*.keystore **/*.jks diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle deleted file mode 100644 index 5e18be5..0000000 --- a/example/android/app/build.gradle +++ /dev/null @@ -1,63 +0,0 @@ -plugins { - id "com.android.application" - id "kotlin-android" - id "dev.flutter.flutter-gradle-plugin" -} - -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - - -android { - namespace "com.conezi.face_camera_example" - compileSdkVersion 36 - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.conezi.face_camera_example" - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} diff --git a/example/android/app/build.gradle.kts b/example/android/app/build.gradle.kts new file mode 100644 index 0000000..21ecea9 --- /dev/null +++ b/example/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.example" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.example" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml index 1e29c5c..399f698 100644 --- a/example/android/app/src/debug/AndroidManifest.xml +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index f99f728..74a78b9 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,13 +1,13 @@ - - + + + + + + + + diff --git a/example/android/app/src/main/kotlin/com/conezi/face_camera_example/MainActivity.kt b/example/android/app/src/main/kotlin/com/conezi/face_camera_example/MainActivity.kt deleted file mode 100644 index 6034078..0000000 --- a/example/android/app/src/main/kotlin/com/conezi/face_camera_example/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.conezi.face_camera_example - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt new file mode 100644 index 0000000..ac81bae --- /dev/null +++ b/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml index 3db14bb..06952be 100644 --- a/example/android/app/src/main/res/values-night/styles.xml +++ b/example/android/app/src/main/res/values-night/styles.xml @@ -3,7 +3,7 @@ diff --git a/example/android/build.gradle b/example/android/build.gradle deleted file mode 100644 index ec77c10..0000000 --- a/example/android/build.gradle +++ /dev/null @@ -1,30 +0,0 @@ -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -//workaround for plugins namespace -subprojects { - afterEvaluate { project -> - if (project.hasProperty('android')) { - project.android { - if (namespace == null) { - namespace project.group - } - } - } - } -} -subprojects { - project.evaluationDependsOn(':app') -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} diff --git a/example/android/build.gradle.kts b/example/android/build.gradle.kts new file mode 100644 index 0000000..dbee657 --- /dev/null +++ b/example/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 94adc3a..f018a61 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 8f3239a..ac3b479 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle deleted file mode 100644 index 0aa3bfd..0000000 --- a/example/android/settings.gradle +++ /dev/null @@ -1,25 +0,0 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - }() - - includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.13.0" apply false - id "org.jetbrains.kotlin.android" version "2.2.20" apply false -} - -include ":app" \ No newline at end of file diff --git a/example/android/settings.gradle.kts b/example/android/settings.gradle.kts new file mode 100644 index 0000000..fb605bc --- /dev/null +++ b/example/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/example/assets/images/face_net.png b/example/assets/images/face_net.png deleted file mode 100644 index 841b936b9d58dddfae25fa70512c49b27a902287..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9258 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 1.0 MinimumOSVersion - 12.0 + 13.0 diff --git a/example/ios/Podfile b/example/ios/Podfile index 77be1c3..620e46e 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '15.5.0' +# platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -29,31 +29,15 @@ flutter_ios_podfile_setup target 'Runner' do use_frameworks! - use_modular_headers! flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end end - -# add this line: -$iOSVersion = '15.5' # or newer version - post_install do |installer| - # add these lines: - installer.pods_project.build_configurations.each do |config| - config.build_settings["EXCLUDED_ARCHS[sdk=*]"] = "armv7" - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = $iOSVersion - end - installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) - - # add these lines: - target.build_configurations.each do |config| - if Gem::Version.new($iOSVersion) > Gem::Version.new(config.build_settings['IPHONEOS_DEPLOYMENT_TARGET']) - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = $iOSVersion - end - end - end end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock deleted file mode 100644 index 2dd766d..0000000 --- a/example/ios/Podfile.lock +++ /dev/null @@ -1,114 +0,0 @@ -PODS: - - camera_avfoundation (0.0.1): - - Flutter - - face_camera (0.0.1): - - Flutter - - Flutter (1.0.0) - - google_mlkit_commons (0.9.0): - - Flutter - - MLKitVision - - google_mlkit_face_detection (0.12.0): - - Flutter - - google_mlkit_commons - - GoogleMLKit/FaceDetection (~> 7.0.0) - - GoogleDataTransport (10.1.0): - - nanopb (~> 3.30910.0) - - PromisesObjC (~> 2.4) - - GoogleMLKit/FaceDetection (7.0.0): - - GoogleMLKit/MLKitCore - - MLKitFaceDetection (~> 6.0.0) - - GoogleMLKit/MLKitCore (7.0.0): - - MLKitCommon (~> 12.0.0) - - GoogleToolboxForMac/Defines (4.2.1) - - GoogleToolboxForMac/Logger (4.2.1): - - GoogleToolboxForMac/Defines (= 4.2.1) - - "GoogleToolboxForMac/NSData+zlib (4.2.1)": - - GoogleToolboxForMac/Defines (= 4.2.1) - - GoogleUtilities/Environment (8.0.2): - - GoogleUtilities/Privacy - - GoogleUtilities/Logger (8.0.2): - - GoogleUtilities/Environment - - GoogleUtilities/Privacy - - GoogleUtilities/Privacy (8.0.2) - - GoogleUtilities/UserDefaults (8.0.2): - - GoogleUtilities/Logger - - GoogleUtilities/Privacy - - GTMSessionFetcher/Core (3.5.0) - - MLImage (1.0.0-beta6) - - MLKitCommon (12.0.0): - - GoogleDataTransport (~> 10.0) - - GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1) - - "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)" - - GoogleUtilities/Logger (~> 8.0) - - GoogleUtilities/UserDefaults (~> 8.0) - - GTMSessionFetcher/Core (< 4.0, >= 3.3.2) - - MLKitFaceDetection (6.0.0): - - MLKitCommon (~> 12.0) - - MLKitVision (~> 8.0) - - MLKitVision (8.0.0): - - GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1) - - "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)" - - GTMSessionFetcher/Core (< 4.0, >= 3.3.2) - - MLImage (= 1.0.0-beta6) - - MLKitCommon (~> 12.0) - - nanopb (3.30910.0): - - nanopb/decode (= 3.30910.0) - - nanopb/encode (= 3.30910.0) - - nanopb/decode (3.30910.0) - - nanopb/encode (3.30910.0) - - PromisesObjC (2.4.0) - -DEPENDENCIES: - - camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`) - - face_camera (from `.symlinks/plugins/face_camera/ios`) - - Flutter (from `Flutter`) - - google_mlkit_commons (from `.symlinks/plugins/google_mlkit_commons/ios`) - - google_mlkit_face_detection (from `.symlinks/plugins/google_mlkit_face_detection/ios`) - -SPEC REPOS: - trunk: - - GoogleDataTransport - - GoogleMLKit - - GoogleToolboxForMac - - GoogleUtilities - - GTMSessionFetcher - - MLImage - - MLKitCommon - - MLKitFaceDetection - - MLKitVision - - nanopb - - PromisesObjC - -EXTERNAL SOURCES: - camera_avfoundation: - :path: ".symlinks/plugins/camera_avfoundation/ios" - face_camera: - :path: ".symlinks/plugins/face_camera/ios" - Flutter: - :path: Flutter - google_mlkit_commons: - :path: ".symlinks/plugins/google_mlkit_commons/ios" - google_mlkit_face_detection: - :path: ".symlinks/plugins/google_mlkit_face_detection/ios" - -SPEC CHECKSUMS: - camera_avfoundation: 759172d1a77ae7be0de08fc104cfb79738b8a59e - face_camera: 787c50bc183b37c9b6f9777a1416e5b384b5c234 - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - google_mlkit_commons: 384e4e206e122b6dad430d3158205e0b2fac6789 - google_mlkit_face_detection: ff627695d8eba051db7e0f13f7b20d802df1f84c - GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 - GoogleMLKit: eff9e23ec1d90ea4157a1ee2e32a4f610c5b3318 - GoogleToolboxForMac: d1a2cbf009c453f4d6ded37c105e2f67a32206d8 - GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d - GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6 - MLImage: 0ad1c5f50edd027672d8b26b0fee78a8b4a0fc56 - MLKitCommon: 07c2c33ae5640e5380beaaa6e4b9c249a205542d - MLKitFaceDetection: 2a593db4837db503ad3426b565e7aab045cefea5 - MLKitVision: 45e79d68845a2de77e2dd4d7f07947f0ed157b0e - nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 - PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 - -PODFILE CHECKSUM: 251c540b86ac8c2dbf28814f4241a9a0973eacd0 - -COCOAPODS: 1.16.2 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 02a2dd2..faa8e15 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -8,14 +8,24 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 48E4B76CE6B756A66EB1B9FD /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 40522BA8BA5918187D8063C6 /* Pods_Runner.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -30,15 +40,14 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 0CAB0517EA1190F06B296CB7 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 40522BA8BA5918187D8063C6 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 92D8FFB6E9378F3BC822909C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -46,7 +55,6 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - B2BAB4959A30BDE210540C75 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -54,13 +62,20 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 48E4B76CE6B756A66EB1B9FD /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -78,8 +93,7 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - D8BA30948EE3C25BE4ED4CDC /* Pods */, - BE0DDB5DF9CEBA6EB394DAB1 /* Frameworks */, + 331C8082294A63A400263BE5 /* RunnerTests */, ); sourceTree = ""; }; @@ -87,6 +101,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; @@ -106,40 +121,36 @@ path = Runner; sourceTree = ""; }; - BE0DDB5DF9CEBA6EB394DAB1 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 40522BA8BA5918187D8063C6 /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - D8BA30948EE3C25BE4ED4CDC /* Pods */ = { - isa = PBXGroup; - children = ( - B2BAB4959A30BDE210540C75 /* Pods-Runner.debug.xcconfig */, - 0CAB0517EA1190F06B296CB7 /* Pods-Runner.release.xcconfig */, - 92D8FFB6E9378F3BC822909C /* Pods-Runner.profile.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - A1244AD42C7D984A57BEA2D8 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 1DD9E7F292D00AC6ADD738E5 /* [CP] Embed Pods Frameworks */, - F230A7FB2012CCCFF84F8BD7 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -156,9 +167,14 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; @@ -179,11 +195,19 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -198,23 +222,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 1DD9E7F292D00AC6ADD738E5 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -246,48 +253,17 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - A1244AD42C7D984A57BEA2D8 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - 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; - }; - F230A7FB2012CCCFF84F8BD7 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, ); 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 */ 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -299,6 +275,14 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -323,6 +307,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -352,7 +337,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - "EXCLUDED_ARCHS[sdk=*]" = armv7; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -361,7 +346,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -376,29 +361,74 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 4J6G3CYQ9U; + DEVELOPMENT_TEAM = K966339N22; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.conezi.faceCameraExample; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Profile; }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -428,7 +458,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - "EXCLUDED_ARCHS[sdk=*]" = armv7; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -443,7 +473,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -455,6 +485,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -484,7 +515,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - "EXCLUDED_ARCHS[sdk=*]" = armv7; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -493,7 +524,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -510,19 +541,16 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 4J6G3CYQ9U; + DEVELOPMENT_TEAM = K966339N22; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.conezi.faceCameraExample; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -536,19 +564,16 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 4J6G3CYQ9U; + DEVELOPMENT_TEAM = K966339N22; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.conezi.faceCameraExample; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -558,6 +583,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c53e2b3..e3773d4 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -26,6 +26,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" shouldUseLaunchSchemeArgsEnv = "YES"> + + + + - - diff --git a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift index b636303..6266644 100644 --- a/example/ios/Runner/AppDelegate.swift +++ b/example/ios/Runner/AppDelegate.swift @@ -1,5 +1,5 @@ -import UIKit import Flutter +import UIKit @main @objc class AppDelegate: FlutterAppDelegate { diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 28c6bf03016f6c994b70f38d1b7346e5831b531f..7353c41ecf9ca08017312dc233d9830079b50717 100644 GIT binary patch delta 279 zcmV+y0qFj;1g8R!8Gi!+006pI?LPnj0Blf9R7L;)|5U~J`u_j-{Qm)0oAmqtj@kOz z^8J|I`-|B6ht~R5kG+%I`zf~eztraM`u^bc{`dO)zUlmg)%x%C`E}6wSI77~z4s`y z^XT{f(eM4n?EUff`e@AgO~UxV*5*r_%Uhbj5N)LaQj!wdIe!-b004GLL_t&-)18pX z4udcZ1u-#g(~z+5JN*AY5?>Gw7hsN~k)CYt4dQDFxbs5*_&e@Hj)wtt(&JE<3Eq*D z;_gQLvqXoKv=I*gWqM9C(Tvu0>=?hTbOp9!6k6AF;>f6|S5%jGEE}TA9h)e`Yuiu8 d7)l?o1NFcJg%EAfM$P~L002ovPDHLkV1g^Dnv?(l delta 550 zcmV+>0@?ki0<;8>8Gi-<0051N9Sr~g00DDSM?wIu&K&6g00HhvL_t(I5v`QFOB_)Y z#?QI;j_a;jjf#Z$YJ7mH(xecJU?W)A`9CN~KrBV85C}GDQ=|;GDFPNjtWty!L{u=? zh>8yo%^GE+J9o~_IZFoiamQVQXP7%LzTbT3F@uf+9x&7cvVV%GdjTaC;zf>@mq<=3 z!c<%*UT)@yJ|0BK6~d4Jx-*KV`ZQ(@VyUPupum=XhInNG#Z_k-X|hK{B}~9IfiWx} zLD5QY6Vm)p0NrWymdkrHPN5Vgwd>5>4HI1=@PA+e^rq~CEj|n2X`??)0mUI*D{KBn zjv{V=y5X9|X@3grkpcXC6oou4ML~ezCc2EtnsQTB4tWNg?4bkf;hG7IMfhgNI(FV5 zGs4|*GyMTIY0$B=_*mso9+>eB z?J{?+FLkYu+4_Uk`r_>LHF~flZm0oBf#vr8%vJ>#p~!KNvqGG3)|f1T_)ydeh8$vDceZ>oNbH^|*hJ*t?Yc*1`WB&W>VYVEzu) zq#7;;VjO)t*nbgf(!`OXJBr45rP>>AQr$6c7slJWvbpNW@KTwna6d?PP>hvXCcp=4 zF;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f<+$JJpcdz delta 1274 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 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 4cde12118dda48d71e01fcb589a74d069c5d7cb5..4cd7b0099ca80c806f8fe495613e8d6c69460d76 100644 GIT binary patch delta 266 zcmV+l0rmcY2$}+r8Gi!+003c4mpuRg09{Z_R7L;)|5U~JDYo_jSDX9(|7FYh`2GLd z^Zv2r{H^2sT*&w!Y^SB+`<>qVZqE6)=lqo0`vF#&*75!I`TIh@_d&k*HoEtQyV-iD z%Xz2D9EQRbeYh5Nr~y=#0ZD;^+vz0$004MNL_t(2&&|%+4u6C&2tZM$Wf&dzefR%A z(^3-?6X>hnCz2Ba@RH&`m!pgy?n@#@AuLYB&}Q)FGY`?vcft0!vht0Z@M&ZeNCWXh75gzRTXR8EE3oN&6 Q00000NkvXXt^-0~g5kS`djJ3c delta 1014 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 Zxpx7IC@PekH?;r&002ovPDHLkV1i)CYaajr delta 1916 zcmV-?2ZQ*)1%MBb8Gi-<0042w*=zs+2S-UnK~#9!?cG~!6jc}p@R>r@2Yv8@p?G^R zA|eDZ7{rR#1}sop6nca3fIb-?ED*6VwIFJZ!6Hy8w-yO8C@}~_05Gdr_$c4kiU&u$4j+xhLc-+x@XJ4X;S3;@U>VSc^? zQ-oQ8>A;-DT*34?AXhQJV-8~KF(sHg2eU|P;DUxQ_a|dEVEzDijZ2tj%oNrIBN{~& z>4Wk1F-%L`6DpV>Mpo}D4uPcWBCG2czh1jBlh{hu3!B5d1(snX=85|q1gQs{g(mmw zFhk?t-J03}-hU3m?2B8tH)4^yF(WhqGZlM3=9Ibs$%U1wWzcss*_c0=v_+^bfb`kB zFsI`d;ElwiU%frgRB%qBjn@!0U2zZehBn|{%uNIKBA7n=zE`nnwTP85{g;8AkYxA6 z8>#muXa!G>xH22D1I*SiD~7C?7Za+9y7j1SHiuSkK7ajvv#C@#-AyB-fbF?o#FaMR zJDRHO-oJwI(P;@j{Y`?E22zh%eMW-!PD-%va?p$yjUHg_5SW97D|{EkK-iW`L3pv- z4~1!@=&&EA9Pq)SV*$7tP|P@nrw{)Za}U8S%a)eF!V;W0J$@*|lp087uOFr#^24%U zq{wnjs(&o%xPaiU&xXU>0kGeNGuuGQ5tmf`yC)E6~>g8M!1m77Jdtm6rS zdzt5cn`N-@5mj#acH657tGvPJ!hP*GaHk;W`bL8(b&Ca)IkqSle-( z3~MW{(_wAHbpxy|xNd>XIIf#uGm7gr*o@)25q~x#xNe2D9M{dTmf~6gTbo6&mf^a+ zVlBhOVG}?}yia48X#p0jM&V#m55h z>JI^E`!oE3BU#}Dmwv9b)dtvg=lWr4mmi7``{5;>DN=7szV*Yi2Ys;Wj0F8;T@+3# zmw&G0iEAwC?DK@aT)GHRLhnz2WCvf3Ba;o=aY72{Asu5MEjGOY4O# zGgz@@J;q*0`kd2n8I3BeNuMmYZf{}pg=jTdTCrIIYuW~luKecn+E-pHY%ohyj1YuzG;)ZUq^`O?8S;53Ckoo?tVMn}05B zGT>6qU~R)?+l5}(M8IV|KHPZupz$m}u(sinl_#h8mK+a2-Z%PTS>T7;ufv262{vDp zBPZ@%`$0U4OAyGe*$BiPV-R;#+kY^w3*gq;1F)dJExc@8xT3fim)*FL!`r-_`hf}T zm`;Gax^BpsUI#+qYM8gWQ+@FWuz%ui+@N9%I0E}YCkWG)gIKl^a_2UIFntXIALItu z){pJS0}s~#9D>DGkhi=8gcoW+oYRQ78$!9MG7ea_7ufbMoah0Lz%Jbl!qW>uoV5yZ z*MeBOUIpGb5LmIV2XpaNDJ?A`1ltWTyk;i|kG}@u%nv~uIJ^uvgD3GS^%*ikdW6-!VFUU?JVZc2)4cMs@z;op$113mAD>fO*E%TZ|nArgH8#-g2!+%8FHwf;15T1O3 z%f6cwxNr>!C5<2yuQisJ*MabSJ(PUB7y5jX85K+)O)e+)5WQGt3uMU^^;zI|wjF^d zm+XKkwXKj}(_$#kENzAHZ*GT%JtreABF(BL3)s(I;&le^eK!%ZnImYePe^V6%BS#_+}3{E!Zyy%yt6N zc_MCu=*%YGbTRt+EScu(c1Sd(7eueRKax2l_JFm)Uc-z{HH8dq4-*++uSFzp1^;03 zwN8FSfgg=)5whnQIg+Indk!;R^%|;o+Ah*Vw#K~;+&BY@!gZ`W9baLF>6#BM(F}EX ze-`F=f_@`A7+Q&|QaZ??Txp_dB#lg!NH=t3$G8&06MFhwR=Iu*Im0s_b2B@|nW>X} zsy~m#EW)&6E&!*0%}8UAS)wjt+A(io#wGI@Z2S+Ms1Cxl%YVE80000+>eB z?J{?+FLkYu+4_Uk`r_>LHF~flZm0oBf#vr8%vJ>#p~!KNvqGG3)|f1T_)ydeh8$vDceZ>oNbH^|*hJ*t?Yc*1`WB&W>VYVEzu) zq#7;;VjO)t*nbgf(!`OXJBr45rP>>AQr$6c7slJWvbpNW@KTwna6d?PP>hvXCcp=4 zF;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f<+$JJpcdz delta 1274 zcmV@pi1MCNO0zH7s z{8#}P0)7Ba8DqYf&QgSne>X__O83t$NZM4&R0{XJq|x}oAU?tcfC@|eNz$04T}34& z8DJf78R&>*Zz`k$q{`#gfGHnx7nlH^G{y`jfER)1<_fNi<9aM%_zrm1C`yPkKma(+ ztQ;y*CR2bbBYz>zG*SVsfpkGU(q>uHZf3iogk_%#9E|5SWeHrmAo>P;ejX7mwq#*} zW25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+X$F_KMdb6sRz!~7K zkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&IDi_4_D!s#MVXp|-XhH;H z#&@_;oApJVd}}5O@b=X_gJboD^-fM@6|#V@sA%X)Rlkd}3MLH0dGXGG&-HX|aD~|M zC)W#H7=H?AbtdaV#dGpubj_O^J-SlWpVNv-5(;wR%mvE9`Qaqo>03b&##eNNf=m#B z9@^lsd8tJ;BvI86kNV zc~0CY(7V{s+h%cWG|y=gt|q`z$l<(@qU=i?9q#uz`G?PgDMK!VMGidHZt*N+1L0ZI zFkH=mFtywc6rJ}C_?)=m)18V!ZQ`*-j(D`gCFK|nt#{bk*%%zuQ7o7kvJgA^=(^7b zzkm5GZ;jxRn{Wup8IOUx8D4uh&(=Ox-7$a;U><*5L^!% zxRlw)vAbh;sdlR||&e}8_8%)c2Fwy=F& zH|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}Jb#viX>Oi;kBKp1x_fc0#UIbIeSJ^EkWFox zijdim{ojmn@#7EC*aY;fC0W*WN+DmQtE06pNK3SfZ^#@2K`6RgEuU_KwJTQ>E?Yar zc_9e#I$F8%>kuy-JI6ocSsYvQGbsxUCx04(w1z-pMRz9`kH5smmF@WHEG?dcYkv){ zV?kn3XB$_3zr*h1Uow)(<5)w5;3Wh1jHI)`ZlXp&!yEV{Y_~@;?CLwq;4eeaGOe6( zEsSSbwSGD0-`dUUl014$1_O8Gi!+006nq0-pc?0H{z*R7L;)|5U~JDYo_jSDXF*|5nEMy6F5^ z$M}8I`uzU?*Yf=uXr;5|{0m;6_Wb|A>ik^D_|)+I$?g3CSDK^3+eX0mD!2CP`2NN0 z{dLg!a?km&%iyTt`yiax0acdp`~T(l{$a`ZF1YpsRg(cvjDG_-U$Er-fz#Bw>2W$eUI#iU z)Wdgs8Y3U+A$Gd&{+j)d)BmGKx+43U_!tik_YlN)>$7G!hkE!s;%oku3;IwG3U^2k zw?z+HM)jB{@zFhK8P#KMSytSthr+4!c(5c%+^UBn_j%}l|2+O?a>_7qq7W zmx(qtA2nV^tZlLpy_#$U%ZNx5;$`0L&dZ!@e7rFXPGAOup%q`|03hpdtXsPP0000< KMNUMnLSTZ1N;Pr- delta 1891 zcmV-p2b}oI1m_Nr8Gi-<0052=@~r>>2QEoOK~#9!?VW3E6jc<*XLh$yKNt;)Mial3 z7z%<>zxaV5DhMs*(b6YIW1=KP6Jj(m21QYbiJ}su&;o5EN=$%gptMj6p|(7#AOTUJ zlt8fsX(iGq?ZQ50=XmbU+~w|cmz~|6$KBbz$-g^IcV>Hk`+q<8%-p?uMi3G-0B~!5 ze-yPCwFPw?HGmpMc~K)7BCq;C528+>zC*o^8h^XKC)IFgkv#xzm!ewK7j|kRa9dFo zC>MoDSR@P2#cWSU{i1oH5K2-Xb3jRz>|h7VOh0K` zhq^--L3H}A0r)nr z;Tr|-kPjB1s=ItpnS`oT%|U=a4oK-ZFIE^YBLH{u2#~@%%D^K)$`9*Tg(~9M-B+Zj z;~H?4LVsEt0eFtN4&>H(DZ@KpI6RhBKLL21CxC`J&m4Gc^9wwMZU#7SR1+KtuhSZM z+yLY}Vekzw6T_ApfEkuB_yU;e&a)L@rX~z70A_N+upOXN!qygmPDmKG0d%7CECcAI zgkd>ArzH$a0XjKsO$X@IgkcH5Y;m3`0G*yNOn(KK4GF_EfL4aB5i1j9o&Z{vFk~k> z&?@K2jQcJO%W!cddG(_DyfSoO55bUMHtbDF8DPkwF^~Ql#Eq4w15k{h%ML5Ar&pzi zl-D7v8kQXQ!&RRgKCW#5DZB$$6?mjWm50rRw*ukK>P-GkA|k69h{NARc>e}uLx+U4 z0DqE>7pa}9Fez+Vc-3jb`%i^uulglFoMzAVR|2%rf= zf#;74FXF^Ku_4+G&-4$KVy%YP>%2rxu2VG_cdm?XRjEhF&wPXJ># z_Q2+jGs=l~Fyx#MmGn+PZ0`@kBfGp|fO;Vov<$;z`(+sSZ7;Y=zXaF(8rb@CuQDV^ zq3i(2LfqO%AS!Ss>V%j7%>{6mtbYQrtQK5V4InPq0NZSaXv+f2U=&2}Z6OvkBfNHi z{LSaVJ!d5dC2K*ft_L^DRk;boQhOoVw!~Kt#0b2vd%!(&DF|~u1F@nG#LA5zR&7Fv z4GKgXooMSKb1g)6Obo-rgpuEP20T;W0Aa>55KC4gtQrKkAq-Hgs@FigV1GG8+rQ=z z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRet3L_uNyQ*c zE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=kyx=~RKa4{iT zm{_>_vSCm?$Ej=i6@=m%@PE9t1zZaoM}@2|h!#1K02~31S_I<0ZV=|K0}n!RRX6Ac zXmMf*5P-dLW}WPVsCKq)-x(0*txpZ2xrv3cxJ%l=7lpoNCyG< zK92ySAcmb-3m&}s@VwXv9(0#p<>B-5$bMxT;rk;OmENa6eM4D&LVo~01soUL39?R{ zyFLt3m|v?rCK7#KNu9E9Q4KV-pEUv^{rrClE&X&9I4-e7%pu_31#zGTOfC=ab%w20R*zBP+uT#l2{a~~~0wuG%6 zco*tVxK&e>%SJj*K!2tq*_h&ES5S9@TKb8WzpK;`&b9dNdxh4S)z%Q)o`aYWUh}9L z(`p!#WO5IxI|nf?yz{90R93Ed6@2qim*}Zjj$H&Esd`?JsFJUnDfiAgF_eYiWR3GC z>M9SHDylEWrA(%mfm~;u7OU9!Wz^!7Z%jZF zi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i0WYBP d*#0Ks^FNSabJA*5${_#%002ovPDHLkV1gB0Vle;! diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index a6d6b8609df07bf62e5100a53a01510388bd2b22..0ec303439225b78712f49115768196d8d76f6790 100644 GIT binary patch delta 850 zcmV-Y1Fih&6y64q8Gi!+000iU#^3+|0OwFlR7L;)|5U~J09TtSw)Xt~|5(QO`~Ck( z!T0|D|3<*~RmJ%E{r+;#`2ba!klFf7!uJMSo%Q?vP{jByxcAZE>;OrUCbaZYjJo^$ z{nGILmD~Da$@upC{`C6(Ey4dPw)Pyc^>5DkHoEo!QcuK-Jwl-l}t(fQKv z{dds$V#@dygS`PvhX6is7Z+@*x-d;$ zb=6f@U3Jw}_s+W3%*+b9H_vS)-R#9?zrXogeLVI2We2RFTTAL}&3C8PS~<5D&v@UI z+`s*$wqQ=yd$laNUY-|ovcS9~n_90tFUdl#qq0tEUXle|k{Op|DHpSrbxEeZ5~$>o%>OSe z^=41qvh3LlC2xXzu+-2eQoqs1^L>7ylB$bCP);(%(xYZL1 cY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f@rA97ytkO literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index a6d6b8609df07bf62e5100a53a01510388bd2b22..0ec303439225b78712f49115768196d8d76f6790 100644 GIT binary patch delta 850 zcmV-Y1Fih&6y64q8Gi!+000iU#^3+|0OwFlR7L;)|5U~J09TtSw)Xt~|5(QO`~Ck( z!T0|D|3<*~RmJ%E{r+;#`2ba!klFf7!uJMSo%Q?vP{jByxcAZE>;OrUCbaZYjJo^$ z{nGILmD~Da$@upC{`C6(Ey4dPw)Pyc^>5DkHoEo!QcuK-Jwl-l}t(fQKv z{dds$V#@dygS`PvhX6is7Z+@*x-d;$ zb=6f@U3Jw}_s+W3%*+b9H_vS)-R#9?zrXogeLVI2We2RFTTAL}&3C8PS~<5D&v@UI z+`s*$wqQ=yd$laNUY-|ovcS9~n_90tFUdl#qq0tEUXle|k{Op|DHpSrbxEeZ5~$>o%>OSe z^=41qvh3LlC2xXzu+-2eQoqs1^L>7ylB$bCP);(%(xYZL1 cY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f@rA97ytkO literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..e9f5fea27c705180eb716271f41b582e76dcbd90 100644 GIT binary patch delta 1668 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 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..84ac32ae7d989f82d5e46a60405adcc8279e8001 100644 GIT binary patch delta 749 zcmVg;Ps8|O$@u8^{Z_{KM!@$5TAfS6_e#O{MZfpz`2O`0$7~@NRr(1{THzH08y3x{{PYM{eL;T_A9^tcF_4Sxb`8l z_9V3RD6;a(-0A^Pjsi!1?)d#Ap4Tk3^CP0(07;VpJ7@tgQ}z4)*zx@&yZwC9`DV-b z0ZobH_5IB4{KxD3;p_6%|f=bdFhu+F!zMZ2UFj;GUKX7tI;hv3{q~!*pMj75WP_c}> z6)IWvg5_yyg<9Op()eD1hWC19M@?_9_MHec{Z8n3FMs~w_u?Av_yNBmRxVYrpi(M% zFMP21g+hmocQp3ay*Su=qM6He)*HaaTg$E^sym`(t%s3A)x!M+vfjXUBEpK6X9%iU zU!u9jj3(-$dM~sJ%Liy#?|+!6IY#MTau#O6vVj`yh_7%Ni!?!VS+MPTO(_fG+1<#p zqu;A#i+_(N%CmVnYvb>#nA{>Q%3E`Ds7<~jZMywn@h2t>G-LrYy7?Dj{aZqhQd6tzX%(Trn+ z)HNF}%-F{rr=m*0{=a;s#YDL00000NkvXXu0mjfaGjYE delta 1884 zcmV-i2c!7<1>g>l8Gi-<0076AQ7Zrd2Pa8HK~#9!?VNjT6h$1z_m0EFf5bmb1dTDK zp;kdKV1h(V(8Sc1M<37!RE>znAk{x4#zX@eOeE1j3~!+nB5IL z<xS}u?#DBMB>w^b($1Z)`9G?eP95EKi& z$eOy@K%h;ryrR3la%;>|o*>CgB(s>dDcNOXg}CK9SPmD?Uu$P4(=PGA0ShFasNfcIHTL?9WjB9#(2xSLC z`0%$#9DW9F;B4mbU{BlaYx!SjF!QSeF~(msQRxwboh5B_O$BWOQja)GboJz$&!?mgB&3$ytsA zvns&b3Cl5Hx#%p%faR*Q906u&fbXy$maV`n?S>A)vJIH!F-vxCrY+rq5_JA(GcOgu7(Ky4X3ATR9z8*%k&<5qYeV&4Y`~}XYmK(j{)!g8d2UgHXIINM!Rvn zKtEq~Foe0s!U{kux~F6Y7Sp+2f|*Cc${S{@oh8D0=XhB8Ec-w9CflfL+te4ium2cU zoPTCj_m<3d#gjK=<*8R`HP^C$lOPM5d~UhKhRRmvv{LI za^|oavk1$QiEApSrP@~Jjbg`<*dW4TO@DPEEX$Tg$xh?Y>Qd}y@kaH~IT8!lLpS^J zR7(&wZSI6+>Eb)tX>9Z?GX#q$u z4I>7e#b7ojyJ1grOh!^}s8S#ubi^Jkd1?UK)3mp6rI^_zxRY zrx6_QmhoWoDR`fp4R7gu6@OBFGu7IDVR6~nJsB{^f5jHn<{WJ&&f^X?3f8TIk3#U& zu1*Q-e@;snJxNx8-PBnpI|uFTKN!+Lp;fPfZ+eqqU^Y1|#DJY~126?zOx-+d>%4*? z&o`TbrXSNXZW^!P0t2>@$6&aiBtUDh2wLXLD9&a(1J=k_FK|iGbAQ@x4Qmx}Ms+*; zze&q6bH(=wYuXHfz0H6<05!LkE4rl~v^!bj=^9d+vI5fN<;GP>*Pas=q2l9RxDkk` zPRk&EQI+t_0$Y%nKE)Ma)W?jaA@4Z{h zTk*7;;#lG?hvTN_On=Jaxp%bdE;mDq(q#dgdYF|-?wrMeI4h`$idZ6^VyXZVlaCd0 z;i)OYR3npf@9>00Gqn##Zb4HRurgaWFCzL9u6@J@sse>Z1XznxWvSy%Td32I3!#YN zXt9v0)RQtDDZRd?#WY?~KF7A0UcR{jt9 W+;fr}hV%pg0000&=UXv0SHh`R7L;)|5U~JDYo_jSDRDC`1<|-SjPDL z{{Q{{{{H{}09Kk-#rR9Y_viNgVafPO!S|ls`uzR=MZfp^{QU=8od8La1X`Tr_Wmff z_5e$ivgQ1@=KMy$_g9a+`TPAle6cOJ_Fc#L7qIpvwDkd1mw$fK`6IOUD75rX!}mad zv(fMTE4=(Nx%L54lL1hVF1YpqNrC`FddBPg#_Ietx%Lrkq5wX00X1L{S%Cm9QY*av z#_Rh5PKy9KYTWbvz3BX9%J>0Hi1+#X{rLA{m%$Kamk?i!03AC38#Yrxs)5QTeTVRiEmz~MKK1WAjCw(c-JK6eox;2O)?`?TG`AHia671e^vgmp!llK zp|=5sVHk#C7=~epA~VAf-~%aPC=%Qw01h8mnSZ|p?tc*y?iZ$PR7_ceEIapF3KB14K0Pog?7wtd+^xgUCa_GVmlD z<^nU>AU_Yn-JU?NFdu|wf^bTCNf-wSBYVZltDdvGBln-YrbeGvJ!|s{#`gjN@yAMb zM6cjFz0eFECCsc|_8hTa3*9-JQGehksdoVP^K4m?&wpA~+|b%{EP5D-+7h)6CE; z*{>BP=GRR3Ea}xyV*bqry{l^J=0#DaC4ej;1qs8_by?H6Tr@7hl>UKNZt)^B&yl;)&oqzLg zcfZxpE?3k%_iTOVywh%`XVN-E#COl+($9{v(pqSQcrz=)>G!!3HeNxbXGM@})1|9g zG4*@(OBaMvY0P0_TfMFPh fVHk#CZX3S=^^2mI>Ux-D00000NkvXXu0mjfzK(<8 literal 3294 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 cX)(b1KSk$MOV07*qoM6N<$f&{Qds= z{r_0T`1}6fwc-8!#-TGX}_?g)CZq4{k!uZ_g@DrQdoW0kI zu+W69&uN^)W`CK&06mMNcYMVF00dG=L_t(|+U?wHQxh>12H+Dm+1+fh+IF>G0SjJM zkQQre1x4|G*Z==(Ot&kCnUrL4I(rf(ucITwmuHf^hXiJTkdTm&kdTm&kdTm&kdP`e zsgWG0BcWCVkVZ&2dUwN`cgM8QJb`Z7Z~e<&Yj2(}>VI$fQI%^ugM`#6By?GeadWcu z0gy9!D`m!H>Bd!JW(@avE8`|5XX(0PN}!8K>`dkavs;rHL+wy96QGNT=S@#7%xtlm zIW!++@*2zm-Py#Zr`DzqsLm!b{iskFNULSqE9A>SqHem>o31A%XL>S_5?=;V_i_y+ z(xxXhnt#r-l1Y8_*h`r?8Tr|)(RAiO)4jQR`13X0mx07C&p@KBP_2s``KEhv^|*8c z$$_T(v6^1Ig=#R}sE{vjA?ErGDZGUsyoJuWdJMc7Nb1^KF)-u<7q zPy$=;)0>vuWuK2hQhswLf!9yg`88u&eBbR8uhod?Nw09AXH}-#qOLLxeT2%C;R)QQ$Za#qp~cM&YVmS4i-*Fpd!cC zBXc?(4wcg>sHmXGd^VdE<5QX{Kyz$;$sCPl(_*-P2Iw?p^C6J2ZC!+UppiK6&y3Kmbv&O!oYF34$0Z;QO!J zOY#!`qyGH<3Pd}Pt@q*A0V=3SVtWKRR8d8Z&@)3qLPA19LPA19LPEUCUoZo%k(yku QW&i*H07*qoM6N<$g47z!?*IS* literal 3612 zcmV+%4&(8OP)6$jw%VRuvdN2+38CZWny1cRtlsl+0_KtW)EU14Ei(F!UtWuj4IK+3{sK@>rh zs1Z;=(DD&U6+tlyL?UnHVN^&g6QhFi2#HS+*qz;(>63G(`|jRtW|nz$Pv7qTovP!^ zP_jES{mr@O-02w%!^a?^1ZP!_KmQiz0L~jZ=W@Qt`8wzOoclQsAS<5YdH;a(4bGLE zk8s}1If(PSIgVi!XE!5kA?~z*sobvNyohr;=Q_@h2@$6Flyej3J)D-6YfheRGl`HEcPk|~huT_2-U?PfL=4BPV)f1o!%rQ!NMt_MYw-5bUSwQ9Z&zC>u zOrl~UJglJNa%f50Ok}?WB{on`Ci`p^Y!xBA?m@rcJXLxtrE0FhRF3d*ir>yzO|BD$ z3V}HpFcCh6bTzY}Nt_(W%QYd3NG)jJ4<`F<1Od) zfQblTdC&h2lCz`>y?>|9o2CdvC8qZeIZt%jN;B7Hdn2l*k4M4MFEtq`q_#5?}c$b$pf_3y{Y!cRDafZBEj-*OD|gz#PBDeu3QoueOesLzB+O zxjf2wvf6Wwz>@AiOo2mO4=TkAV+g~%_n&R;)l#!cBxjuoD$aS-`IIJv7cdX%2{WT7 zOm%5rs(wqyPE^k5SIpUZ!&Lq4<~%{*>_Hu$2|~Xa;iX*tz8~G6O3uFOS?+)tWtdi| zV2b#;zRN!m@H&jd=!$7YY6_}|=!IU@=SjvGDFtL;aCtw06U;-v^0%k0FOyESt z1Wv$={b_H&8FiRV?MrzoHWd>%v6KTRU;-v^Miiz+@q`(BoT!+<37CKhoKb)|8!+RG z6BQFU^@fRW;s8!mOf2QViKQGk0TVER6EG1`#;Nm39Do^PoT!+<37AD!%oJe86(=et zZ~|sLzU>V-qYiU6V8$0GmU7_K8|Fd0B?+9Un1BhKAz#V~Fk^`mJtlCX#{^8^M8!me z8Yg;8-~>!e<-iG;h*0B1kBKm}hItVGY6WnjVpgnTTAC$rqQ^v)4KvOtpY|sIj@WYg zyw##ZZ5AC2IKNC;^hwg9BPk0wLStlmBr;E|$5GoAo$&Ui_;S9WY62n3)i49|T%C#i017z3J=$RF|KyZWnci*@lW4 z=AKhNN6+m`Q!V3Ye68|8y@%=am>YD0nG99M)NWc20%)gwO!96j7muR}Fr&54SxKP2 zP30S~lt=a*qDlbu3+Av57=9v&vr<6g0&`!8E2fq>I|EJGKs}t|{h7+KT@)LfIV-3K zK)r_fr2?}FFyn*MYoLC>oV-J~eavL2ho4a4^r{E-8m2hi>~hA?_vIG4a*KT;2eyl1 zh_hUvUJpNCFwBvRq5BI*srSle>c6%n`#VNsyC|MGa{(P&08p=C9+WUw9Hl<1o9T4M zdD=_C0F7#o8A_bRR?sFNmU0R6tW`ElnF8p53IdHo#S9(JoZCz}fHwJ6F<&?qrpVqE zte|m%89JQD+XwaPU#%#lVs-@-OL);|MdfINd6!XwP2h(eyafTUsoRkA%&@fe?9m@jw-v(yTTiV2(*fthQH9}SqmsRPVnwwbV$1E(_lkmo&S zF-truCU914_$jpqjr(>Ha4HkM4YMT>m~NosUu&UZ>zirfHo%N6PPs9^_o$WqPA0#5 z%tG>qFCL+b*0s?sZ;Sht0nE7Kl>OVXy=gjWxxK;OJ3yGd7-pZf7JYNcZo2*1SF`u6 zHJyRRxGw9mDlOiXqVMsNe#WX`fC`vrtjSQ%KmLcl(lC>ZOQzG^%iql2w-f_K@r?OE zwCICifM#L-HJyc7Gm>Ern?+Sk3&|Khmu4(~3qa$(m6Ub^U0E5RHq49za|XklN#?kP zl;EstdW?(_4D>kwjWy2f!LM)y?F94kyU3`W!6+AyId-89v}sXJpuic^NLL7GJItl~ zsiuB98AI-(#Mnm|=A-R6&2fwJ0JVSY#Q>&3$zFh|@;#%0qeF=j5Ajq@4i0tIIW z&}sk$&fGwoJpe&u-JeGLi^r?dO`m=y(QO{@h zQqAC7$rvz&5+mo3IqE?h=a~6m>%r5Quapvzq;{y~p zJpyXOBgD9VrW7@#p6l7O?o3feml(DtSL>D^R) zZUY%T2b0-vBAFN7VB;M88!~HuOXi4KcI6aRQ&h|XQ0A?m%j2=l1f0cGP}h(oVfJ`N zz#PpmFC*ieab)zJK<4?^k=g%OjPnkANzbAbmGZHoVRk*mTfm75s_cWVa`l*f$B@xu z5E*?&@seIo#*Y~1rBm!7sF9~~u6Wrj5oICUOuz}CS)jdNIznfzCA(stJ(7$c^e5wN z?lt>eYgbA!kvAR7zYSD&*r1$b|(@;9dcZ^67R0 zXAXJKa|5Sdmj!g578Nwt6d$sXuc&MWezA0Whd`94$h{{?1IwXP4)Tx4obDK%xoFZ_Z zjjHJ_P@R_e5blG@yEjnaJb`l;s%Lb2&=8$&Ct-fV`E^4CUs)=jTk!I}2d&n!f@)bm z@ z_4Dc86+3l2*p|~;o-Sb~oXb_RuLmoifDU^&Te$*FevycC0*nE3Xws8gsWp|Rj2>SM zns)qcYj?^2sd8?N!_w~4v+f-HCF|a$TNZDoNl$I1Uq87euoNgKb6&r26TNrfkUa@o zfdiFA@p{K&mH3b8i!lcoz)V{n8Q@g(vR4ns4r6w;K z>1~ecQR0-<^J|Ndg5fvVUM9g;lbu-){#ghGw(fg>L zh)T5Ljb%lWE;V9L!;Cqk>AV1(rULYF07ZBJbGb9qbSoLAd;in9{)95YqX$J43-dY7YU*k~vrM25 zxh5_IqO0LYZW%oxQ5HOzmk4x{atE*vipUk}sh88$b2tn?!ujEHn`tQLe&vo}nMb&{ zio`xzZ&GG6&ZyN3jnaQy#iVqXE9VT(3tWY$n-)uWDQ|tc{`?fq2F`oQ{;d3aWPg4Hp-(iE{ry>MIPWL> iW8 - CADisableMinimumFrameDurationOnPhone - CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - Face Camera + Example CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -15,7 +13,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - face_camera_example + example CFBundlePackageType APPL CFBundleShortVersionString @@ -26,12 +24,6 @@ $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS - NSCameraUsageDescription - Camera permission is required for image upload. - NSMicrophoneUsageDescription - This app needs to be able to access your microphone - UIApplicationSupportsIndirectInputEvents - UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -49,7 +41,9 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIViewControllerBasedStatusBarAppearance - + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + diff --git a/example/ios/RunnerTests/RunnerTests.swift b/example/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..86a7c3b --- /dev/null +++ b/example/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/example/lib/main.dart b/example/lib/main.dart index 4cf5eb3..bfa32c0 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,8 +1,7 @@ import 'dart:io'; -import 'package:flutter/material.dart'; - import 'package:face_camera/face_camera.dart'; +import 'package:flutter/material.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -27,7 +26,7 @@ class _MyAppState extends State { @override void initState() { controller = FaceCameraController( - autoCapture: true, + autoCapture: false, defaultCameraLens: CameraLens.front, onCapture: (File? image) { setState(() => _capturedImage = image); @@ -43,10 +42,9 @@ class _MyAppState extends State { Widget build(BuildContext context) { return MaterialApp( home: Scaffold( - appBar: AppBar( - title: const Text('FaceCamera example app'), - ), - body: Builder(builder: (context) { + appBar: AppBar(title: const Text('FaceCamera example app')), + body: Builder( + builder: (context) { if (_capturedImage != null) { return Center( child: Stack( @@ -58,42 +56,54 @@ class _MyAppState extends State { fit: BoxFit.fitWidth, ), ElevatedButton( - onPressed: () async { - await controller.startImageStream(); - setState(() => _capturedImage = null); - }, - child: const Text( - 'Capture Again', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, fontWeight: FontWeight.w700), - )) + onPressed: () async { + await controller.startImageStream(); + setState(() => _capturedImage = null); + }, + child: const Text( + 'Capture Again', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w700, + ), + ), + ), ], ), ); } return SmartFaceCamera( - controller: controller, - messageBuilder: (context, face) { - if (face == null) { - return _message('Place your face in the camera'); - } - if (!face.wellPositioned) { - return _message('Center your face in the square'); - } - return const SizedBox.shrink(); - }); - })), + controller: controller, + indicatorShape: IndicatorShape.square, + messageBuilder: (context, face) { + if (face == null) { + return _message('Place your face in the camera'); + } + if (!face.wellPositioned) { + return _message('Center your face in the square'); + } + return const SizedBox.shrink(); + }, + ); + }, + ), + ), ); } Widget _message(String msg) => Padding( - padding: const EdgeInsets.symmetric(horizontal: 55, vertical: 15), - child: Text(msg, - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 14, height: 1.5, fontWeight: FontWeight.w400)), - ); + padding: const EdgeInsets.symmetric(horizontal: 55, vertical: 15), + child: Text( + msg, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 14, + height: 1.5, + fontWeight: FontWeight.w400, + ), + ), + ); @override void dispose() { diff --git a/example/pubspec.lock b/example/pubspec.lock index 2df3d66..7c8ba22 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.13.0" boolean_selector: dependency: transitive description: @@ -53,10 +53,10 @@ packages: dependency: transitive description: name: camera_web - sha256: "9e9aba2fbab77ce2472924196ff8ac4dd8f9126c4f9a3096171cd1d870d6b26c" + sha256: "595f28c89d1fb62d77c73c633193755b781c6d2e0ebcd8dc25b763b514e6ba8f" url: "https://pub.dev" source: hosted - version: "0.3.3" + version: "0.3.5" characters: dependency: transitive description: @@ -85,18 +85,18 @@ packages: dependency: transitive description: name: cross_file - sha256: "7632a2bcddc8cef4afde3c6f80e69b29a7060e176f01119c229fe4eb3a2a3d4f" + sha256: "942a4791cd385a68ccb3b32c71c427aba508a1bb949b86dff2adbe4049f16239" url: "https://pub.dev" source: hosted - version: "0.3.3+1" + version: "0.3.5" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - sha256: "1989d917fbe8e6b39806207df5a3fdd3d816cbd090fac2ce26fb45e9a71476e5" + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.8" face_camera: dependency: "direct main" description: @@ -121,10 +121,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493 + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "5.0.0" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -159,14 +159,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.13.1" - js: - dependency: transitive - description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 - url: "https://pub.dev" - source: hosted - version: "0.6.7" leak_tracker: dependency: transitive description: @@ -195,10 +187,10 @@ packages: dependency: transitive description: name: lints - sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c + sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "5.1.1" matcher: dependency: transitive description: @@ -272,10 +264,10 @@ packages: dependency: transitive description: name: stream_transform - sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: @@ -312,10 +304,18 @@ packages: dependency: transitive description: name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" + url: "https://pub.dev" + source: hosted + version: "15.0.2" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" url: "https://pub.dev" source: hosted - version: "14.3.1" + version: "1.1.1" sdks: - dart: ">=3.9.0 <4.0.0" + dart: ">=3.9.2 <4.0.0" flutter: ">=3.35.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 6630bc1..56f68cb 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,12 +1,25 @@ -name: face_camera_example -description: Demonstrates how to use the face_camera plugin. - +name: example +description: "A new Flutter project." # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + environment: - sdk: ">=2.16.2 <3.0.0" + sdk: ^3.9.2 # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -18,6 +31,7 @@ dependencies: flutter: sdk: flutter + face_camera: # When depending on this package from a real application you should use: # face_camera: ^x.y.z @@ -28,7 +42,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.2 + cupertino_icons: ^1.0.8 dev_dependencies: flutter_test: @@ -39,12 +53,12 @@ dev_dependencies: # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. - flutter_lints: ^1.0.0 + flutter_lints: ^5.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec -# The following section is specific to Flutter. +# The following section is specific to Flutter packages. flutter: # The following line ensures that the Material Icons font is @@ -56,14 +70,12 @@ flutter: # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg - assets: - - assets/images/ # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. + # https://flutter.dev/to/resolution-aware-images # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages + # https://flutter.dev/to/asset-from-package # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a @@ -83,4 +95,4 @@ flutter: # weight: 700 # # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages + # see https://flutter.dev/to/font-from-package diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart index e1aac96..092d222 100644 --- a/example/test/widget_test.dart +++ b/example/test/widget_test.dart @@ -1,27 +1,30 @@ // This is a basic Flutter widget test. // // To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll +// utility in the flutter_test package. For example, you can send tap and scroll // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:face_camera_example/main.dart'; +import 'package:example/main.dart'; void main() { - testWidgets('Verify Platform version', (WidgetTester tester) async { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { // Build our app and trigger a frame. await tester.pumpWidget(const MyApp()); - // Verify that platform version is retrieved. - expect( - find.byWidgetPredicate( - (Widget widget) => - widget is Text && widget.data!.startsWith('Running on:'), - ), - findsOneWidget, - ); + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); }); } diff --git a/lib/src/controllers/face_camera_controller.dart b/lib/src/controllers/face_camera_controller.dart index 36a86b3..851b4c6 100644 --- a/lib/src/controllers/face_camera_controller.dart +++ b/lib/src/controllers/face_camera_controller.dart @@ -76,35 +76,44 @@ class FaceCameraController extends ValueNotifier { } value = value.copyWith( - availableCameraLens: availableCameraLens, - currentCameraLens: currentCameraLens); + availableCameraLens: availableCameraLens, + currentCameraLens: currentCameraLens, + ); } Future _initCamera() async { final cameras = FaceCamera.cameras - .where((c) => - c.lensDirection == - EnumHandler.cameraLensToCameraLensDirection( - value.availableCameraLens[value.currentCameraLens])) + .where( + (c) => + c.lensDirection == + EnumHandler.cameraLensToCameraLensDirection( + value.availableCameraLens[value.currentCameraLens], + ), + ) .toList(); if (cameras.isNotEmpty) { - final cameraController = CameraController(cameras.first, - EnumHandler.imageResolutionToResolutionPreset(imageResolution), - enableAudio: enableAudio, - imageFormatGroup: Platform.isAndroid - ? ImageFormatGroup.nv21 - : ImageFormatGroup.bgra8888); + final cameraController = CameraController( + cameras.first, + EnumHandler.imageResolutionToResolutionPreset(imageResolution), + enableAudio: enableAudio, + imageFormatGroup: Platform.isAndroid + ? ImageFormatGroup.yuv420 + : ImageFormatGroup.bgra8888, + ); await cameraController.initialize().whenComplete(() { value = value.copyWith( - isInitialized: true, cameraController: cameraController); + isInitialized: true, + cameraController: cameraController, + ); }); await changeFlashMode(value.availableFlashMode.indexOf(defaultFlashMode)); await cameraController.lockCaptureOrientation( - EnumHandler.cameraOrientationToDeviceOrientation(orientation)); + EnumHandler.cameraOrientationToDeviceOrientation(orientation), + ); } startImageStream(); @@ -114,11 +123,14 @@ class FaceCameraController extends ValueNotifier { final newIndex = index ?? (value.currentFlashMode + 1) % value.availableFlashMode.length; await value.cameraController! - .setFlashMode(EnumHandler.cameraFlashModeToFlashMode( - value.availableFlashMode[newIndex])) + .setFlashMode( + EnumHandler.cameraFlashModeToFlashMode( + value.availableFlashMode[newIndex], + ), + ) .then((_) { - value = value.copyWith(currentFlashMode: newIndex); - }); + value = value.copyWith(currentFlashMode: newIndex); + }); } /// The supplied [zoom] value should be between 1.0 and the maximum supported @@ -132,8 +144,9 @@ class FaceCameraController extends ValueNotifier { Future changeCameraLens() async { value = value.copyWith( - currentCameraLens: - (value.currentCameraLens + 1) % value.availableCameraLens.length); + currentCameraLens: + (value.currentCameraLens + 1) % value.availableCameraLens.length, + ); _initCamera(); } @@ -183,16 +196,25 @@ class FaceCameraController extends ValueNotifier { } void _processImage(CameraImage cameraImage) async { + print('📷 _processImage called'); final CameraController? cameraController = value.cameraController; if (!value.alreadyCheckingImage) { + print('✅ Starting face scan...'); value = value.copyWith(alreadyCheckingImage: true); try { await FaceIdentifier.scanImage( - cameraImage: cameraImage, - controller: cameraController, - performanceMode: performanceMode) - .then((result) async { + cameraImage: cameraImage, + controller: cameraController, + performanceMode: performanceMode, + ).then((result) async { + print('📸 Scan result: $result'); + print('📸 Result is null: ${result == null}'); + if (result != null) { + print('📸 Result face: ${result.face}'); + print('📸 Result wellPositioned: ${result.wellPositioned}'); + } value = value.copyWith(detectedFace: result); + print('📦 State detectedFace after update: ${value.detectedFace}'); if (result != null) { try { @@ -210,11 +232,47 @@ class FaceCameraController extends ValueNotifier { }); value = value.copyWith(alreadyCheckingImage: false); } catch (ex, stack) { + print('🖼️ ERROR SCANIMAGE: ${ex} ${stack}'); value = value.copyWith(alreadyCheckingImage: false); logError('$ex, $stack'); } + } else { + print('⏭️ Skipping - already checking image'); } } + // void _processImage(CameraImage cameraImage) async { + // final CameraController? cameraController = value.cameraController; + // if (!value.alreadyCheckingImage) { + // value = value.copyWith(alreadyCheckingImage: true); + // try { + // await FaceIdentifier.scanImage( + // cameraImage: cameraImage, + // controller: cameraController, + // performanceMode: performanceMode) + // .then((result) async { + // value = value.copyWith(detectedFace: result); + // + // if (result != null) { + // try { + // if (result.face != null) { + // onFaceDetected?.call(result.face); + // } + // if (autoCapture && + // (result.wellPositioned || ignoreFacePositioning)) { + // captureImage(); + // } + // } catch (e) { + // logError(e.toString()); + // } + // } + // }); + // value = value.copyWith(alreadyCheckingImage: false); + // } catch (ex, stack) { + // value = value.copyWith(alreadyCheckingImage: false); + // logError('$ex, $stack'); + // } + // } + // } @Deprecated('Use [captureImage]') void onTakePictureButtonPressed() async { @@ -238,7 +296,7 @@ class FaceCameraController extends ValueNotifier { } } -/* void onViewFinderTap(TapDownDetails details, BoxConstraints constraints) { + /* void onViewFinderTap(TapDownDetails details, BoxConstraints constraints) { if (value.cameraController == null) { return; } diff --git a/lib/src/extension/nv21_converter.dart b/lib/src/extension/nv21_converter.dart index ce985d0..6fcbad5 100644 --- a/lib/src/extension/nv21_converter.dart +++ b/lib/src/extension/nv21_converter.dart @@ -7,6 +7,15 @@ extension Nv21Converter on CameraImage { final width = this.width; final height = this.height; + // Safety check: ensure we have enough planes + if (planes.length < 3) { + print( + '⚠️ Camera image has ${planes.length} plane(s), expected 3 for NV21', + ); + // Fallback: return the Y plane only + return planes[0].bytes; + } + final yPlane = planes[0]; final uPlane = planes[1]; final vPlane = planes[2]; @@ -44,7 +53,7 @@ extension Nv21Converter on CameraImage { final bufferIndex = uvOffset + (x * uvPixelStride); //V channel nv21[idUV++] = vBuffer[bufferIndex]; - //V channel + //U channel nv21[idUV++] = uBuffer[bufferIndex]; } } diff --git a/lib/src/handlers/face_identifier.dart b/lib/src/handlers/face_identifier.dart index d380636..43b8132 100644 --- a/lib/src/handlers/face_identifier.dart +++ b/lib/src/handlers/face_identifier.dart @@ -1,17 +1,19 @@ import 'dart:io'; + import 'package:camera/camera.dart'; +import 'package:face_camera/src/extension/nv21_converter.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart'; -import 'package:face_camera/src/extension/nv21_converter.dart'; import '../models/detected_image.dart'; class FaceIdentifier { - static Future scanImage( - {required CameraImage cameraImage, - required CameraController? controller, - required FaceDetectorMode performanceMode}) async { + static Future scanImage({ + required CameraImage cameraImage, + required CameraController? controller, + required FaceDetectorMode performanceMode, + }) async { final orientations = { DeviceOrientation.portraitUp: 0, DeviceOrientation.landscapeLeft: 90, @@ -19,20 +21,35 @@ class FaceIdentifier { DeviceOrientation.landscapeRight: 270, }; + final inputImage = _inputImageFromCameraImage( + cameraImage, + controller, + orientations, + ); + + print('🖼️ InputImage created: ${inputImage != null}'); + DetectedFace? result; + final face = await _detectFace( - performanceMode: performanceMode, - visionImage: - _inputImageFromCameraImage(cameraImage, controller, orientations)); + performanceMode: performanceMode, + visionImage: inputImage, + ); + print('👤 Face detection result: ${face != null}'); if (face != null) { + print('👤 Face object: ${face.face}'); + print('👤 Well positioned: ${face.wellPositioned}'); result = face; } return result; } - static InputImage? _inputImageFromCameraImage(CameraImage image, - CameraController? controller, Map orientations) { + static InputImage? _inputImageFromCameraImage( + CameraImage image, + CameraController? controller, + Map orientations, + ) { // get image rotation // it is used in android to convert the InputImage from Dart to Java // `rotation` is not used in iOS to convert the InputImage from Dart to Obj-C @@ -64,16 +81,18 @@ class FaceIdentifier { // only supported formats: // * bgra8888 for iOS if (format == null || - (Platform.isIOS && format != InputImageFormat.bgra8888)) return null; + (Platform.isIOS && format != InputImageFormat.bgra8888)) + return null; if (image.planes.isEmpty) return null; final bytes = Platform.isAndroid ? image.getNv21Uint8List() : Uint8List.fromList( image.planes.fold( - [], - (List previousValue, element) => - previousValue..addAll(element.bytes)), + [], + (List previousValue, element) => + previousValue..addAll(element.bytes), + ), ); // compose InputImage using bytes @@ -88,14 +107,16 @@ class FaceIdentifier { ); } - static Future _detectFace( - {required InputImage? visionImage, - required FaceDetectorMode performanceMode}) async { + static Future _detectFace({ + required InputImage? visionImage, + required FaceDetectorMode performanceMode, + }) async { if (visionImage == null) return null; final options = FaceDetectorOptions( - enableLandmarks: true, - enableTracking: true, - performanceMode: performanceMode); + enableLandmarks: true, + enableTracking: true, + performanceMode: performanceMode, + ); final faceDetector = FaceDetector(options: options); try { final List faces = await faceDetector.processImage(visionImage); @@ -163,9 +184,6 @@ class FaceIdentifier { } } - return DetectedFace( - wellPositioned: wellPositioned, - face: detectedFace, - ); + return DetectedFace(wellPositioned: wellPositioned, face: detectedFace); } } diff --git a/lib/src/smart_face_camera.dart b/lib/src/smart_face_camera.dart index 26d0c47..8499ef1 100644 --- a/lib/src/smart_face_camera.dart +++ b/lib/src/smart_face_camera.dart @@ -122,6 +122,8 @@ class _SmartFaceCameraState extends State return ValueListenableBuilder( valueListenable: widget.controller, builder: (BuildContext context, FaceCameraState value, Widget? child) { + print('🏗️ Building - detectedFace: ${value.detectedFace != null}'); + print('🏗️ Face object: ${value.detectedFace?.face}'); final CameraController? cameraController = value.cameraController; return Stack( alignment: Alignment.center, @@ -146,11 +148,7 @@ class _SmartFaceCameraState extends State if (value.detectedFace != null && widget.indicatorShape != IndicatorShape.none) ...[ - SizedBox( - width: - cameraController.value.previewSize!.width, - height: - cameraController.value.previewSize!.height, + Positioned.fill( child: widget.indicatorBuilder?.call( context, diff --git a/lib/src/utils/logger.dart b/lib/src/utils/logger.dart index b5931a0..47c8eaf 100644 --- a/lib/src/utils/logger.dart +++ b/lib/src/utils/logger.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; void logError(String message, [String? code]) { if (code != null) { - debugPrint('Error: $code\nError Message: $message'); + debugPrint('Face Camera Error: $code\nError Message: $message'); } else { - debugPrint('Error: $code'); + debugPrint('Face Camera Error: $code'); } } From 0d7659a27907986728b3ef28ec6396c64bb974c1 Mon Sep 17 00:00:00 2001 From: Jiten Basnet Date: Fri, 31 Oct 2025 13:52:16 +0545 Subject: [PATCH 4/7] :up: update and remove un-wanted code --- lib/src/handlers/face_identifier.dart | 18 +++++------------- lib/src/smart_face_camera.dart | 8 +++++--- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/lib/src/handlers/face_identifier.dart b/lib/src/handlers/face_identifier.dart index 43b8132..f8eecc4 100644 --- a/lib/src/handlers/face_identifier.dart +++ b/lib/src/handlers/face_identifier.dart @@ -21,24 +21,16 @@ class FaceIdentifier { DeviceOrientation.landscapeRight: 270, }; - final inputImage = _inputImageFromCameraImage( - cameraImage, - controller, - orientations, - ); - - print('🖼️ InputImage created: ${inputImage != null}'); - DetectedFace? result; - final face = await _detectFace( performanceMode: performanceMode, - visionImage: inputImage, + visionImage: _inputImageFromCameraImage( + cameraImage, + controller, + orientations, + ), ); - print('👤 Face detection result: ${face != null}'); if (face != null) { - print('👤 Face object: ${face.face}'); - print('👤 Well positioned: ${face.wellPositioned}'); result = face; } diff --git a/lib/src/smart_face_camera.dart b/lib/src/smart_face_camera.dart index 8499ef1..26d0c47 100644 --- a/lib/src/smart_face_camera.dart +++ b/lib/src/smart_face_camera.dart @@ -122,8 +122,6 @@ class _SmartFaceCameraState extends State return ValueListenableBuilder( valueListenable: widget.controller, builder: (BuildContext context, FaceCameraState value, Widget? child) { - print('🏗️ Building - detectedFace: ${value.detectedFace != null}'); - print('🏗️ Face object: ${value.detectedFace?.face}'); final CameraController? cameraController = value.cameraController; return Stack( alignment: Alignment.center, @@ -148,7 +146,11 @@ class _SmartFaceCameraState extends State if (value.detectedFace != null && widget.indicatorShape != IndicatorShape.none) ...[ - Positioned.fill( + SizedBox( + width: + cameraController.value.previewSize!.width, + height: + cameraController.value.previewSize!.height, child: widget.indicatorBuilder?.call( context, From 80068fbe6143d5e0ecd454a237815dd22ad64ea4 Mon Sep 17 00:00:00 2001 From: Jiten Basnet Date: Fri, 31 Oct 2025 13:53:09 +0545 Subject: [PATCH 5/7] :up: update initial loading widget to initialLoadingWidget --- lib/src/smart_face_camera.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/src/smart_face_camera.dart b/lib/src/smart_face_camera.dart index 26d0c47..1592a74 100644 --- a/lib/src/smart_face_camera.dart +++ b/lib/src/smart_face_camera.dart @@ -10,7 +10,7 @@ import 'res/builders.dart'; class SmartFaceCamera extends StatefulWidget { ///Initial widget to show when camera is initializing - final Widget? initialWidget; + final Widget? initialLoadingWidget; /// Set false to hide all controls. final bool showControls; @@ -77,7 +77,7 @@ class SmartFaceCamera extends StatefulWidget { this.indicatorAssetImage, this.indicatorBuilder, this.autoDisableCaptureControl = false, - this.initialWidget, + this.initialLoadingWidget, Key? key, }) : assert( indicatorShape != IndicatorShape.image || indicatorAssetImage != null, @@ -194,8 +194,8 @@ class _SmartFaceCameraState extends State ), ), ] else ...[ - widget.initialWidget != null - ? widget.initialWidget! + widget.initialLoadingWidget != null + ? widget.initialLoadingWidget! : Column( mainAxisAlignment: MainAxisAlignment.center, children: [ From d0f16f13c4ea51d6b687b8e2d9398d2826b6ec02 Mon Sep 17 00:00:00 2001 From: Jiten Basnet Date: Fri, 31 Oct 2025 14:14:50 +0545 Subject: [PATCH 6/7] :up: remove print statements --- .../controllers/face_camera_controller.dart | 45 ------------------- 1 file changed, 45 deletions(-) diff --git a/lib/src/controllers/face_camera_controller.dart b/lib/src/controllers/face_camera_controller.dart index 851b4c6..5b21522 100644 --- a/lib/src/controllers/face_camera_controller.dart +++ b/lib/src/controllers/face_camera_controller.dart @@ -196,10 +196,8 @@ class FaceCameraController extends ValueNotifier { } void _processImage(CameraImage cameraImage) async { - print('📷 _processImage called'); final CameraController? cameraController = value.cameraController; if (!value.alreadyCheckingImage) { - print('✅ Starting face scan...'); value = value.copyWith(alreadyCheckingImage: true); try { await FaceIdentifier.scanImage( @@ -207,14 +205,7 @@ class FaceCameraController extends ValueNotifier { controller: cameraController, performanceMode: performanceMode, ).then((result) async { - print('📸 Scan result: $result'); - print('📸 Result is null: ${result == null}'); - if (result != null) { - print('📸 Result face: ${result.face}'); - print('📸 Result wellPositioned: ${result.wellPositioned}'); - } value = value.copyWith(detectedFace: result); - print('📦 State detectedFace after update: ${value.detectedFace}'); if (result != null) { try { @@ -232,47 +223,11 @@ class FaceCameraController extends ValueNotifier { }); value = value.copyWith(alreadyCheckingImage: false); } catch (ex, stack) { - print('🖼️ ERROR SCANIMAGE: ${ex} ${stack}'); value = value.copyWith(alreadyCheckingImage: false); logError('$ex, $stack'); } - } else { - print('⏭️ Skipping - already checking image'); } } - // void _processImage(CameraImage cameraImage) async { - // final CameraController? cameraController = value.cameraController; - // if (!value.alreadyCheckingImage) { - // value = value.copyWith(alreadyCheckingImage: true); - // try { - // await FaceIdentifier.scanImage( - // cameraImage: cameraImage, - // controller: cameraController, - // performanceMode: performanceMode) - // .then((result) async { - // value = value.copyWith(detectedFace: result); - // - // if (result != null) { - // try { - // if (result.face != null) { - // onFaceDetected?.call(result.face); - // } - // if (autoCapture && - // (result.wellPositioned || ignoreFacePositioning)) { - // captureImage(); - // } - // } catch (e) { - // logError(e.toString()); - // } - // } - // }); - // value = value.copyWith(alreadyCheckingImage: false); - // } catch (ex, stack) { - // value = value.copyWith(alreadyCheckingImage: false); - // logError('$ex, $stack'); - // } - // } - // } @Deprecated('Use [captureImage]') void onTakePictureButtonPressed() async { From a1b7d0ea815cb9d797a3de4cfcf88e806a52cccf Mon Sep 17 00:00:00 2001 From: Jiten Basnet Date: Wed, 26 Nov 2025 14:50:06 +0545 Subject: [PATCH 7/7] :up: update to add customControlsBuilder --- example/pubspec.lock | 8 ++++---- lib/src/res/builders.dart | 24 ++++++++++++++++-------- lib/src/smart_face_camera.dart | 10 +++++++++- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index 7c8ba22..2e27dd6 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -211,10 +211,10 @@ packages: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" path: dependency: transitive description: @@ -288,10 +288,10 @@ packages: dependency: transitive description: name: test_api - sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" + sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 url: "https://pub.dev" source: hosted - version: "0.7.6" + version: "0.7.7" vector_math: dependency: transitive description: diff --git a/lib/src/res/builders.dart b/lib/src/res/builders.dart index 1ee3b9d..3af4e7d 100644 --- a/lib/src/res/builders.dart +++ b/lib/src/res/builders.dart @@ -3,17 +3,25 @@ import 'package:flutter/material.dart'; import '../../face_camera.dart'; /// Returns widget for flash modes -typedef FlashControlBuilder = Widget Function( - BuildContext context, CameraFlashMode mode); +typedef FlashControlBuilder = + Widget Function(BuildContext context, CameraFlashMode mode); /// Returns message based on face position -typedef MessageBuilder = Widget Function( - BuildContext context, DetectedFace? detectedFace); +typedef MessageBuilder = + Widget Function(BuildContext context, DetectedFace? detectedFace); /// Returns widget for detector -typedef IndicatorBuilder = Widget Function( - BuildContext context, DetectedFace? detectedFace, Size? imageSize); +typedef IndicatorBuilder = + Widget Function( + BuildContext context, + DetectedFace? detectedFace, + Size? imageSize, + ); /// Returns widget for capture control -typedef CaptureControlBuilder = Widget Function( - BuildContext context, DetectedFace? detectedFace); +typedef CaptureControlBuilder = + Widget Function(BuildContext context, DetectedFace? detectedFace); + +/// Returns widget for custom controls +typedef CustomControlBuilder = + Widget Function(BuildContext context, DetectedFace? detectedFace); diff --git a/lib/src/smart_face_camera.dart b/lib/src/smart_face_camera.dart index 1592a74..1aecf60 100644 --- a/lib/src/smart_face_camera.dart +++ b/lib/src/smart_face_camera.dart @@ -33,6 +33,9 @@ class SmartFaceCamera extends StatefulWidget { /// Use this to build custom widgets for capture control. final CaptureControlBuilder? captureControlBuilder; + /// Use this to build custom controls. + final CustomControlBuilder? customControlsBuilder; + /// Use this to render a custom widget for camera lens control. final Widget? lensControlIcon; @@ -79,6 +82,7 @@ class SmartFaceCamera extends StatefulWidget { this.autoDisableCaptureControl = false, this.initialLoadingWidget, Key? key, + this.customControlsBuilder, }) : assert( indicatorShape != IndicatorShape.image || indicatorAssetImage != null, 'IndicatorAssetImage must be provided when IndicatorShape is set to image.', @@ -211,7 +215,8 @@ class _SmartFaceCameraState extends State ), ], - if (widget.showControls) ...[ + if (widget.showControls && + widget.customControlsBuilder == null) ...[ Align( alignment: Alignment.bottomCenter, child: Padding( @@ -234,6 +239,9 @@ class _SmartFaceCameraState extends State ), ), ), + ] else ...[ + if (widget.showControls && widget.customControlsBuilder != null) + widget.customControlsBuilder!.call(context, value.detectedFace), ], ], );