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