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.

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