diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..24476c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,44 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..714f02b --- /dev/null +++ b/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf + channel: stable + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf + base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf + - platform: android + create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf + base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf + + # 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/README.md b/README.md new file mode 100644 index 0000000..24c45b4 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# fitster_poc + +A new Flutter project. + +## Getting Started + +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://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +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/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..39d6341 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +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. + # + # 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 + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + avoid_print: false # Uncomment to disable the `avoid_print` rule + prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..6f56801 --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..f9675a1 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,81 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 33 + ndkVersion flutter.ndkVersion + + 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.dalbitresb.fitster_poc" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. + minSdkVersion 21 + targetSdkVersion 33 + 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 + } + } + + aaptOptions { + noCompress "tflite" // Your model's file extension: "tflite", "lite", etc. + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + + // Object detection feature with bundled default classifier + implementation "com.google.mlkit:object-detection:17.0.0" + + // Object detection feature with custom classifier support + implementation 'com.google.mlkit:object-detection-custom:17.0.0' +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..6d22752 --- /dev/null +++ b/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..c085412 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/android/app/src/main/jniLibs/arm64-v8a/libtensorflowlite_c.so b/android/app/src/main/jniLibs/arm64-v8a/libtensorflowlite_c.so new file mode 100644 index 0000000..e2b6397 Binary files /dev/null and b/android/app/src/main/jniLibs/arm64-v8a/libtensorflowlite_c.so differ diff --git a/android/app/src/main/jniLibs/arm64-v8a/libtensorflowlite_gpu_delegate.so b/android/app/src/main/jniLibs/arm64-v8a/libtensorflowlite_gpu_delegate.so new file mode 100644 index 0000000..e38b8b0 Binary files /dev/null and b/android/app/src/main/jniLibs/arm64-v8a/libtensorflowlite_gpu_delegate.so differ diff --git a/android/app/src/main/jniLibs/armeabi-v7a/libtensorflowlite_c.so b/android/app/src/main/jniLibs/armeabi-v7a/libtensorflowlite_c.so new file mode 100644 index 0000000..4567280 Binary files /dev/null and b/android/app/src/main/jniLibs/armeabi-v7a/libtensorflowlite_c.so differ diff --git a/android/app/src/main/jniLibs/x86/libtensorflowlite_c.so b/android/app/src/main/jniLibs/x86/libtensorflowlite_c.so new file mode 100644 index 0000000..a38e7f9 Binary files /dev/null and b/android/app/src/main/jniLibs/x86/libtensorflowlite_c.so differ diff --git a/android/app/src/main/jniLibs/x86_64/libtensorflowlite_c.so b/android/app/src/main/jniLibs/x86_64/libtensorflowlite_c.so new file mode 100644 index 0000000..2cee5db Binary files /dev/null and b/android/app/src/main/jniLibs/x86_64/libtensorflowlite_c.so differ diff --git a/android/app/src/main/kotlin/com/dalbitresb/fitster_poc/MainActivity.kt b/android/app/src/main/kotlin/com/dalbitresb/fitster_poc/MainActivity.kt new file mode 100644 index 0000000..f969c52 --- /dev/null +++ b/android/app/src/main/kotlin/com/dalbitresb/fitster_poc/MainActivity.kt @@ -0,0 +1,6 @@ +package com.dalbitresb.fitster_poc + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..06952be --- /dev/null +++ b/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..cb1ef88 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..6d22752 --- /dev/null +++ b/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..58a8c74 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.7.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.2.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..94adc3a --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..3c472b9 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..44e62bc --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/assets/ssd_mobilenet.tflite b/assets/ssd_mobilenet.tflite new file mode 100644 index 0000000..8015ee5 Binary files /dev/null and b/assets/ssd_mobilenet.tflite differ diff --git a/assets/ssd_mobilenet.txt b/assets/ssd_mobilenet.txt new file mode 100644 index 0000000..5a70ff8 --- /dev/null +++ b/assets/ssd_mobilenet.txt @@ -0,0 +1,91 @@ +??? +person +bicycle +car +motorcycle +airplane +bus +train +truck +boat +traffic light +fire hydrant +??? +stop sign +parking meter +bench +bird +cat +dog +horse +sheep +cow +elephant +bear +zebra +giraffe +??? +backpack +umbrella +??? +??? +handbag +tie +suitcase +frisbee +skis +snowboard +sports ball +kite +baseball bat +baseball glove +skateboard +surfboard +tennis racket +bottle +??? +wine glass +cup +fork +knife +spoon +bowl +banana +apple +sandwich +orange +broccoli +carrot +hot dog +pizza +donut +cake +chair +couch +potted plant +bed +??? +dining table +??? +??? +toilet +??? +tv +laptop +mouse +remote +keyboard +cell phone +microwave +oven +toaster +sink +refrigerator +??? +book +clock +vase +scissors +teddy bear +hair drier +toothbrush diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..2e9b505 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +import 'views/object_detector.dart'; + +void main() { + WidgetsFlutterBinding.ensureInitialized(); + runApp(const FitsterApp()); +} + +class FitsterApp extends StatelessWidget { + const FitsterApp({super.key}); + + static const title = 'Fitster Demo'; + + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + title: title, + debugShowCheckedModeBanner: false, + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: const ObjectDetectorView(title: title), + ); + } +} diff --git a/lib/views/camera_view.dart b/lib/views/camera_view.dart new file mode 100644 index 0000000..62ef9eb --- /dev/null +++ b/lib/views/camera_view.dart @@ -0,0 +1,226 @@ +import 'package:camera/camera.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:google_mlkit_object_detection/google_mlkit_object_detection.dart'; + +enum CameraViewStatus { + initializing, + ready, + live, + stopped, + failed; + + bool get isInitializing => this == CameraViewStatus.initializing; + bool get isReady => this == CameraViewStatus.ready; + bool get isLive => this == CameraViewStatus.live; + bool get isStopped => this == CameraViewStatus.stopped; + bool get isFailed => this == CameraViewStatus.failed; + + bool get isUsable => isReady || isLive; +} + +class CameraView extends StatefulWidget { + final String title; + final Function(InputImage inputImage) onImage; + final CameraLensDirection initialDirection; + + const CameraView({ + super.key, + required this.title, + required this.onImage, + this.initialDirection = CameraLensDirection.back, + }); + + @override + State createState() => _CameraViewState(); +} + +class _CameraViewState extends State { + List? _cameras; + CameraController? _controller; + CameraViewStatus _status = CameraViewStatus.initializing; + + int _cameraIndex = -1; + bool _changingCamera = false; + + @override + void initState() { + super.initState(); + _initCameras(); + } + + @override + void dispose() { + _stopLiveFeed(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + actions: [ + if (_status.isUsable && _cameras!.length > 1) + Padding( + padding: const EdgeInsets.only(right: 16), + child: GestureDetector( + onTap: _switchLiveCamera, + child: const Icon(Icons.flip_camera_android_outlined, size: 48), + ), + ), + ], + ), + body: _liveFeedBody(), + ); + } + + Widget _liveFeedBody() { + if (_status.isFailed) { + return const Center(child: Text('Failed to initialize camera')); + } + + if (!_status.isUsable || _controller?.value.isInitialized == false) { + return const Center(child: Text('Camera uninitialized')); + } + + final size = MediaQuery.of(context).size; + // calculate scale depending on screen and camera ratios + // this is actually size.aspectRatio / (1 / camera.aspectRatio) + // because camera preview size is received as landscape + // but we're calculating for portrait orientation + var scale = size.aspectRatio * _controller!.value.aspectRatio; + + // to prevent scaling down, invert the value + if (scale < 1) scale = 1 / scale; + + return Container( + color: Colors.black, + child: Transform.scale( + scale: scale, + child: Center( + child: CameraPreview(_controller!), + ), + ), + ); + } + + bool _hasInitialCamera(CameraDescription camera) { + return camera.lensDirection == widget.initialDirection && + camera.sensorOrientation == 90; + } + + Future _initCameras() async { + _cameras = await availableCameras(); + + if (_cameras!.any(_hasInitialCamera)) { + _cameraIndex = _cameras!.indexWhere(_hasInitialCamera); + } else { + for (var i = 0; i < _cameras!.length; ++i) { + if (_cameras![i].lensDirection == widget.initialDirection) { + _cameraIndex = i; + break; + } + } + } + + if (_cameraIndex != -1) { + setState(() { + _status = CameraViewStatus.ready; + }); + await _startLiveFeed(); + } else { + setState(() { + _status = CameraViewStatus.failed; + }); + } + } + + Future _switchLiveCamera() async { + if (_changingCamera || _cameras == null) return; + + setState(() => _changingCamera = true); + _cameraIndex = (_cameraIndex + 1) % _cameras!.length; + + await _stopLiveFeed(); + await _startLiveFeed(); + + setState(() => _changingCamera = false); + } + + Future _startLiveFeed() async { + if (!(_status.isReady || _status.isStopped)) return; + + final camera = _cameras![_cameraIndex]; + _controller = CameraController( + camera, + ResolutionPreset.high, + enableAudio: false, + ); + _controller?.initialize().then((_) { + if (!mounted) { + return; + } + _controller?.startImageStream(_processImageStream); + setState(() { + _status = CameraViewStatus.live; + }); + }); + } + + Future _stopLiveFeed() async { + if (!_status.isLive) return; + + setState(() { + _status = CameraViewStatus.stopped; + }); + + await _controller?.stopImageStream(); + await _controller?.dispose(); + _controller = null; + } + + Future _processImageStream(CameraImage image) async { + final WriteBuffer buffer = WriteBuffer(); + for (final plane in image.planes) { + buffer.putUint8List(plane.bytes); + } + final bytes = buffer.done().buffer.asUint8List(); + + final Size imageSize = + Size(image.width.toDouble(), image.height.toDouble()); + + final camera = _cameras![_cameraIndex]; + final imageRotation = + InputImageRotationValue.fromRawValue(camera.sensorOrientation); + if (imageRotation == null) return; + + final inputImageFormat = + InputImageFormatValue.fromRawValue(image.format.raw); + if (inputImageFormat == null) return; + + final planeData = image.planes.map( + (plane) { + return InputImagePlaneMetadata( + bytesPerRow: plane.bytesPerRow, + height: plane.height, + width: plane.width, + ); + }, + ).toList(); + + final inputImageData = InputImageData( + size: imageSize, + imageRotation: imageRotation, + inputImageFormat: inputImageFormat, + planeData: planeData, + ); + + final inputImage = InputImage.fromBytes( + bytes: bytes, + inputImageData: inputImageData, + ); + + widget.onImage(inputImage); + } +} diff --git a/lib/views/object_detector.dart b/lib/views/object_detector.dart new file mode 100644 index 0000000..8c2f9a1 --- /dev/null +++ b/lib/views/object_detector.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:google_mlkit_object_detection/google_mlkit_object_detection.dart'; + +import 'camera_view.dart'; + +class ObjectDetectorView extends StatefulWidget { + final String title; + + const ObjectDetectorView({ + super.key, + required this.title, + }); + + @override + State createState() => _ObjectDetectorViewState(); +} + +class _ObjectDetectorViewState extends State { + @override + Widget build(BuildContext context) { + return CameraView(title: widget.title, onImage: processImage); + } + + Future processImage(InputImage inputImage) async {} +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..13ed64c --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,290 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" + source: hosted + version: "2.10.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + camera: + dependency: "direct main" + description: + name: camera + sha256: "7afc256902062cab191540c09908b98bc71e93d5e20b6486dbee51aa7731e9b2" + url: "https://pub.dev" + source: hosted + version: "0.10.4" + camera_android: + dependency: transitive + description: + name: camera_android + sha256: "0852318827ee91563595b29db4cecfd95c1e7c8945a3bf4affa98cf043347230" + url: "https://pub.dev" + source: hosted + version: "0.10.6+1" + camera_avfoundation: + dependency: transitive + description: + name: camera_avfoundation + sha256: "7ac8b950672716722af235eed7a7c37896853669800b7da706bb0a9fd41d3737" + url: "https://pub.dev" + source: hosted + version: "0.9.13+1" + camera_platform_interface: + dependency: transitive + description: + name: camera_platform_interface + sha256: "525017018d116c5db8c4c43ec2d9b1663216b369c9f75149158280168a7ce472" + url: "https://pub.dev" + source: hosted + version: "2.5.0" + camera_web: + dependency: transitive + description: + name: camera_web + sha256: d77965f32479ee6d8f48205dcf10f845d7210595c6c00faa51eab265d1cae993 + url: "https://pub.dev" + source: hosted + version: "0.3.1+3" + characters: + dependency: transitive + description: + name: characters + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" + source: hosted + version: "1.2.1" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" + source: hosted + version: "1.17.0" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9" + url: "https://pub.dev" + source: hosted + version: "0.3.3+4" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" + source: hosted + version: "1.0.5" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" + source: hosted + version: "2.0.1" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "2818f5233cf8fa5fc51f6d78ce0028feb4e7c18d0b6d40b57b91f366eea7e656" + url: "https://pub.dev" + source: hosted + version: "2.0.12" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + google_mlkit_commons: + dependency: transitive + description: + name: google_mlkit_commons + sha256: "68429fa2e17686819dbaf2344790e3daa59924ef8625dd24f97f9deaaed42767" + url: "https://pub.dev" + source: hosted + version: "0.3.0" + google_mlkit_object_detection: + dependency: "direct main" + description: + name: google_mlkit_object_detection + sha256: ebde4ae04b29fbfe41d91d867bb00003b16d7cd326de765ae87890372bb358a0 + url: "https://pub.dev" + source: hosted + version: "0.7.0" + js: + dependency: transitive + description: + name: js + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" + source: hosted + version: "0.6.5" + lints: + dependency: transitive + description: + name: lints + sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" + source: hosted + version: "0.12.13" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + meta: + dependency: transitive + description: + name: meta + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" + source: hosted + version: "1.8.0" + path: + dependency: transitive + description: + name: path + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" + source: hosted + version: "1.8.2" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + quiver: + dependency: transitive + description: + name: quiver + sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47 + url: "https://pub.dev" + source: hosted + version: "3.2.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" + source: hosted + version: "1.9.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" + source: hosted + version: "0.4.16" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" +sdks: + dart: ">=2.19.6 <3.0.0" + flutter: ">=3.3.0" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..61e9e55 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,92 @@ +name: fitster_poc +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.19.6 <3.0.0' + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + camera: ^0.10.4 + google_mlkit_object_detection: ^0.7.0 + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # 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: ^2.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 packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + assets: + - assets/ + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/test/widget_test.dart b/test/widget_test.dart new file mode 100644 index 0000000..4ca5b55 --- /dev/null +++ b/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// 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:fitster_poc/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const FitsterApp()); + + // 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); + }); +}