diff --git a/covas_mobile/.gitignore b/covas_mobile/.gitignore index a8e938c..e158b41 100644 --- a/covas_mobile/.gitignore +++ b/covas_mobile/.gitignore @@ -45,3 +45,5 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release + +.env \ No newline at end of file diff --git a/covas_mobile/android/build.gradle b/covas_mobile/android/build.gradle index 3cdaac9..8b2a770 100644 --- a/covas_mobile/android/build.gradle +++ b/covas_mobile/android/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlin_version = '1.6.10' + ext.kotlin_version = '2.0.0' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.1.2' + classpath 'com.android.tools.build:gradle:7.1.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/covas_mobile/lib/pages/Camera.dart b/covas_mobile/lib/pages/Camera.dart new file mode 100644 index 0000000..a1b93c3 --- /dev/null +++ b/covas_mobile/lib/pages/Camera.dart @@ -0,0 +1,126 @@ +import 'dart:async'; +import 'dart:io'; + +import 'DisplayPictureScreen.dart'; +import 'package:camera/camera.dart'; +import 'package:flutter/material.dart'; + +Future main() async { + // Ensure that plugin services are initialized so that `availableCameras()` + // can be called before `runApp()` + WidgetsFlutterBinding.ensureInitialized(); + + // Obtain a list of the available cameras on the device. + final cameras = await availableCameras(); + + // Get a specific camera from the list of available cameras. + final firstCamera = cameras.first; + + runApp( + MaterialApp( + theme: ThemeData.dark(), + home: Camera( + // Pass the appropriate camera to the TakePictureScreen widget. + camera: firstCamera, + ), + ), + ); +} + +// A screen that allows users to take a picture using a given camera. +class Camera extends StatefulWidget { + const Camera({ + super.key, + required this.camera, + }); + + final CameraDescription camera; + + @override + CameraState createState() => CameraState(); +} + +class CameraState extends State { + late CameraController _controller; + late Future _initializeControllerFuture; + + @override + void initState() { + super.initState(); + // To display the current output from the Camera, + // create a CameraController. + + _controller = CameraController( + // Get a specific camera from the list of available cameras. + widget.camera, + // Define the resolution to use. + ResolutionPreset.medium, + ); + + // Next, initialize the controller. This returns a Future. + _initializeControllerFuture = _controller.initialize(); + } + + Future getCamera() async {} + + @override + void dispose() { + // Dispose of the controller when the widget is disposed. + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Take a picture')), + // You must wait until the controller is initialized before displaying the + // camera preview. Use a FutureBuilder to display a loading spinner until the + // controller has finished initializing. + body: FutureBuilder( + future: _initializeControllerFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + // If the Future is complete, display the preview. + return CameraPreview(_controller); + } else { + // Otherwise, display a loading indicator. + return const Center(child: CircularProgressIndicator()); + } + }, + ), + floatingActionButton: FloatingActionButton( + // Provide an onPressed callback. + onPressed: () async { + // Take the Picture in a try / catch block. If anything goes wrong, + // catch the error. + try { + // Ensure that the camera is initialized. + await _initializeControllerFuture; + + // Attempt to take a picture and get the file `image` + // where it was saved. + final image = await _controller.takePicture(); + + if (!context.mounted) return; + + // If the picture was taken, display it on a new screen. + await Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => DisplayPictureScreen( + // Pass the automatically generated path to + // the DisplayPictureScreen widget. + imagePath: image.path, + ), + ), + ); + } catch (e) { + // If an error occurs, log the error to the console. + print(e); + } + }, + child: const Icon(Icons.camera_alt), + ), + ); + } +} diff --git a/covas_mobile/lib/pages/DisplayPictureScreen.dart b/covas_mobile/lib/pages/DisplayPictureScreen.dart new file mode 100644 index 0000000..adc9c6e --- /dev/null +++ b/covas_mobile/lib/pages/DisplayPictureScreen.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; +import 'dart:io'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; + +import 'package:flutter_gemini/flutter_gemini.dart'; + +void main() { + runApp(MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({Key? key}) : super(key: key); + + // This widget is the root of your application. + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + // This is the theme of your application. + // + // Try running your application with "flutter run". You'll see the + // application has a blue toolbar. Then, without quitting the app, try + // changing the primarySwatch below to Colors.green and then invoke + // "hot reload" (press "r" in the console where you ran "flutter run", + // or simply save your changes to "hot reload" in a Flutter IDE). + // Notice that the counter didn't reset back to zero; the application + // is not restarted. + primarySwatch: Colors.blue, + ), + ); + } +} + +// A screen that allows users to take a picture using a given camera. +class DisplayPictureScreen extends StatefulWidget { + final String imagePath; + + const DisplayPictureScreen({super.key, required this.imagePath}); + + @override + DisplayPictureScreenState createState() => DisplayPictureScreenState(); +} + +// A widget that displays the picture taken by the user. +class DisplayPictureScreenState extends State { + @override + void initState() { + super.initState(); + + _getEventInfosFromImage(); + } + + Future _getEventInfosFromImage() async { + await dotenv.load(); + + final gemini = Gemini.init( + apiKey: dotenv.env['GEMINI_API_KEY']!, enableDebugging: true); + + final file = File(widget.imagePath); + + gemini + .textAndImage( + text: "What is this picture ?", images: [file.readAsBytesSync()]) + .then((value) => print(value?.content?.parts?.last.text ?? '')) + .catchError((e) => print("problem gemini : ${e}")); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Display the Picture')), + // The image is stored as a file on the device. Use the `Image.file` + // constructor with the given path to display the image. + body: SingleChildScrollView( + child: Column(children: [ + Image.file(File(widget.imagePath)), + Text("Analyse en cours...") + ]))); + } +} diff --git a/covas_mobile/lib/pages/ListItemMenu.dart b/covas_mobile/lib/pages/ListItemMenu.dart index 31ee70a..2f31a10 100644 --- a/covas_mobile/lib/pages/ListItemMenu.dart +++ b/covas_mobile/lib/pages/ListItemMenu.dart @@ -1,12 +1,15 @@ import 'dart:convert'; import 'dart:io'; import "ItemMenu.dart"; +import "Camera.dart"; + import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; import '../classes/events.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:intl/intl.dart'; import 'package:intl/date_symbol_data_local.dart'; +import 'package:camera/camera.dart'; import '../variable/globals.dart' as globals; @@ -57,6 +60,11 @@ class _MyHomePageState extends State { return body; } + Future popCamera() async { + await availableCameras().then((value) => Navigator.push(context, + MaterialPageRoute(builder: (_) => Camera(camera: value.first)))); + } + // build function @override Widget build(BuildContext context) { @@ -117,7 +125,7 @@ class _MyHomePageState extends State { }, ), floatingActionButton: FloatingActionButton( - onPressed: () {}, + onPressed: popCamera, backgroundColor: Colors.blue, tooltip: 'Recherche', child: const Icon(Icons.search, color: Colors.white), diff --git a/covas_mobile/macos/Flutter/GeneratedPluginRegistrant.swift b/covas_mobile/macos/Flutter/GeneratedPluginRegistrant.swift index 724bb2a..b8e2b22 100644 --- a/covas_mobile/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/covas_mobile/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,8 +5,10 @@ import FlutterMacOS import Foundation +import path_provider_foundation import shared_preferences_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) } diff --git a/covas_mobile/pubspec.lock b/covas_mobile/pubspec.lock index b873bf1..5c8ffbb 100644 --- a/covas_mobile/pubspec.lock +++ b/covas_mobile/pubspec.lock @@ -17,6 +17,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + camera: + dependency: "direct main" + description: + name: camera + sha256: "2170a943dcb67be2af2c6bcda8775e74b41d4c02d6a4eb10bdc832ee185c4eea" + url: "https://pub.dev" + source: hosted + version: "0.11.0+1" + camera_android_camerax: + dependency: transitive + description: + name: camera_android_camerax + sha256: "7c03940cb8c92eb5b184952674a07cc4a73c6ba2b3568aad70255ad4cb913660" + url: "https://pub.dev" + source: hosted + version: "0.6.7+1" + camera_avfoundation: + dependency: transitive + description: + name: camera_avfoundation + sha256: b5093a82537b64bb88d4244f8e00b5ba69e822a5994f47b31d11400e1db975e5 + url: "https://pub.dev" + source: hosted + version: "0.9.17+1" + camera_platform_interface: + dependency: transitive + description: + name: camera_platform_interface + sha256: b3ede1f171532e0d83111fe0980b46d17f1aa9788a07a2fbed07366bbdbb9061 + url: "https://pub.dev" + source: hosted + version: "2.8.0" + camera_web: + dependency: "direct main" + description: + name: camera_web + sha256: b9235ec0a2ce949daec546f1f3d86f05c3921ed31c7d9ab6b7c03214d152fc2d + url: "https://pub.dev" + source: hosted + version: "0.3.4" characters: dependency: transitive description: @@ -41,6 +81,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "2f9d2cbccb76127ba28528cb3ae2c2326a122446a83de5a056aaa3880d3882c5" + url: "https://pub.dev" + source: hosted + version: "0.3.3+7" cupertino_icons: dependency: "direct main" description: @@ -49,6 +97,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + dio: + dependency: transitive + description: + name: dio + sha256: e17f6b3097b8c51b72c74c9f071a605c47bcc8893839bd66732457a5ebe73714 + url: "https://pub.dev" + source: hosted + version: "5.5.0+1" + dio_web_adapter: + dependency: transitive + description: + name: dio_web_adapter + sha256: "36c5b2d79eb17cdae41e974b7a8284fec631651d2a6f39a8a2ff22327e90aeac" + url: "https://pub.dev" + source: hosted + version: "1.0.1" fake_async: dependency: transitive description: @@ -78,6 +142,22 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_dotenv: + dependency: "direct main" + description: + name: flutter_dotenv + sha256: "9357883bdd153ab78cbf9ffa07656e336b8bbb2b5a3ca596b0b27e119f7c7d77" + url: "https://pub.dev" + source: hosted + version: "5.1.0" + flutter_gemini: + dependency: "direct main" + description: + name: flutter_gemini + sha256: c6079dc6f95c6191e609e9cc627c268ef0bf2526cbba6a2f61aa41ea0053e9a0 + url: "https://pub.dev" + source: hosted + version: "2.0.4" flutter_lints: dependency: "direct dev" description: @@ -86,6 +166,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: c6b0b4c05c458e1c01ad9bcc14041dd7b1f6783d487be4386f793f47a8a4d03e + url: "https://pub.dev" + source: hosted + version: "2.0.20" flutter_test: dependency: "direct dev" description: flutter @@ -96,14 +184,22 @@ packages: description: flutter source: sdk version: "0.0.0" + freezed_annotation: + dependency: transitive + description: + name: freezed_annotation + sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2 + url: "https://pub.dev" + source: hosted + version: "2.4.4" http: dependency: "direct main" description: name: http - sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" http_parser: dependency: transitive description: @@ -120,6 +216,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.19.0" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" leak_tracker: dependency: transitive description: @@ -176,14 +288,46 @@ packages: url: "https://pub.dev" source: hosted version: "1.12.0" - path: + mime: dependency: transitive + description: + name: mime + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + path: + dependency: "direct main" description: name: path sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted version: "1.9.0" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 + url: "https://pub.dev" + source: hosted + version: "2.1.3" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "30c5aa827a6ae95ce2853cdc5fe3971daaac00f6f081c419c013f7f57bff2f5e" + url: "https://pub.dev" + source: hosted + version: "2.2.7" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + url: "https://pub.dev" + source: hosted + version: "2.4.0" path_provider_linux: dependency: transitive description: @@ -204,10 +348,10 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" platform: dependency: transitive description: @@ -268,10 +412,10 @@ packages: dependency: transitive description: name: shared_preferences_web - sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a" + sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.2.1" shared_preferences_windows: dependency: transitive description: @@ -309,6 +453,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + 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: @@ -361,18 +513,10 @@ packages: dependency: transitive description: name: web - sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 url: "https://pub.dev" source: hosted - version: "0.5.1" - win32: - dependency: transitive - description: - name: win32 - sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4 - url: "https://pub.dev" - source: hosted - version: "5.5.1" + version: "1.0.0" xdg_directories: dependency: transitive description: diff --git a/covas_mobile/pubspec.yaml b/covas_mobile/pubspec.yaml index 2865742..25fb5de 100644 --- a/covas_mobile/pubspec.yaml +++ b/covas_mobile/pubspec.yaml @@ -37,6 +37,12 @@ dependencies: http: ^1.2.1 shared_preferences: ^2.2.3 intl: ^0.19.0 + camera: ^0.11.0+1 + camera_web: ^0.3.3 + path_provider: ^2.1.3 + path: ^1.9.0 + flutter_gemini: ^2.0.4 + flutter_dotenv: ^5.1.0 dev_dependencies: flutter_test: @@ -63,6 +69,7 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - images/flutter.png + - .env # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see