You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

308 lines
12KB

  1. import 'dart:io';
  2. import 'package:cached_network_image/cached_network_image.dart';
  3. import 'package:farm_tpf/custom_model/Media.dart';
  4. import 'package:farm_tpf/presentation/custom_widgets/camera_helper.dart';
  5. import 'package:farm_tpf/presentation/custom_widgets/widget_show_video.dart';
  6. import 'package:farm_tpf/presentation/custom_widgets/widget_utils.dart';
  7. import 'package:farm_tpf/presentation/screens/actions/util_action.dart';
  8. import 'package:farm_tpf/utils/const_color.dart';
  9. import 'package:farm_tpf/utils/const_common.dart';
  10. import 'package:farm_tpf/utils/const_string.dart';
  11. import 'package:file_picker/file_picker.dart';
  12. import 'package:flutter/cupertino.dart';
  13. import 'package:flutter/material.dart';
  14. import 'package:flutter_bloc/flutter_bloc.dart';
  15. import 'package:get/get.dart';
  16. import 'bloc/media_helper_bloc.dart';
  17. import 'hoz_list_view.dart';
  18. class WidgetMediaPicker extends StatefulWidget {
  19. final List<Media> currentItems;
  20. final Function(List<String> addNewFilePaths, List<String> deleteFilePaths)
  21. onChangeFiles;
  22. WidgetMediaPicker({this.currentItems, @required this.onChangeFiles});
  23. @override
  24. _WidgetMediaPickerState createState() => _WidgetMediaPickerState();
  25. }
  26. class _WidgetMediaPickerState extends State<WidgetMediaPicker> {
  27. List<Media> currentItems = [];
  28. List<String> addNewFilePaths = new List<String>();
  29. List<String> deleteFilePaths = new List<String>();
  30. @override
  31. void initState() {
  32. super.initState();
  33. }
  34. @override
  35. Widget build(BuildContext context) {
  36. return BlocProvider<MediaHelperBloc>(
  37. create: (BuildContext contextA) =>
  38. MediaHelperBloc()..add(ChangeListMedia(items: currentItems)),
  39. child: BlocBuilder<MediaHelperBloc, MediaHelperState>(
  40. builder: (contextB, state) {
  41. if (state is MediaHelperFailure) {
  42. return Container();
  43. } else if (state is MediaHelperSuccess) {
  44. currentItems = widget.currentItems ?? [];
  45. return Container(
  46. padding: EdgeInsets.only(top: 8, bottom: 8),
  47. child: Column(
  48. children: <Widget>[
  49. SizedBox(
  50. width: double.infinity,
  51. height: 44,
  52. child: FlatButton(
  53. onPressed: () {
  54. showDialog(
  55. context: context,
  56. barrierDismissible: true,
  57. builder: (context) => Opacity(
  58. child: multipleChoice(contextB),
  59. opacity: 1,
  60. ));
  61. },
  62. color: COLOR_CONST.DEFAULT,
  63. shape: RoundedRectangleBorder(
  64. borderRadius: new BorderRadius.circular(7.0),
  65. ),
  66. child: Center(
  67. child: Row(
  68. mainAxisAlignment: MainAxisAlignment.center,
  69. children: <Widget>[
  70. Icon(Icons.image, color: Colors.white),
  71. SizedBox(
  72. width: 8.0,
  73. ),
  74. Text(
  75. button_add_media,
  76. style: TextStyle(
  77. fontWeight: FontWeight.bold,
  78. color: COLOR_CONST.WHITE),
  79. )
  80. ],
  81. ),
  82. )),
  83. ),
  84. SizedBox(
  85. height: 8.0,
  86. ),
  87. Container(
  88. child: _buildListPoster(),
  89. ),
  90. ],
  91. ));
  92. }
  93. return Container();
  94. }));
  95. }
  96. Widget multipleChoice(BuildContext context) {
  97. return CupertinoAlertDialog(
  98. title: Text(label_title_select_media),
  99. actions: <Widget>[
  100. CupertinoDialogAction(
  101. child: const Text(label_take_photo_or_video),
  102. onPressed: () {
  103. Navigator.pop(context, 'Discard');
  104. Navigator.of(context)
  105. .push(MaterialPageRoute(builder: (context) => CameraHelper()))
  106. .then((value) {
  107. if (value != null) {
  108. print("ok");
  109. print(value);
  110. String filePath = value[0];
  111. File f = File(filePath);
  112. f.length().then((lengthFileInBytes) {
  113. if (lengthFileInBytes > ConstCommon.kFileSize) {
  114. Utils.showSnackBarWarning(message: label_file_to_large);
  115. } else {
  116. bool isVideo = value[1];
  117. Media newMedia = Media()
  118. ..isVideo = isVideo
  119. ..isServerFile = false
  120. ..pathFile = filePath;
  121. currentItems.add(newMedia);
  122. addNewFilePaths.add(filePath);
  123. BlocProvider.of<MediaHelperBloc>(context)
  124. ..add(ChangeListMedia(items: currentItems));
  125. widget.onChangeFiles(addNewFilePaths, deleteFilePaths);
  126. }
  127. });
  128. }
  129. });
  130. }),
  131. CupertinoDialogAction(
  132. child: const Text(label_select_image_from_library),
  133. onPressed: () async {
  134. Navigator.pop(context, 'Discard');
  135. FilePickerResult result = await FilePicker.platform
  136. .pickFiles(type: FileType.image, allowMultiple: true);
  137. if (result != null) {
  138. var listFuture = List<Future<File>>();
  139. result.files.forEach((element) {
  140. listFuture.add(UtilAction.compressImage(File(element.path)));
  141. });
  142. Future.wait(listFuture).then((values) {
  143. bool isExistedFileTooLarge = false;
  144. values.forEach((compressFile) {
  145. if (compressFile.lengthSync() > ConstCommon.kFileSize) {
  146. isExistedFileTooLarge = true;
  147. } else {
  148. Media newMedia = Media()
  149. ..isVideo = false
  150. ..isServerFile = false
  151. ..pathFile = compressFile.path;
  152. currentItems.add(newMedia);
  153. addNewFilePaths.add(compressFile.path);
  154. }
  155. });
  156. if (isExistedFileTooLarge) {
  157. Utils.showSnackBarWarning(
  158. message: "Tập tin có kích thước lớn đã được loại bỏ.");
  159. }
  160. BlocProvider.of<MediaHelperBloc>(context)
  161. ..add(ChangeListMedia(items: currentItems));
  162. widget.onChangeFiles(addNewFilePaths, deleteFilePaths);
  163. });
  164. }
  165. }),
  166. CupertinoDialogAction(
  167. child: const Text(label_select_video_from_library),
  168. onPressed: () async {
  169. Navigator.pop(context, 'Discard');
  170. FilePickerResult result = await FilePicker.platform
  171. .pickFiles(type: FileType.video, allowMultiple: true);
  172. if (result != null) {
  173. bool isExistedFileTooLarge = false;
  174. result.files?.forEach((videoFile) {
  175. if (videoFile.size * 1000 > ConstCommon.kFileSize) {
  176. isExistedFileTooLarge = true;
  177. } else {
  178. Media newMedia = Media()
  179. ..isVideo = true
  180. ..isServerFile = false
  181. ..pathFile = videoFile.path;
  182. currentItems.add(newMedia);
  183. addNewFilePaths.add(videoFile.path);
  184. }
  185. });
  186. if (isExistedFileTooLarge) {
  187. Utils.showSnackBarWarning(
  188. message: "Tập tin có kích thước lớn đã được loại bỏ.");
  189. }
  190. BlocProvider.of<MediaHelperBloc>(context)
  191. ..add(ChangeListMedia(items: currentItems));
  192. widget.onChangeFiles(addNewFilePaths, deleteFilePaths);
  193. }
  194. }),
  195. CupertinoDialogAction(
  196. child: const Text(label_cancel),
  197. textStyle: TextStyle(fontWeight: FontWeight.bold),
  198. isDefaultAction: true,
  199. onPressed: () {
  200. Navigator.pop(context, 'Cancel');
  201. }),
  202. ],
  203. );
  204. }
  205. _buildListPoster() {
  206. return BlocBuilder<MediaHelperBloc, MediaHelperState>(
  207. builder: (context, state) {
  208. if (state is MediaHelperSuccess) {
  209. return GridView.count(
  210. physics: NeverScrollableScrollPhysics(),
  211. shrinkWrap: true,
  212. crossAxisCount: 4,
  213. children: currentItems.map(
  214. (item) {
  215. return _WidgetItemMedia(
  216. item: item,
  217. deleteImage: (item) {
  218. if (item.isServerFile) {
  219. var url = item.pathFile
  220. .replaceAll(ConstCommon.baseImageUrl, '');
  221. deleteFilePaths.add(url);
  222. }
  223. currentItems.remove(item);
  224. widget.onChangeFiles(addNewFilePaths, deleteFilePaths);
  225. BlocProvider.of<MediaHelperBloc>(context)
  226. .add(ChangeListMedia(items: currentItems));
  227. });
  228. },
  229. ).toList());
  230. }
  231. return Container();
  232. });
  233. }
  234. }
  235. class _WidgetItemMedia extends StatelessWidget {
  236. ItemMediaCallback deleteImage;
  237. final Media item;
  238. _WidgetItemMedia({@required this.item, @required this.deleteImage});
  239. BuildContext _context;
  240. // screenSize/rowGridview - iconSize - (rowGridview-1)*marginContainer
  241. // Get.width/4 - 24 - 3*4
  242. double positionIconDelete = -(Get.width / 4 - 36);
  243. @override
  244. Widget build(BuildContext context) {
  245. _context = context;
  246. return GestureDetector(
  247. onTap: () {
  248. print("Show preview image or video");
  249. },
  250. child: Stack(
  251. alignment: Alignment.topRight,
  252. overflow: Overflow.visible,
  253. children: <Widget>[
  254. Positioned.fill(
  255. child: item.isVideo
  256. ? VideoWidget(
  257. pathFile: item.pathFile,
  258. isServerFile: item.isServerFile,
  259. play: false,
  260. )
  261. : Container(
  262. margin: EdgeInsets.all(4.0),
  263. decoration: BoxDecoration(
  264. color: Colors.white,
  265. border: Border.all(color: Colors.grey),
  266. borderRadius:
  267. BorderRadius.all(Radius.circular(8.0))),
  268. child: item.isServerFile
  269. ? CachedNetworkImage(
  270. placeholder: (context, url) =>
  271. Icon(Icons.crop_original),
  272. imageUrl: item.pathFile)
  273. : Image.file(File(item.pathFile)),
  274. )),
  275. Positioned.fill(
  276. top: positionIconDelete,
  277. right: positionIconDelete,
  278. child: IconButton(
  279. icon: Icon(
  280. Icons.cancel,
  281. color: Colors.redAccent,
  282. size: 24,
  283. ),
  284. onPressed: () {
  285. print("On tap delete media");
  286. deleteImage(item);
  287. }),
  288. )
  289. ],
  290. ));
  291. }
  292. }
  293. typedef ItemMediaCallback = void Function(Media item);