| In most cases you can leave this as-is, but you if you want to provide | In most cases you can leave this as-is, but you if you want to provide | ||||
| additional functionality it is fine to subclass or reimplement | additional functionality it is fine to subclass or reimplement | ||||
| FlutterApplication and put your custom class here. --> | FlutterApplication and put your custom class here. --> | ||||
| <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> | |||||
| <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> | |||||
| <uses-permission android:name="android.permission.INTERNET"/> | <uses-permission android:name="android.permission.INTERNET"/> | ||||
| <uses-permission android:name="android.permission.CAMERA" /> | <uses-permission android:name="android.permission.CAMERA" /> | ||||
| <application | <application |
| 3c0c9b0c45d3aa2cb4c28b2c17dc1064 | |||||
| 0d1f90510e22958a585802bb59f9c570 |
| - shared_preferences (0.0.1): | - shared_preferences (0.0.1): | ||||
| - Flutter | - Flutter | ||||
| - SwiftProtobuf (1.12.0) | - SwiftProtobuf (1.12.0) | ||||
| - thumbnails (0.0.1): | |||||
| - Flutter | |||||
| - video_player (0.0.1): | - video_player (0.0.1): | ||||
| - Flutter | - Flutter | ||||
| - package_info (from `.symlinks/plugins/package_info/ios`) | - package_info (from `.symlinks/plugins/package_info/ios`) | ||||
| - path_provider (from `.symlinks/plugins/path_provider/ios`) | - path_provider (from `.symlinks/plugins/path_provider/ios`) | ||||
| - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) | - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) | ||||
| - thumbnails (from `.symlinks/plugins/thumbnails/ios`) | |||||
| - video_player (from `.symlinks/plugins/video_player/ios`) | - video_player (from `.symlinks/plugins/video_player/ios`) | ||||
| SPEC REPOS: | SPEC REPOS: | ||||
| :path: ".symlinks/plugins/path_provider/ios" | :path: ".symlinks/plugins/path_provider/ios" | ||||
| shared_preferences: | shared_preferences: | ||||
| :path: ".symlinks/plugins/shared_preferences/ios" | :path: ".symlinks/plugins/shared_preferences/ios" | ||||
| thumbnails: | |||||
| :path: ".symlinks/plugins/thumbnails/ios" | |||||
| video_player: | video_player: | ||||
| :path: ".symlinks/plugins/video_player/ios" | :path: ".symlinks/plugins/video_player/ios" | ||||
| SDWebImageFLPlugin: 6c2295fb1242d44467c6c87dc5db6b0a13228fd8 | SDWebImageFLPlugin: 6c2295fb1242d44467c6c87dc5db6b0a13228fd8 | ||||
| shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d | shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d | ||||
| SwiftProtobuf: 4ef85479c18ca85b5482b343df9c319c62bda699 | SwiftProtobuf: 4ef85479c18ca85b5482b343df9c319c62bda699 | ||||
| thumbnails: bb4f4e9bb4b51c8ae4e6ad9a2fa81373f9b634ad | |||||
| video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e | video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e | ||||
| PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c | PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c |
| }); | }); | ||||
| if (filePath != null) { | if (filePath != null) { | ||||
| print('Picture saved to $filePath'); | print('Picture saved to $filePath'); | ||||
| Get.back(result: filePath); | |||||
| Get.back(result: [filePath, false]); | |||||
| } | } | ||||
| } | } | ||||
| }); | }); | ||||
| if (mounted) setState(() {}); | if (mounted) setState(() {}); | ||||
| { | { | ||||
| print('Video recorded to: $videoPath'); | print('Video recorded to: $videoPath'); | ||||
| _getImage(videoPath); | |||||
| Get.back(result: [videoPath, true]); | |||||
| } | } | ||||
| }); | }); | ||||
| } | } | ||||
| _getImage(videoPathUrl) async { | |||||
| var appDocDir = await getApplicationDocumentsDirectory(); | |||||
| final folderPath = appDocDir.path; | |||||
| String thumb = await Thumbnails.getThumbnail( | |||||
| thumbnailFolder: folderPath, | |||||
| videoFile: videoPathUrl, | |||||
| imageType: | |||||
| ThumbFormat.PNG, //this image will store in created folderpath | |||||
| quality: 30); | |||||
| print("--thumb--" + thumb); | |||||
| Get.back(result: thumb); | |||||
| } | |||||
| void onPauseButtonPressed() { | void onPauseButtonPressed() { | ||||
| pauseVideoRecording().then((_) { | pauseVideoRecording().then((_) { | ||||
| if (mounted) setState(() {}); | if (mounted) setState(() {}); |
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| return SingleChildScrollView( | return SingleChildScrollView( | ||||
| reverse: true, | |||||
| scrollDirection: Axis.horizontal, | scrollDirection: Axis.horizontal, | ||||
| physics: BouncingScrollPhysics(), | physics: BouncingScrollPhysics(), | ||||
| child: Row( | child: Row( |
| import 'package:farm_tpf/custom_model/Media.dart'; | import 'package:farm_tpf/custom_model/Media.dart'; | ||||
| import 'package:farm_tpf/presentation/custom_widgets/camera_helper.dart'; | import 'package:farm_tpf/presentation/custom_widgets/camera_helper.dart'; | ||||
| import 'package:farm_tpf/presentation/custom_widgets/shimmer_image.dart'; | |||||
| import 'package:farm_tpf/presentation/custom_widgets/widget_show_video.dart'; | |||||
| import 'package:farm_tpf/utils/const_color.dart'; | import 'package:farm_tpf/utils/const_color.dart'; | ||||
| import 'package:farm_tpf/utils/const_common.dart'; | |||||
| import 'package:farm_tpf/utils/const_string.dart'; | import 'package:farm_tpf/utils/const_string.dart'; | ||||
| import 'package:file_picker/file_picker.dart'; | import 'package:file_picker/file_picker.dart'; | ||||
| import 'package:flutter/cupertino.dart'; | import 'package:flutter/cupertino.dart'; | ||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||
| import 'package:get/route_manager.dart'; | |||||
| import 'package:path_provider/path_provider.dart'; | |||||
| import 'package:thumbnails/thumbnails.dart'; | |||||
| import 'package:video_player/video_player.dart'; | |||||
| import 'package:get/get.dart'; | |||||
| import 'bloc/media_helper_bloc.dart'; | import 'bloc/media_helper_bloc.dart'; | ||||
| import 'hoz_list_view.dart'; | import 'hoz_list_view.dart'; | ||||
| )), | )), | ||||
| ), | ), | ||||
| SizedBox( | SizedBox( | ||||
| height: 4.0, | |||||
| height: 8.0, | |||||
| ), | ), | ||||
| Container( | Container( | ||||
| height: 150, | height: 150, | ||||
| if (value != null) { | if (value != null) { | ||||
| print("ok"); | print("ok"); | ||||
| print(value); | print(value); | ||||
| String filePath = value; | |||||
| Media newMedia = Media() | |||||
| ..isVideo = false | |||||
| ..isServerFile = false | |||||
| ..pathFile = filePath; | |||||
| currentItems.add(newMedia); | |||||
| files.add(filePath); | |||||
| BlocProvider.of<MediaHelperBloc>(context) | |||||
| ..add(ChangeListMedia(items: currentItems)); | |||||
| widget.onChangeFiles(files); | |||||
| String filePath = value[0]; | |||||
| File f = File(filePath); | |||||
| f.length().then((lengthFileInBytes) { | |||||
| if (lengthFileInBytes > ConstCommon.kFileSize) { | |||||
| Get.snackbar(label_file_to_large, | |||||
| "Kích thước: $lengthFileInBytes bytes", | |||||
| snackPosition: SnackPosition.BOTTOM); | |||||
| } else { | |||||
| bool isVideo = value[1]; | |||||
| Media newMedia = Media() | |||||
| ..isVideo = isVideo | |||||
| ..isServerFile = false | |||||
| ..pathFile = filePath; | |||||
| currentItems.add(newMedia); | |||||
| files.add(filePath); | |||||
| BlocProvider.of<MediaHelperBloc>(context) | |||||
| ..add(ChangeListMedia(items: currentItems)); | |||||
| widget.onChangeFiles(files); | |||||
| } | |||||
| print("Kích thước: $lengthFileInBytes bytes"); | |||||
| }); | |||||
| } | } | ||||
| }); | }); | ||||
| }), | }), | ||||
| if (result != null) { | if (result != null) { | ||||
| String filePath = result.files.single.path; | String filePath = result.files.single.path; | ||||
| Media newMedia = Media() | |||||
| ..isVideo = false | |||||
| ..isServerFile = false | |||||
| ..pathFile = filePath; | |||||
| currentItems.add(newMedia); | |||||
| files.add(filePath); | |||||
| BlocProvider.of<MediaHelperBloc>(context) | |||||
| ..add(ChangeListMedia(items: currentItems)); | |||||
| widget.onChangeFiles(files); | |||||
| var lengthFileInBytes = result.files.single.size * 1000; | |||||
| if (lengthFileInBytes > ConstCommon.kFileSize) { | |||||
| Get.snackbar(label_file_to_large, | |||||
| "Kích thước: $lengthFileInBytes bytes", | |||||
| snackPosition: SnackPosition.BOTTOM); | |||||
| } else { | |||||
| Media newMedia = Media() | |||||
| ..isVideo = false | |||||
| ..isServerFile = false | |||||
| ..pathFile = filePath; | |||||
| currentItems.add(newMedia); | |||||
| files.add(filePath); | |||||
| BlocProvider.of<MediaHelperBloc>(context) | |||||
| ..add(ChangeListMedia(items: currentItems)); | |||||
| widget.onChangeFiles(files); | |||||
| } | |||||
| print("file size: $lengthFileInBytes"); | |||||
| } | } | ||||
| }), | }), | ||||
| CupertinoDialogAction( | CupertinoDialogAction( | ||||
| await FilePicker.platform.pickFiles(type: FileType.video); | await FilePicker.platform.pickFiles(type: FileType.video); | ||||
| if (result != null) { | if (result != null) { | ||||
| //Get thumb video | |||||
| var appDocDir = await getApplicationDocumentsDirectory(); | |||||
| final folderPath = appDocDir.path; | |||||
| String filePath = await Thumbnails.getThumbnail( | |||||
| thumbnailFolder: folderPath, | |||||
| videoFile: result.files.single.path, | |||||
| imageType: ThumbFormat | |||||
| .PNG, //this image will store in created folderpath | |||||
| quality: 30); | |||||
| Media newMedia = Media() | |||||
| ..isVideo = false | |||||
| ..isServerFile = false | |||||
| ..pathFile = filePath; | |||||
| currentItems.add(newMedia); | |||||
| files.add(filePath); | |||||
| BlocProvider.of<MediaHelperBloc>(context) | |||||
| ..add(ChangeListMedia(items: currentItems)); | |||||
| widget.onChangeFiles(files); | |||||
| String filePath = result.files.single.path; | |||||
| var lengthFileInBytes = result.files.single.size * 1000; | |||||
| if (lengthFileInBytes > ConstCommon.kFileSize) { | |||||
| Get.snackbar(label_file_to_large, | |||||
| "Kích thước: $lengthFileInBytes bytes", | |||||
| snackPosition: SnackPosition.BOTTOM); | |||||
| } else { | |||||
| Media newMedia = Media() | |||||
| ..isVideo = true | |||||
| ..isServerFile = false | |||||
| ..pathFile = filePath; | |||||
| currentItems.add(newMedia); | |||||
| files.add(filePath); | |||||
| BlocProvider.of<MediaHelperBloc>(context) | |||||
| ..add(ChangeListMedia(items: currentItems)); | |||||
| widget.onChangeFiles(files); | |||||
| } | |||||
| print("file size: $lengthFileInBytes"); | |||||
| } | } | ||||
| }), | }), | ||||
| CupertinoDialogAction( | CupertinoDialogAction( | ||||
| }); | }); | ||||
| }, | }, | ||||
| separatorBuilder: (context, index) { | separatorBuilder: (context, index) { | ||||
| return SizedBox(width: 14); | |||||
| return SizedBox(width: 4); | |||||
| }, | }, | ||||
| list: state.items, | list: state.items, | ||||
| ); | ); | ||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| _context = context; | _context = context; | ||||
| VideoPlayerController _controller = | |||||
| VideoPlayerController.file(File(item.pathFile)); | |||||
| _controller.play(); | |||||
| return GestureDetector( | return GestureDetector( | ||||
| onTap: () { | onTap: () { | ||||
| print("Show preview image or video"); | print("Show preview image or video"); | ||||
| overflow: Overflow.visible, | overflow: Overflow.visible, | ||||
| children: <Widget>[ | children: <Widget>[ | ||||
| Positioned( | Positioned( | ||||
| child: ClipRRect( | |||||
| borderRadius: BorderRadius.circular(8), | |||||
| child: Image.file(File(item.pathFile), width: 100, height: 100), | |||||
| )), | |||||
| child: item.isVideo | |||||
| ? VideoWidget( | |||||
| pathFile: item.pathFile, | |||||
| play: false, | |||||
| ) | |||||
| : Container( | |||||
| width: 100, | |||||
| height: 100, | |||||
| decoration: BoxDecoration( | |||||
| color: Colors.white, | |||||
| border: Border.all(color: Colors.grey), | |||||
| borderRadius: | |||||
| BorderRadius.all(Radius.circular(8.0))), | |||||
| child: Image.file(File(item.pathFile), | |||||
| width: 100, height: 100), | |||||
| )), | |||||
| Positioned( | Positioned( | ||||
| top: -5, | |||||
| right: -5, | |||||
| top: -14, | |||||
| right: -14, | |||||
| child: IconButton( | child: IconButton( | ||||
| icon: Icon( | icon: Icon( | ||||
| Icons.cancel, | Icons.cancel, | ||||
| color: Colors.redAccent, | color: Colors.redAccent, | ||||
| size: 24, | |||||
| ), | ), | ||||
| onPressed: () { | onPressed: () { | ||||
| print("On tap delete media"); | print("On tap delete media"); |
| import 'dart:async'; | |||||
| import 'dart:io'; | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:video_player/video_player.dart'; | |||||
| class VideoWidget extends StatefulWidget { | |||||
| final bool play; | |||||
| final String pathFile; | |||||
| const VideoWidget({Key key, @required this.pathFile, @required this.play}) | |||||
| : super(key: key); | |||||
| @override | |||||
| _VideoWidgetState createState() => _VideoWidgetState(); | |||||
| } | |||||
| class _VideoWidgetState extends State<VideoWidget> { | |||||
| VideoPlayerController videoPlayerController; | |||||
| Future<void> _initializeVideoPlayerFuture; | |||||
| @override | |||||
| void initState() { | |||||
| super.initState(); | |||||
| videoPlayerController = VideoPlayerController.file(File(widget.pathFile)); | |||||
| _initializeVideoPlayerFuture = videoPlayerController.initialize().then((_) { | |||||
| // Ensure the first frame is shown after the video is initialized, even before the play button has been pressed. | |||||
| videoPlayerController.play(); | |||||
| videoPlayerController.setVolume(0.0); | |||||
| Timer.periodic(Duration(seconds: 1), (_) { | |||||
| videoPlayerController.pause(); | |||||
| }); | |||||
| setState(() {}); | |||||
| }); | |||||
| } | |||||
| @override | |||||
| void dispose() { | |||||
| videoPlayerController.dispose(); | |||||
| print("dispose video item"); | |||||
| super.dispose(); | |||||
| } | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return FutureBuilder( | |||||
| future: _initializeVideoPlayerFuture, | |||||
| builder: (context, snapshot) { | |||||
| if (snapshot.connectionState == ConnectionState.done) { | |||||
| return new Container( | |||||
| child: Container( | |||||
| key: new PageStorageKey(widget.pathFile), | |||||
| child: Container( | |||||
| padding: EdgeInsets.all(1), | |||||
| width: 100, | |||||
| height: 100, | |||||
| decoration: BoxDecoration( | |||||
| color: Colors.white, | |||||
| border: Border.all(color: Colors.red), | |||||
| borderRadius: BorderRadius.all(Radius.circular(8.0))), | |||||
| child: VideoPlayer(videoPlayerController), | |||||
| ), | |||||
| ), | |||||
| ); | |||||
| } else { | |||||
| return Center( | |||||
| child: CircularProgressIndicator(), | |||||
| ); | |||||
| } | |||||
| }, | |||||
| ); | |||||
| } | |||||
| } |
| class ConstCommon { | class ConstCommon { | ||||
| static int kExpiredTime = 12 * 60 * 60 * 1000; //24h | static int kExpiredTime = 12 * 60 * 60 * 1000; //24h | ||||
| static int kFileSize = 1000000; //1M = 1000.000 bytes | |||||
| static const String baseUrl = "http://tpf.aztrace.vn"; | static const String baseUrl = "http://tpf.aztrace.vn"; | ||||
| static const String supplyTypeSeed = "GIONG"; | static const String supplyTypeSeed = "GIONG"; |
| const String label_update_success = "Cập nhật thành công"; | const String label_update_success = "Cập nhật thành công"; | ||||
| const String label_add_success = "Thêm thành công"; | const String label_add_success = "Thêm thành công"; | ||||
| const String label_file_to_large = "Kích thước hình/video quá lớn"; | |||||
| //Exception | //Exception | ||||
| const String exception_common = "Đã có lỗi xảy ra"; | const String exception_common = "Đã có lỗi xảy ra"; | ||||
| const String exception_dio_cancle = "Truy vấn đến máy chủ bị huỷ"; | const String exception_dio_cancle = "Truy vấn đến máy chủ bị huỷ"; |