From 49a108905c0a00bc1980abde8392b62f44726b7a Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Sat, 14 Dec 2024 19:10:23 +0100 Subject: [PATCH 1/3] add button edit image --- covas_mobile/lib/pages/Camera.dart | 2 -- covas_mobile/lib/pages/EditEvent.dart | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/covas_mobile/lib/pages/Camera.dart b/covas_mobile/lib/pages/Camera.dart index 9ff6cc3..1187d8f 100644 --- a/covas_mobile/lib/pages/Camera.dart +++ b/covas_mobile/lib/pages/Camera.dart @@ -63,8 +63,6 @@ class CameraState extends State { _initializeControllerFuture = _controller.initialize(); } - Future getCamera() async {} - Future pickImage() async { final imagePicker = ImagePicker(); final pickedFile = await imagePicker.pickImage(source: ImageSource.gallery); diff --git a/covas_mobile/lib/pages/EditEvent.dart b/covas_mobile/lib/pages/EditEvent.dart index 1f38d90..38b4447 100644 --- a/covas_mobile/lib/pages/EditEvent.dart +++ b/covas_mobile/lib/pages/EditEvent.dart @@ -449,6 +449,23 @@ class _EditEventState extends State ); }, )), + Padding( + padding: EdgeInsets.symmetric(horizontal: 15), + child: ElevatedButton.icon( + onPressed: () { + // Define your action here + print("Edit Image button pressed"); + }, + icon: Icon(Icons.edit, size: 16), // Edit icon + label: Text("Edit Image"), // Button text + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, // Button color + foregroundColor: Colors.white, // Text color + padding: + EdgeInsets.symmetric(horizontal: 10, vertical: 5), + ), + ), + ), Padding( //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0), padding: EdgeInsets.symmetric(horizontal: 15), From 578107c83c3826795c6ed999fa1206c268a97f64 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Sat, 14 Dec 2024 21:30:32 +0100 Subject: [PATCH 2/3] add cameraedit --- covas_mobile/lib/pages/CameraEdit.dart | 154 +++++++++++++++++++++++++ covas_mobile/lib/pages/EditEvent.dart | 86 +++++++++----- covas_mobile/lib/pages/ItemMenu.dart | 6 +- 3 files changed, 216 insertions(+), 30 deletions(-) create mode 100644 covas_mobile/lib/pages/CameraEdit.dart diff --git a/covas_mobile/lib/pages/CameraEdit.dart b/covas_mobile/lib/pages/CameraEdit.dart new file mode 100644 index 0000000..b104f3f --- /dev/null +++ b/covas_mobile/lib/pages/CameraEdit.dart @@ -0,0 +1,154 @@ +import 'dart:async'; +import 'dart:io'; + +import '../classes/events.dart'; +import 'package:image_picker/image_picker.dart'; +import 'EditEvent.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; + Events? events; + + runApp( + MaterialApp( + theme: ThemeData.dark(), + home: CameraEdit( + // Pass the appropriate camera to the TakePictureScreen widget. + camera: firstCamera, + events: events), + ), + ); +} + +// A screen that allows users to take a picture using a given camera. +class CameraEdit extends StatefulWidget { + const CameraEdit({super.key, required this.camera, required this.events}); + final Events? events; + + final CameraDescription camera; + + @override + CameraEditState createState() => CameraEditState(); +} + +class CameraEditState 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 pickImage() async { + final imagePicker = ImagePicker(); + final pickedFile = await imagePicker.pickImage(source: ImageSource.gallery); + if (pickedFile != null) { + await Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => EditEvent( + // Pass the automatically generated path to + // the DisplayPictureScreen widget. + events: widget.events, + imgPath: pickedFile.path, + ), + ), + ); + } + } + + @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: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FloatingActionButton( + onPressed: pickImage, + child: Icon(Icons.photo_library), + ), + 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) => EditEvent( + // Pass the automatically generated path to + // the DisplayPictureScreen widget. + events: widget.events, + imgPath: 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/EditEvent.dart b/covas_mobile/lib/pages/EditEvent.dart index 38b4447..0ebb8cb 100644 --- a/covas_mobile/lib/pages/EditEvent.dart +++ b/covas_mobile/lib/pages/EditEvent.dart @@ -1,3 +1,4 @@ +import 'package:covas_mobile/pages/CameraEdit.dart'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:http/http.dart' as http; @@ -10,6 +11,9 @@ import 'dart:io'; import '../classes/events.dart'; import 'ItemMenu.dart'; +import 'CameraEdit.dart'; +import 'package:camera/camera.dart'; + import '../classes/alert.dart'; import '../classes/eventAdded.dart'; @@ -26,15 +30,21 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, - home: EditEvent(events: events), + home: EditEvent( + events: events, + imgPath: "", + ), ); } } class EditEvent extends StatefulWidget { - const EditEvent({Key? key, required this.events}) : super(key: key); + const EditEvent({Key? key, required this.events, required this.imgPath}) + : super(key: key); final Events? events; + final String imgPath; + @override _EditEventState createState() => _EditEventState(); } @@ -411,6 +421,14 @@ class _EditEventState extends State ); } + Future popCamera() async { + await availableCameras().then((value) => Navigator.push( + context, + MaterialPageRoute( + builder: (_) => + CameraEdit(camera: value.first, events: widget.events)))); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -425,37 +443,47 @@ class _EditEventState extends State child: SingleChildScrollView( child: Column( children: [ - Padding( + if (widget.imgPath.isNotEmpty) + Padding( padding: const EdgeInsets.only(top: 60.0), - child: Image.network( - imgUrl, - width: MediaQuery.of(context).size.width * - 0.5, // 50% of screen width - height: MediaQuery.of(context).size.height * 0.5, - loadingBuilder: (BuildContext context, Widget child, - ImageChunkEvent? loadingProgress) { - if (loadingProgress == null) { - return child; // The image has finished loading - } - return Center( - child: CircularProgressIndicator(), - ); - }, - errorBuilder: (BuildContext context, Object error, - StackTrace? stackTrace) { - return Center( - child: Icon(Icons.error, - size: MediaQuery.of(context).size.width * 0.1), - ); - }, - )), + child: Center( + child: Container( + width: 200, + height: 150, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(100.0)), + child: Image.file(File(widget.imgPath))), + ), + ), + if (widget.imgPath.isEmpty) + Padding( + padding: const EdgeInsets.only(top: 60.0), + child: Image.network( + imgUrl, + width: MediaQuery.of(context).size.width * + 0.5, // 50% of screen width + height: MediaQuery.of(context).size.height * 0.5, + loadingBuilder: (BuildContext context, Widget child, + ImageChunkEvent? loadingProgress) { + if (loadingProgress == null) { + return child; // The image has finished loading + } + return Center( + child: CircularProgressIndicator(), + ); + }, + errorBuilder: (BuildContext context, Object error, + StackTrace? stackTrace) { + return Center( + child: Icon(Icons.error, + size: MediaQuery.of(context).size.width * 0.1), + ); + }, + )), Padding( padding: EdgeInsets.symmetric(horizontal: 15), child: ElevatedButton.icon( - onPressed: () { - // Define your action here - print("Edit Image button pressed"); - }, + onPressed: popCamera, icon: Icon(Icons.edit, size: 16), // Edit icon label: Text("Edit Image"), // Button text style: ElevatedButton.styleFrom( diff --git a/covas_mobile/lib/pages/ItemMenu.dart b/covas_mobile/lib/pages/ItemMenu.dart index ce4498d..daafdc8 100644 --- a/covas_mobile/lib/pages/ItemMenu.dart +++ b/covas_mobile/lib/pages/ItemMenu.dart @@ -408,7 +408,11 @@ class _ItemMenuState extends State with ShowErrorDialog { onPressed: () { Navigator.push( context, - MaterialPageRoute(builder: (_) => EditEvent(events: events)), + MaterialPageRoute( + builder: (_) => EditEvent( + events: events, + imgPath: "", + )), ); }, backgroundColor: Colors.blue, From ea3d5ef8de5a90517851485affc00d38bb08ee48 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Sun, 15 Dec 2024 20:10:19 +0100 Subject: [PATCH 3/3] =?UTF-8?q?add=20post=20image=20in=20edit=20event?= =?UTF-8?q?=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- covas_mobile/lib/pages/EditEvent.dart | 33 ++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/covas_mobile/lib/pages/EditEvent.dart b/covas_mobile/lib/pages/EditEvent.dart index 0ebb8cb..fedc2bb 100644 --- a/covas_mobile/lib/pages/EditEvent.dart +++ b/covas_mobile/lib/pages/EditEvent.dart @@ -8,6 +8,8 @@ import 'package:textfield_tags/textfield_tags.dart'; import 'dart:convert'; import 'dart:io'; + +import 'dart:typed_data'; import '../classes/events.dart'; import 'ItemMenu.dart'; @@ -206,12 +208,41 @@ class _EditEventState extends State if (responseGet.statusCode == 200) { var events = jsonDecode(utf8.decode(responseGet.bodyBytes)); if (events.length > 0) { - showErrorDialog(context, "Evenement deja existant"); + if (events[0]["id"] != widget.events!.id) { + showErrorDialog(context, "Evenement deja existant"); + } return; } } + if (widget.imgPath.isNotEmpty) { + final params = { + 'expiration': '15552000', + 'key': dotenv.env["IMGBB_API_KEY"], + }; + print("Post Img"); + final urlPost = Uri.parse('https://api.imgbb.com/1/upload') + .replace(queryParameters: params); + File image = File(widget.imgPath); + Uint8List _bytes = await image.readAsBytes(); + String _base64String = base64.encode(_bytes); + + final req = http.MultipartRequest('POST', urlPost) + ..fields['image'] = _base64String; + + final stream = await req.send(); + final res = await http.Response.fromStream(stream); + + final status = res.statusCode; + print("code status imgbb ${status}"); + if (status != 200) { + showErrorDialog(context, "Image non posté"); + return; + } + var body = json.decode(utf8.decode(res.bodyBytes)); + imgUrl = body["data"]["url"]; + } var urlPut = Uri.parse("${globals.api}/events/${widget.events!.id}"); var responsePut = await http.put(urlPut,