diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 2a71919..293cc2d 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -13,6 +13,8 @@ PODS: - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) + - image_gallery_saver (2.0.1): + - Flutter - image_picker_ios (0.0.1): - Flutter - ObjectBox (1.8.1) @@ -45,6 +47,7 @@ DEPENDENCIES: - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - Flutter (from `Flutter`) - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) + - image_gallery_saver (from `.symlinks/plugins/image_gallery_saver/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - objectbox_flutter_libs (from `.symlinks/plugins/objectbox_flutter_libs/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) @@ -73,6 +76,8 @@ EXTERNAL SOURCES: :path: Flutter fluttertoast: :path: ".symlinks/plugins/fluttertoast/ios" + image_gallery_saver: + :path: ".symlinks/plugins/image_gallery_saver/ios" image_picker_ios: :path: ".symlinks/plugins/image_picker_ios/ios" objectbox_flutter_libs: @@ -99,6 +104,7 @@ SPEC CHECKSUMS: Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 fluttertoast: eb263d302cc92e04176c053d2385237e9f43fad0 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + image_gallery_saver: 6eb11e5a866e9ac2c8a98c74ef99a04fc62878b2 image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5 ObjectBox: a7900d5335218cd437cbc080b7ccc38a5211f7b4 objectbox_flutter_libs: 61d74196d924fbc773da5f5757d1e9fab7b3cc78 diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index f34142f..52a54f7 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -53,5 +53,7 @@ Cette application a besoin de votre autorisation pour accéder à votre caméra afin que vous puissiez prendre des photos pour votre profil. NSMicrophoneUsageDescription Cette application a besoin de votre autorisation pour accéder à votre microphone afin que vous puissiez enregistrer des messages audio pour envoyer à vos amis. + NSPhotoLibraryAddUsageDescription + Description de l'autorisation pour accéder à la galerie diff --git a/lib/ui/visit/visit_photo_typology_detail.dart b/lib/ui/visit/visit_photo_typology_detail.dart index 70c307c..c16f0bc 100644 --- a/lib/ui/visit/visit_photo_typology_detail.dart +++ b/lib/ui/visit/visit_photo_typology_detail.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; +import 'package:image_gallery_saver/image_gallery_saver.dart'; import 'package:mobdr/config/constant.dart'; import 'package:mobdr/config/global_style.dart'; @@ -150,32 +151,23 @@ class _VisitPhotoTypologyDetailPageState ), child: Row( children: [ - Container( - child: GestureDetector( - onTap: () { - // TODO icone rond a coté copier galerie a supprimer on Tap c'est chatus() - }, - child: ClipOval( - child: Container( - color: SOFT_BLUE, - padding: EdgeInsets.all(9), - child: Icon(Icons.chat, - color: Colors.white, size: 16)), - ), - ), - ), SizedBox( - width: 10, + width: 8, ), Expanded( child: GestureDetector( - onTap: () { - setState(() { - //_shoppingCartCount++; - }); - Fluttertoast.showToast( - msg: 'Item has been added to Shopping Card', - toastLength: Toast.LENGTH_LONG); + onTap: () async { + bool isSaved = + await saveImageToGallery(widget.pp_image); + if (isSaved) { + Fluttertoast.showToast( + msg: 'Photo has been added to gallery', + toastLength: Toast.LENGTH_LONG); + } else { + Fluttertoast.showToast( + msg: 'Error while copying!', + toastLength: Toast.LENGTH_LONG); + } }, child: Container( alignment: Alignment.center, @@ -511,6 +503,12 @@ class _VisitPhotoTypologyDetailPageState }); } + Future saveImageToGallery(String imagePath) async { + final result = await ImageGallerySaver.saveFile(imagePath); + bool isSuccess = result["isSuccess"]; + return isSuccess; + } + /// Initializes data when the page loads. Future loadData(int photoId) async { String tags = ""; diff --git a/lib/ui/visit/visit_photo_typology_list.dart b/lib/ui/visit/visit_photo_typology_list.dart index 626065d..f5948b7 100644 --- a/lib/ui/visit/visit_photo_typology_list.dart +++ b/lib/ui/visit/visit_photo_typology_list.dart @@ -191,47 +191,47 @@ class _VisitPhotoTypologyListPageState VisitPhoto photoData, boxImageSize, animation, index) { return SizeTransition( sizeFactor: animation, - child: Container( - margin: EdgeInsets.fromLTRB(12, 6, 12, 0), - child: Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - elevation: 2, - color: Colors.white, - child: Container( - margin: EdgeInsets.all(8), - child: Column( - children: [ - GestureDetector( - onTap: () { - Route route = MaterialPageRoute( - builder: (context) => VisitPhotoTypologyDetailPage( - pp_imageId: _visitPhotoData[index].id, - pp_visitModel: widget.pp_visitModel, - pp_image: _visitPhotoData[index].getImage(), - pp_id_typologie: widget.pp_id_typologie, - )); + child: GestureDetector( + onTap: () { + Route route = MaterialPageRoute( + builder: (context) => VisitPhotoTypologyDetailPage( + pp_imageId: _visitPhotoData[index].id, + pp_visitModel: widget.pp_visitModel, + pp_image: _visitPhotoData[index].getImage(), + pp_id_typologie: widget.pp_id_typologie, + ), + ); - Navigator.push(context, route).then((result) { - if (result['change_typologie']) { - // the photo must be removed - setState(() { - _visitPhotoData.removeAt(index); - _listKey = GlobalKey(); - }); - } else { - setState(() { - _visitPhotoData[index].tags = result['tags']; - _visitPhotoData[index].photo_principale = - result['photo_principale']; - _visitPhotoData[index].photo_privee = - result['photo_privee']; - }); - } - }); - }, - child: Row( + Navigator.push(context, route).then((result) { + if (result['change_typologie']) { + // the photo must be removed + setState(() { + _visitPhotoData.removeAt(index); + _listKey = GlobalKey(); + }); + } else { + setState(() { + _visitPhotoData[index].tags = result['tags']; + _visitPhotoData[index].photo_principale = + result['photo_principale']; + _visitPhotoData[index].photo_privee = result['photo_privee']; + }); + } + }); + }, + child: Container( + margin: EdgeInsets.fromLTRB(12, 6, 12, 0), + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + elevation: 2, + color: Colors.white, + child: Container( + margin: EdgeInsets.all(8), + child: Column( + children: [ + Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -252,10 +252,11 @@ class _VisitPhotoTypologyListPageState child: Row( children: [ Text( - DateFormat('dd/MM/yyyy HH:mm:ss') - .format(photoData.date_photo), - style: TextStyle( - fontSize: 11, color: SOFT_GREY)) + DateFormat('dd/MM/yyyy HH:mm:ss') + .format(photoData.date_photo), + style: TextStyle( + fontSize: 11, color: SOFT_GREY), + ), ], ), ), @@ -269,148 +270,92 @@ class _VisitPhotoTypologyListPageState Container( margin: EdgeInsets.only(top: 5), child: Text( - '${photoData.tags.isNotEmpty ? (photoData.tags.length > 53 ? '${photoData.tags.substring(0, 50)}...' : photoData.tags) : "notag"}', - style: TextStyle( - fontSize: 13, - fontWeight: FontWeight.bold)), + '${photoData.tags.isNotEmpty ? (photoData.tags.length > 53 ? '${photoData.tags.substring(0, 50)}...' : photoData.tags) : "notag"}', + style: TextStyle( + fontSize: 13, fontWeight: FontWeight.bold), + ), ), Container(height: 8), ], ), - ) + ), ], ), - ), - Container( - margin: EdgeInsets.only(top: 12), - child: Row( - children: [ - GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () { - showPopupDeletePhoto(index, boxImageSize); - }, - child: Container( - padding: EdgeInsets.fromLTRB(5, 0, 5, 0), - height: 30, - decoration: BoxDecoration( + Container( + margin: EdgeInsets.only(top: 12), + child: Row( + children: [ + GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + showPopupDeletePhoto(index, boxImageSize); + }, + child: Container( + padding: EdgeInsets.fromLTRB(5, 0, 5, 0), + height: 30, + decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), border: Border.all( - width: 1, color: Colors.grey[300]!)), - child: Icon(Icons.delete, color: _color1, size: 20), + width: 1, color: Colors.grey[300]!), + ), + child: Icon(Icons.delete, color: _color1, size: 20), + ), ), - ), - SizedBox( - width: 8, - ), - Expanded( - child: (1 == 0) // (productData.stock == 0) - ? TextButton( - style: ButtonStyle( - minimumSize: - MaterialStateProperty.all(Size(0, 30)), - backgroundColor: - MaterialStateProperty.resolveWith( - (Set states) => - Colors.grey[300]!, - ), - overlayColor: MaterialStateProperty.all( - Colors.transparent), - shape: MaterialStateProperty.all( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(5.0), - )), - ), - onPressed: null, - child: Text( - 'Out of Stock', - style: TextStyle( - color: Colors.grey[600], - fontWeight: FontWeight.bold, - fontSize: 13), - textAlign: TextAlign.center, - )) - : OutlinedButton( - onPressed: () { - Fluttertoast.showToast( - msg: - 'Item has been added to Shopping Cart'); - }, - style: ButtonStyle( - minimumSize: - MaterialStateProperty.all(Size(0, 30)), - overlayColor: MaterialStateProperty.all( - Colors.transparent), - shape: MaterialStateProperty.all( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(5.0), - )), - side: MaterialStateProperty.all( - BorderSide(color: SOFT_GREY, width: 1.0), - )), - child: Text( - 'Copier dans galerie', - style: TextStyle( - color: SOFT_GREY, - fontWeight: FontWeight.bold, - fontSize: 13), - textAlign: TextAlign.center, - )), - ), - SizedBox( - width: 8, - ), - GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () async { - await rotateAndReplaceImage( - File(_visitPhotoData[index].getImage()), 90); - setState(() { - _listKey = GlobalKey(); - }); - Fluttertoast.showToast( - msg: 'The image has been rotated'); - }, - child: Container( - padding: EdgeInsets.fromLTRB(5, 0, 5, 0), - height: 30, - decoration: BoxDecoration( + Spacer(), + GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () async { + await rotateAndReplaceImage( + File(_visitPhotoData[index].getImage()), 90); + setState(() { + _listKey = GlobalKey(); + }); + Fluttertoast.showToast( + msg: 'The image has been rotated'); + }, + child: Container( + padding: EdgeInsets.fromLTRB(5, 0, 5, 0), + height: 30, + decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), border: Border.all( - width: 1, color: Colors.grey[300]!)), - child: Icon(Icons.rotate_right_rounded, - color: _color1, size: 20), + width: 1, color: Colors.grey[300]!), + ), + child: Icon(Icons.rotate_right_rounded, + color: _color1, size: 20), + ), ), - ), - SizedBox( - width: 8, - ), - GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () async { - await rotateAndReplaceImage( - File(_visitPhotoData[index].getImage()), -90); - setState(() { - _listKey = GlobalKey(); - }); - Fluttertoast.showToast( - msg: 'The image has been rotated'); - }, - child: Container( - padding: EdgeInsets.fromLTRB(5, 0, 5, 0), - height: 30, - decoration: BoxDecoration( + SizedBox( + width: 8, + ), + GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () async { + await rotateAndReplaceImage( + File(_visitPhotoData[index].getImage()), -90); + setState(() { + _listKey = GlobalKey(); + }); + Fluttertoast.showToast( + msg: 'The image has been rotated'); + }, + child: Container( + padding: EdgeInsets.fromLTRB(5, 0, 5, 0), + height: 30, + decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), border: Border.all( - width: 1, color: Colors.grey[300]!)), - child: Icon(Icons.rotate_left_rounded, - color: _color1, size: 20), + width: 1, color: Colors.grey[300]!), + ), + child: Icon(Icons.rotate_left_rounded, + color: _color1, size: 20), + ), ), - ) - ], + ], + ), ), - ) - ], + ], + ), ), ), ), diff --git a/pubspec.lock b/pubspec.lock index 7208f01..9f255af 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -549,6 +549,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.15" + image_gallery_saver: + dependency: "direct main" + description: + name: image_gallery_saver + sha256: "009b7722cd8507fd72c7f2cb7cbc46d6e15ad0895469cfcc39a10f86e3556979" + url: "https://pub.dev" + source: hosted + version: "2.0.1" image_picker: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index ef9bda2..de9ef10 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -108,6 +108,9 @@ dependencies: # https://pub.dev/packages/logger logger: ^1.3.0 + # https://pub.dev/packages/image_gallery_saver + image_gallery_saver: ^2.0.1 + dev_dependencies: flutter_test: sdk: flutter