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.

282 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: EdgeInsets.all(8),
  43. child: Column(
  44. crossAxisAlignment: CrossAxisAlignment.start,
  45. children: <Widget>[
  46. Text('Hình ảnh/ Video', style: TextStyle(color: Colors.black54, fontSize: 16)),
  47. 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. 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: Text(label_title_select_media),
  86. actions: <Widget>[
  87. CupertinoDialogAction(
  88. child: const Text('Chụp ảnh'),
  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. File 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. Media 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('Chọn ảnh'),
  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. bool isExistedFileTooLarge = false;
  127. values.forEach((compressFile) {
  128. if (compressFile.lengthSync() > ConstCommon.kFileSize) {
  129. isExistedFileTooLarge = true;
  130. } else {
  131. Media 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
  152. // .pickFiles(type: FileType.video, allowMultiple: true);
  153. // if (result != null) {
  154. // bool isExistedFileTooLarge = false;
  155. // result.files?.forEach((videoFile) {
  156. // if (videoFile.size * 1000 > ConstCommon.kFileSize) {
  157. // isExistedFileTooLarge = true;
  158. // } else {
  159. // Media newMedia = Media()
  160. // ..isVideo = true
  161. // ..isServerFile = false
  162. // ..pathFile = videoFile.path;
  163. // currentItems.add(newMedia);
  164. // addNewFilePaths.add(videoFile.path);
  165. // }
  166. // });
  167. // if (isExistedFileTooLarge) {
  168. // Utils.showSnackBarWarning(
  169. // message: "Tập tin có kích thước lớn đã được loại bỏ.");
  170. // }
  171. // BlocProvider.of<MediaHelperBloc>(context)
  172. // ..add(ChangeListMedia(items: currentItems));
  173. // widget.onChangeFiles(addNewFilePaths, deleteFilePaths);
  174. // }
  175. // }),
  176. CupertinoDialogAction(
  177. child: const Text(label_cancel),
  178. textStyle: TextStyle(fontWeight: FontWeight.bold),
  179. isDefaultAction: true,
  180. onPressed: () {
  181. Navigator.pop(context, 'Cancel');
  182. }),
  183. ],
  184. );
  185. }
  186. _buildListPoster() {
  187. return BlocBuilder<MediaHelperBloc, MediaHelperState>(builder: (context, state) {
  188. if (state is MediaHelperSuccess) {
  189. return WrapContentHozListView(
  190. list: currentItems,
  191. itemBuilder: (context, index) {
  192. var item = currentItems[index];
  193. return Container(
  194. width: 120,
  195. height: 120,
  196. child: _WidgetItemMedia(
  197. item: item,
  198. deleteImage: (item) {
  199. if (item.isServerFile) {
  200. var url = item.pathFile?.replaceAll(ConstCommon.baseImageUrl, '');
  201. deleteFilePaths.add(url ?? '');
  202. }
  203. addNewFilePaths.remove(item.pathFile);
  204. currentItems.remove(item);
  205. widget.onChangeFiles(addNewFilePaths, deleteFilePaths);
  206. BlocProvider.of<MediaHelperBloc>(context).add(ChangeListMedia(items: currentItems));
  207. }),
  208. );
  209. });
  210. }
  211. return Container();
  212. });
  213. }
  214. }
  215. class _WidgetItemMedia extends StatelessWidget {
  216. ItemMediaCallback deleteImage;
  217. final Media item;
  218. _WidgetItemMedia({required this.item, required this.deleteImage});
  219. @override
  220. Widget build(BuildContext context) {
  221. return GestureDetector(
  222. onTap: () {
  223. print("Show preview image or video");
  224. },
  225. child: Stack(
  226. alignment: Alignment.topRight,
  227. children: <Widget>[
  228. Positioned.fill(
  229. child: item.isVideo ?? false
  230. ? VideoWidget(
  231. pathFile: item.pathFile ?? '',
  232. isServerFile: item.isServerFile,
  233. play: false,
  234. )
  235. : Container(
  236. margin: EdgeInsets.all(4.0),
  237. decoration: BoxDecoration(
  238. color: Colors.white,
  239. border: Border.all(color: Colors.grey),
  240. borderRadius: BorderRadius.all(
  241. Radius.circular(8.0),
  242. ),
  243. ),
  244. child: item.isServerFile
  245. ? CachedNetworkImage(
  246. placeholder: (context, url) => Icon(Icons.crop_original),
  247. imageUrl: item.pathFile ?? '',
  248. )
  249. : Image.file(File(item.pathFile ?? '')),
  250. )),
  251. Positioned.fill(
  252. top: -(120.0 - 36),
  253. right: -(120.0 - 36),
  254. child: IconButton(
  255. icon: Icon(
  256. Icons.delete,
  257. color: Colors.redAccent,
  258. size: 24,
  259. ),
  260. onPressed: () {
  261. print("On tap delete media");
  262. deleteImage(item);
  263. }))
  264. ],
  265. ));
  266. }
  267. }
  268. typedef ItemMediaCallback = void Function(Media item);