486 lines
18 KiB
Dart
486 lines
18 KiB
Dart
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<PhotoListPage> {
|
|
final _globalWidget = GlobalWidget();
|
|
|
|
// initialize photos files list
|
|
final List<File> photoFiles = [];
|
|
List<PhotoModel> _photoData = [];
|
|
|
|
Color _color1 = Color(0xff777777);
|
|
Color _color2 = Color(0xFF515151);
|
|
|
|
// _listKey is used for AnimatedList
|
|
var _listKey = GlobalKey<AnimatedListState>();
|
|
|
|
@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: <Widget>[
|
|
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<Color>(
|
|
(Set<MaterialState> 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<Photo> _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<void> 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());
|
|
}
|
|
}
|