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.

298 lines
11KB

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