import 'dart:async'; import 'dart:io'; import 'package:mobdr/config/constant.dart'; import 'package:mobdr/main.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:mobdr/model/photo_model.dart'; import 'package:mobdr/ui/reusable/cache_image_network.dart'; import 'package:mobdr/ui/reusable/global_widget.dart'; import 'package:mobdr/ui/home/photo_camera.dart'; import 'package:mobdr/objectbox.dart'; import 'package:mobdr/db/box_photo.dart'; class PhotoListPage extends StatefulWidget { @override _PhotoListPageState createState() => _PhotoListPageState(); } class _PhotoListPageState extends State { final _globalWidget = GlobalWidget(); // initialize photos files list final List photoFiles = []; List _photoData = []; Color _color1 = Color(0xff777777); Color _color2 = Color(0xFF515151); // _listKey is used for AnimatedList var _listKey = GlobalKey(); @override void initState() { super.initState(); _loadData(); } @override void dispose() { super.dispose(); } void _loadData() { for (Photo myPhoto in objectbox.getPhotos2()) { _photoData.add(PhotoModel( id: myPhoto.id, id_visite: myPhoto.id_visite, id_photo_typologie: myPhoto.id_photo_typologie, image: myPhoto.image)); } } @override Widget build(BuildContext context) { final double boxImageSize = (MediaQuery.of(context).size.width / 4); return Scaffold( appBar: AppBar( iconTheme: IconThemeData( color: Colors.black, //change your color here ), systemOverlayStyle: SystemUiOverlayStyle.dark, elevation: 0, title: Text( 'Catégorie : A trier', style: TextStyle(fontSize: 18, color: Colors.black), ), backgroundColor: Colors.white, actions: [ GestureDetector( onTap: () { Fluttertoast.showToast( msg: 'Click message', toastLength: Toast.LENGTH_SHORT); }, child: Icon(Icons.email, color: _color1)), IconButton( icon: _globalWidget.customNotifIcon( count: 8, notifColor: _color1, notifSize: 24, labelSize: 14), //icon: _globalWidget.customNotifIcon2(8, _color1), onPressed: () { Fluttertoast.showToast( msg: 'Click notification', toastLength: Toast.LENGTH_SHORT); }), ], ), body: RefreshIndicator( onRefresh: refreshData, child: AnimatedList( key: _listKey, initialItemCount: _photoData.length, physics: AlwaysScrollableScrollPhysics(), itemBuilder: (context, index, animation) { return _buildPhotolistCard( _photoData[index], boxImageSize, animation, index); }, ), ), floatingActionButton: fabCart(context)); } Widget _buildPhotolistCard( PhotoModel 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: () { Fluttertoast.showToast( msg: 'Click ' + photoData.image, toastLength: Toast.LENGTH_SHORT); }, child: Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ ClipRRect( borderRadius: BorderRadius.all(Radius.circular(10)), child: Image.file( File(photoData.image), fit: BoxFit.cover, height: 100, width: 150, ), ), SizedBox( width: 10, ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( photoData.id_photo_typologie.toString(), style: TextStyle(fontSize: 13, color: _color2), maxLines: 3, overflow: TextOverflow.ellipsis, ), Container( margin: EdgeInsets.only(top: 5), child: Text((index + 1).toString(), style: TextStyle( fontSize: 13, fontWeight: FontWeight.bold)), ), Container( margin: EdgeInsets.only(top: 5), child: Row( children: [ Icon(Icons.location_on, color: SOFT_GREY, size: 12), Text( ' ' + photoData.id_photo_typologie .toString(), style: TextStyle( fontSize: 11, color: SOFT_GREY)) ], ), ), Container( margin: EdgeInsets.only(top: 5), child: Row( children: [ Text( '(' + photoData.id_photo_typologie .toString() + ')', style: TextStyle( fontSize: 11, color: SOFT_GREY)) ], ), ), Container( margin: EdgeInsets.only(top: 5), child: Text( photoData.id_photo_typologie.toString() + ' ' + 'Sale', style: TextStyle( fontSize: 11, color: SOFT_GREY)), ), ], ), ) ], ), ), Container( margin: EdgeInsets.only(top: 12), child: Row( children: [ GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { showPopupDeleteFavorite(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), ), ), 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_BLUE, width: 1.0), )), child: Text( 'Copier dans galerie', style: TextStyle( color: SOFT_BLUE, fontWeight: FontWeight.bold, fontSize: 13), textAlign: TextAlign.center, )), ), SizedBox( width: 8, ), GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { showPopupDeleteFavorite(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.rotate_right_rounded, color: _color1, size: 20), ), ), SizedBox( width: 8, ), GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { showPopupDeleteFavorite(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.rotate_left_rounded, color: _color1, size: 20), ), ) ], ), ) ], ), ), ), ), ); } Widget fabCart(context) { return FloatingActionButton( onPressed: () { Route route = MaterialPageRoute( builder: (context) => CameraPage(photoFiles: photoFiles)); Navigator.push(context, route).then((val) { /// if the user has validated photos if (val == true) { savePhotos(); } else { deletePhotos(); } }); }, child: Stack(children: [ Icon(Icons.add_a_photo, color: BLACK21, size: 42), Positioned( right: 0, bottom: 0, child: Container( padding: EdgeInsets.all(1), decoration: BoxDecoration( color: PRIMARY_COLOR, borderRadius: BorderRadius.circular(14), ), constraints: BoxConstraints( minWidth: 16, minHeight: 16, ), child: Center( child: Text( _photoData.length.toString(), style: TextStyle( color: Colors.white, fontSize: 8, ), textAlign: TextAlign.center, ), ), ), ) ]), backgroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(4.0))), ); } void savePhotos() { print("Save PHOTOS ----:" + photoFiles.length.toString()); if (photoFiles.length > 0) { final List _listPhotos = []; for (var photo in photoFiles) { _listPhotos .add(Photo(id_visite: 0, id_photo_typologie: 0, image: photo.path)); } objectbox.addPhotos(_listPhotos); /// refresh widget PhotoListPage refreshData(); } } void deletePhotos() { print("DELETE PHOTO ------------"); // delete files on local storage photoFiles.forEach((element) { //deleteFile(File(element.path)); //element.delete(); }); } void showPopupDeleteFavorite(index, boxImageSize) { // set up the buttons Widget cancelButton = TextButton( onPressed: () { Navigator.pop(context); }, child: Text('No', style: TextStyle(color: SOFT_BLUE))); Widget continueButton = TextButton( onPressed: () { int removeIndex = index; var removedItem = _photoData.removeAt(removeIndex); // This builder is just so that the animation has something // to work with before it disappears from view since the original // has already been deleted. AnimatedRemovedItemBuilder builder = (context, animation) { // A method to build the Card widget. return _buildPhotolistCard( removedItem, boxImageSize, animation, removeIndex); }; _listKey.currentState!.removeItem(removeIndex, builder); Navigator.pop(context); Fluttertoast.showToast( msg: 'Item has been deleted from your favorite', toastLength: Toast.LENGTH_SHORT); }, child: Text('Yes', style: TextStyle(color: SOFT_BLUE))); // set up the AlertDialog AlertDialog alert = AlertDialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), title: Text( 'Delete Favorite', style: TextStyle(fontSize: 18), ), content: Text('Are you sure to delete this item from your Favorite ?', style: TextStyle(fontSize: 13, color: _color1)), actions: [ cancelButton, continueButton, ], ); // show the dialog showDialog( context: context, builder: (BuildContext context) { return alert; }, ); } Future deleteFile(File file) async { try { if (await file.exists()) { await file.delete(); } } catch (e) { // Error in getting access to the file. // todo toast print(e.toString()); } } Future refreshData() async { /// clear all data /// TODO on pourrait simplement ajouter les nouvelles photos (bien mieux) _photoData.clear(); photoFiles.clear(); /// reload all photo data from database _loadData(); /// reinitialiez AnimatedList widget setState(() => _listKey = GlobalKey()); } }