Merge pull request 'feature/modal-description-ai' (#5) from feature/modal-description-ai into main

Reviewed-on: #5
This commit is contained in:
v4l3n71n 2024-07-22 23:17:58 +02:00
commit 8063124fe6
10 changed files with 249 additions and 71 deletions

View File

@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
mixin ShowDescImageAdd<T extends StatefulWidget> on State<T> {
void showDescImageAddDialog(BuildContext context, String text) {
// Create AlertDialog
AlertDialog dialog = AlertDialog(
title: Text("Description image"),
content: Text(text),
actions: [
ElevatedButton(
child: Text("OK"),
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(horizontal: 50, vertical: 20),
textStyle:
TextStyle(fontSize: 15, fontWeight: FontWeight.normal)),
onPressed: () {
Navigator.of(context).pop("Yes, Of course!"); // Return value
}),
],
);
// Call showDialog function to show dialog.
Future futureValue = showDialog(
context: context,
builder: (BuildContext context) {
return dialog;
});
}
}

View File

@ -1,6 +1,8 @@
import 'dart:async';
import 'dart:io';
import 'package:image_picker/image_picker.dart';
import 'DisplayPictureScreen.dart';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
@ -63,6 +65,22 @@ class CameraState extends State<Camera> {
Future<void> getCamera() async {}
Future<void> pickImage() async {
final imagePicker = ImagePicker();
final pickedFile = await imagePicker.pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DisplayPictureScreen(
// Pass the automatically generated path to
// the DisplayPictureScreen widget.
imagePath: pickedFile.path,
),
),
);
}
}
@override
void dispose() {
// Dispose of the controller when the widget is disposed.
@ -73,54 +91,65 @@ class CameraState extends State<Camera> {
@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<void>(
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,
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<void>(
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: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FloatingActionButton(
onPressed: pickImage,
child: Icon(Icons.photo_library),
),
),
);
} catch (e) {
// If an error occurs, log the error to the console.
print(e);
}
},
child: const Icon(Icons.camera_alt),
),
);
SizedBox(width: 40),
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),
)
],
)));
}
}

View File

@ -1,7 +1,8 @@
import 'package:flutter/material.dart';
import 'dart:io';
import '../classes/descriptionImage.dart';
import '../classes/alert.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_gemini/flutter_gemini.dart';
void main() {
@ -44,7 +45,8 @@ class DisplayPictureScreen extends StatefulWidget {
}
// A widget that displays the picture taken by the user.
class DisplayPictureScreenState extends State<DisplayPictureScreen> {
class DisplayPictureScreenState extends State<DisplayPictureScreen>
with ShowDescImageAdd, ShowErrorDialog {
@override
void initState() {
super.initState();
@ -52,6 +54,12 @@ class DisplayPictureScreenState extends State<DisplayPictureScreen> {
_getEventInfosFromImage();
}
Future<void> displayError(String e) async {
print("problem gemini : ${e}");
showErrorDialog(context,
"L'IA de Google n'a pas su analyser l'image. Recommecer avec une autre");
}
Future<void> _getEventInfosFromImage() async {
await dotenv.load();
@ -62,9 +70,13 @@ class DisplayPictureScreenState extends State<DisplayPictureScreen> {
gemini
.textAndImage(
text: "What is this picture ?", images: [file.readAsBytesSync()])
.then((value) => print(value?.content?.parts?.last.text ?? ''))
.catchError((e) => print("problem gemini : ${e}"));
text:
"Peux-tu donner le nom, la date et le lieu de l'évènement sous format JSON avec les valeurs suivantes : name, place et date",
images: [file.readAsBytesSync()],
modelName: "models/gemini-1.5-flash-latest")
.then((value) => showDescImageAddDialog(
context, value?.content?.parts?.last.text ?? ''))
.catchError((e) => displayError);
}
@override

View File

@ -6,6 +6,10 @@
#include "generated_plugin_registrant.h"
#include <file_selector_linux/file_selector_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
}

View File

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
file_selector_linux
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST

View File

@ -5,10 +5,12 @@
import FlutterMacOS
import Foundation
import file_selector_macos
import path_provider_foundation
import shared_preferences_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
}

View File

@ -85,10 +85,10 @@ packages:
dependency: transitive
description:
name: cross_file
sha256: "2f9d2cbccb76127ba28528cb3ae2c2326a122446a83de5a056aaa3880d3882c5"
sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32"
url: "https://pub.dev"
source: hosted
version: "0.3.3+7"
version: "0.3.4+1"
cupertino_icons:
dependency: "direct main"
description:
@ -137,6 +137,38 @@ packages:
url: "https://pub.dev"
source: hosted
version: "7.0.0"
file_selector_linux:
dependency: transitive
description:
name: file_selector_linux
sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492"
url: "https://pub.dev"
source: hosted
version: "0.9.2+1"
file_selector_macos:
dependency: transitive
description:
name: file_selector_macos
sha256: f42eacb83b318e183b1ae24eead1373ab1334084404c8c16e0354f9a3e55d385
url: "https://pub.dev"
source: hosted
version: "0.9.4"
file_selector_platform_interface:
dependency: transitive
description:
name: file_selector_platform_interface
sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b
url: "https://pub.dev"
source: hosted
version: "2.6.2"
file_selector_windows:
dependency: transitive
description:
name: file_selector_windows
sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0
url: "https://pub.dev"
source: hosted
version: "0.9.3+1"
flutter:
dependency: "direct main"
description: flutter
@ -196,10 +228,10 @@ packages:
dependency: "direct main"
description:
name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
url: "https://pub.dev"
source: hosted
version: "1.2.2"
version: "1.2.1"
http_parser:
dependency: transitive
description:
@ -208,6 +240,70 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.2"
image_picker:
dependency: "direct main"
description:
name: image_picker
sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a"
url: "https://pub.dev"
source: hosted
version: "1.1.2"
image_picker_android:
dependency: transitive
description:
name: image_picker_android
sha256: cea2bd5b9fcff039a4901d3b13c67fe747f940be9ba76bde1bcd218d168eeb7f
url: "https://pub.dev"
source: hosted
version: "0.8.12+6"
image_picker_for_web:
dependency: transitive
description:
name: image_picker_for_web
sha256: "5d6eb13048cd47b60dbf1a5495424dea226c5faf3950e20bf8120a58efb5b5f3"
url: "https://pub.dev"
source: hosted
version: "3.0.4"
image_picker_ios:
dependency: transitive
description:
name: image_picker_ios
sha256: "6703696ad49f5c3c8356d576d7ace84d1faf459afb07accbb0fae780753ff447"
url: "https://pub.dev"
source: hosted
version: "0.8.12"
image_picker_linux:
dependency: transitive
description:
name: image_picker_linux
sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa"
url: "https://pub.dev"
source: hosted
version: "0.2.1+1"
image_picker_macos:
dependency: transitive
description:
name: image_picker_macos
sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62"
url: "https://pub.dev"
source: hosted
version: "0.2.1+1"
image_picker_platform_interface:
dependency: transitive
description:
name: image_picker_platform_interface
sha256: "9ec26d410ff46f483c5519c29c02ef0e02e13a543f882b152d4bfd2f06802f80"
url: "https://pub.dev"
source: hosted
version: "2.10.0"
image_picker_windows:
dependency: transitive
description:
name: image_picker_windows
sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb"
url: "https://pub.dev"
source: hosted
version: "0.2.1+1"
intl:
dependency: "direct main"
description:
@ -216,14 +312,6 @@ 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:
@ -348,10 +436,10 @@ packages:
dependency: transitive
description:
name: path_provider_windows
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
version: "2.2.1"
platform:
dependency: transitive
description:
@ -412,10 +500,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_web
sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf
sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
version: "2.3.0"
shared_preferences_windows:
dependency: transitive
description:
@ -513,10 +601,18 @@ packages:
dependency: transitive
description:
name: web
sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
version: "0.5.1"
win32:
dependency: transitive
description:
name: win32
sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
url: "https://pub.dev"
source: hosted
version: "5.5.1"
xdg_directories:
dependency: transitive
description:

View File

@ -43,6 +43,7 @@ dependencies:
path: ^1.9.0
flutter_gemini: ^2.0.4
flutter_dotenv: ^5.1.0
image_picker: ^1.1.2
dev_dependencies:
flutter_test:

View File

@ -6,6 +6,9 @@
#include "generated_plugin_registrant.h"
#include <file_selector_windows/file_selector_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
FileSelectorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FileSelectorWindows"));
}

View File

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
file_selector_windows
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST