import 'dart:io'; import 'package:dio/dio.dart'; import 'package:file_picker/file_picker.dart'; import 'package:file_preview/file_preview.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:path_provider/path_provider.dart'; import 'package:video_player/video_player.dart'; import 'package:video_thumbnail/video_thumbnail.dart'; import '../base/YSBase.dart'; import 'YSAlertView.dart'; import 'YSNetWork.dart'; import 'YSTools.dart'; String fileUrl = 'https://cdn.datangyun.cc/'; class YSFileView extends StatelessWidget { final List fileArray; const YSFileView({Key? key, required this.fileArray}) : super(key: key); @override Widget build(BuildContext context) { return LayoutBuilder(builder: (context,conSize){ return GridView.builder(gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 4, childAspectRatio: 54/35, crossAxisSpacing: hsp(15), mainAxisSpacing: hsp(15) ), itemBuilder: (context,index){ Map item = fileArray[index]; return item['type']==1?YSImageView( url: item['url'], ):YSVideoView( url: item['url'] ); },shrinkWrap: true,padding: const EdgeInsets.all(0),physics: const NeverScrollableScrollPhysics(),itemCount: fileArray.length,); }); } } class YSUploadFileView2 extends StatefulWidget { final List fileArray; const YSUploadFileView2({Key? key, required this.fileArray}) : super(key: key); @override YSUploadFileView2State createState() => YSUploadFileView2State(); } class YSUploadFileView2State extends State { @override void initState() { super.initState(); } @override Widget build(BuildContext context) { return LayoutBuilder(builder: (context,conSize){ return GridView.builder(gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 4, childAspectRatio: 54/35, crossAxisSpacing: hsp(15), mainAxisSpacing: hsp(15) ), itemBuilder: (context,index){ return GestureDetector( onTap: () async{ // LogUtil.d('obj'); // return; if(index==0){//&&widget.fileArray.isEmpty if(widget.fileArray.length==4){ ysFlutterToast('最多添加4个文件'); return; } FocusScope.of(context).unfocus(); bool isAgree = await permissionHandler('file'); if(isAgree==false)return; List allowedExtensions = ['jpg','jpeg','png','mp4']; bool isMp4 = widget.fileArray.any((element) => '${element['url']}'.contains('mp4')); if(isMp4){ allowedExtensions.remove('mp4'); } FilePickerResult? result = await FilePicker.platform.pickFiles( type: FileType.custom,//'excel', 'word', 'pdf', allowedExtensions: allowedExtensions, ); if(result!=null){ LogUtil.d(result.files); if(result.files.isNotEmpty){ Map fileMap = {}; for (var element in result.files) { // if(element.size/1000000>20){ // ysFlutterToast('文件不能超过20M'); // return; // } fileMap['path'] = element.path; fileMap['name'] = element.name; } if('${fileMap['path']}'.contains('mp4')){ widget.fileArray.insert(0, fileMap); }else{ widget.fileArray.add(fileMap); } setState(() {}); _postFileData(fileMap); } } } }, child: index==0?Container( color: const Color(0xFF8A93A0), alignment: Alignment.center, child: Icon(Icons.file_copy,size: hsp(10),color: Colors.white,), ):Container( child: widget.fileArray[index-1]['url']!=null?Stack( children: [ YSDocView(url: widget.fileArray[index-1]['url'],), Positioned(right: 0,top: 0,height: hsp(15),width: hsp(15),child: GestureDetector( onTap: (){ widget.fileArray.removeAt(index-1); setState(() {}); }, behavior: HitTestBehavior.opaque, child: Container( decoration: const BoxDecoration( color: Colors.black54, borderRadius: BorderRadius.only(bottomLeft: Radius.circular(50)) ), alignment: Alignment.topRight, padding: EdgeInsets.only(top: hsp(2),right: hsp(2)), child: Icon(Icons.close,size: hsp(8),color: Colors.white,), ), ),) ], ):widget.fileArray[index-1]['path']!=null?Stack( children: [ YSDocView(url: widget.fileArray[index-1]['path'],), ClipRRect( child: Container( alignment: Alignment.center, height: conSize.maxWidth/2, width: conSize.maxWidth/2, child: CircularProgressIndicator( value: widget.fileArray[index-1]['rota'], color: Colors.black54, valueColor: const AlwaysStoppedAnimation(Colors.transparent), strokeWidth: conSize.maxWidth/6, ), ), ), if(widget.fileArray[index-1]['isError']==true)Container( color: Colors.black54, child: Stack( children: [ GestureDetector( onTap: (){ Map item = widget.fileArray[index-1]; item.remove('isError'); _postFileData(item); }, behavior: HitTestBehavior.opaque, child: Container( alignment: Alignment.center, child: Text('上传失败\n重新上传',style: TextStyle(fontSize: zsp(8),color: const Color(0xFFACB5C5)),), ), ), Positioned(right: 0,top: 0,height: hsp(15),width: hsp(15),child: GestureDetector( onTap: (){ widget.fileArray.removeAt(index-1); setState(() {}); }, behavior: HitTestBehavior.opaque, child: Container( decoration: const BoxDecoration( color: Colors.white60, borderRadius: BorderRadius.only(bottomLeft: Radius.circular(50)) ), alignment: Alignment.topRight, padding: EdgeInsets.only(top: hsp(2),right: hsp(2)), child: Icon(Icons.close,size: hsp(8),color: Colors.black,), ), ),), ], ), ) ], ):Container(), ), ); },shrinkWrap: true,padding: const EdgeInsets.all(0),physics: const NeverScrollableScrollPhysics(),itemCount: widget.fileArray.length+1,); }); } _postFileData(Map fileMap) async{ FormData formData = FormData.fromMap(Map.from({})); formData.files.add( MapEntry('file', await MultipartFile.fromFile(fileMap['path'] ,filename: fileMap['name'])) ); if (!mounted) return; YSNetWork.ysRequestHttp2(context, type: RequestType.post, api: '/upload/${'${fileMap['path']}'.contains('mp4')==true?'video':'img'}',parameter: formData,imageSetter: (value){ fileMap['rota'] = value; setState(() {}); }, successSetter: (value) { if(value['msg']!=null){ fileMap['isError'] = true; }else{ Map data = value['data']??{}; fileMap['url'] = data['img']??data['video']??''; } setState(() {}); },isLoading: true); } } uploadFile(BuildContext context,ValueSetter valueSetter) async{ List allowedExtensions = ['jpg','jpeg','png']; FilePickerResult? result = await FilePicker.platform.pickFiles( type: FileType.custom,//'excel', 'word', 'pdf', allowedExtensions: allowedExtensions, ); if(result!=null){ LogUtil.d(result.files); if(result.files.isNotEmpty){ Map fileMap = {}; for (var element in result.files) { fileMap['path'] = element.path; fileMap['name'] = element.name; } FormData formData = FormData.fromMap(Map.from({})); formData.files.add( MapEntry('file', await MultipartFile.fromFile(fileMap['path'] ,filename: fileMap['name'])) ); // ignore: use_build_context_synchronously YSNetWork.ysRequestHttp2(context, type: RequestType.post, api: '/upload/${'${fileMap['path']}'.contains('mp4')==true?'video':'img'}',parameter: formData,imageSetter: (value){ fileMap['rota'] = value; }, successSetter: (value) { if(value['msg']!=null){ fileMap['isError'] = true; }else{ Map data = value['data']??{}; fileMap['url'] = data['img']??data['video']??''; valueSetter(fileMap); } }); } } } class YSUploadFileView extends StatefulWidget { final bool isInvoice; final List fileArray; const YSUploadFileView({Key? key, required this.fileArray,this.isInvoice = false}) : super(key: key); @override YSUploadFileViewState createState() => YSUploadFileViewState(); } class YSUploadFileViewState extends State { bool _isInvoice = false; @override void initState() { _isInvoice = widget.isInvoice; super.initState(); } @override Widget build(BuildContext context) { return LayoutBuilder(builder: (context,conSize){ return GridView.builder(gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 4, childAspectRatio: 54/35, crossAxisSpacing: hsp(15), mainAxisSpacing: hsp(15) ), itemBuilder: (context,index){ return GestureDetector( onTap: (){ FocusScope.of(context).unfocus(); if(index==0){ if(_isInvoice&&widget.fileArray.isNotEmpty)return; ysShowBottomAlertView(context, YSChooseFileView(valueSetter: (fileMap) async{ bool isInvoice = fileMap['invoice']??false; _isInvoice = isInvoice; int type = fileMap['type']??1; var value = fileMap['value']; if(value is List){ List valueArray = value; for (var element in valueArray) { Map fileMap = {'path':element.path,'name':element.name,'type':type}; widget.fileArray.add(fileMap); setState(() {}); _postFileData(fileMap); } }else{ Map fileMap = {'path':value.path,'name':value.name,'type':type}; widget.fileArray.add(fileMap); setState(() {}); _postFileData(fileMap); } },isPhoto: widget.isInvoice,),isBarr: true); } }, child: index==0?Container( color: const Color(0xFFF7F8FA), alignment: Alignment.center, child: Icon(Icons.camera_alt,size: hsp(20),color: const Color(0xFFDCDEE0),), ):Container( child: widget.fileArray[index-1]['url']!=null?Stack( children: [ widget.fileArray[index-1]['type']!=1?YSVideoView( url: widget.fileArray[index-1]['url'] ):YSImageView(url: widget.fileArray[index-1]['url'],), Positioned(right: 0,top: 0,height: hsp(30),width: hsp(30),child: GestureDetector( onTap: (){ widget.fileArray.removeAt(index-1); setState(() {}); }, behavior: HitTestBehavior.opaque, child: Container( decoration: const BoxDecoration( color: Colors.black54, borderRadius: BorderRadius.only(bottomLeft: Radius.circular(50)) ), alignment: Alignment.topRight, padding: EdgeInsets.only(top: hsp(2),right: hsp(2)), child: Icon(Icons.close,size: hsp(20),color: Colors.white,), ), ),) ], ):widget.fileArray[index-1]['path']!=null?Stack( children: [ '${widget.fileArray[index-1]['path']}'.contains('mp4')?YSVideoView( url: widget.fileArray[index-1]['path'] ):YSImageView(url: widget.fileArray[index-1]['path'],), Container( padding: EdgeInsets.all(hsp(25)), height: 100, width: 100, child: CircularProgressIndicator( value: widget.fileArray[index-1]['rota'], color: Colors.lightBlueAccent, backgroundColor: Colors.white, strokeWidth: 4, ), ) ], ):Container(), ), ); },shrinkWrap: true,padding: const EdgeInsets.all(0),physics: const NeverScrollableScrollPhysics(),itemCount: widget.fileArray.length+1,); }); } _postFileData(Map fileMap) async{ FormData formData = FormData.fromMap(Map.from({})); formData.files.add( MapEntry('file', await MultipartFile.fromFile(fileMap['path'] ,filename: fileMap['name'])) ); if (!mounted) return; YSNetWork.ysRequestHttp2(context, type: RequestType.post, api: 'file/upload',parameter: formData,imageSetter: (value){ fileMap['rota'] = value; setState(() {}); }, successSetter: (value) { List data = value['data']??[]; for (var element in data) { fileMap['url'] = element['filePath']; } setState(() {}); if(_isInvoice){ YSNetWork.ysRequestHttp(context, type: RequestType.post, api: 'energyConsumptionOil/appCheckInvoice', parameter: { 'check':fileMap['url'] }, successSetter: (dict){ Map info = dict['data']; CustomerValueNotification(info).dispatch(context); }); } LogUtil.d(fileMap); }); } } class YSDocView extends StatefulWidget { final String url; const YSDocView({Key? key, required this.url}) : super(key: key); @override YSDocViewState createState() => YSDocViewState(); } class YSDocViewState extends State { @override void initState() { super.initState(); } @override Widget build(BuildContext context) { return widget.url.contains('.png')||widget.url.contains('.jpg')||widget.url.contains('.jpeg')?YSImageView( url: widget.url ):widget.url.contains('.mp4')?YSVideoView( url: widget.url ):GestureDetector( onTap: (){ // return; Navigator.of(context).push( CupertinoPageRoute(builder: (context){ return YSDocDetailView(path: widget.url); }) ); }, child: Container( alignment: Alignment.center, child: Icon(Icons.insert_drive_file_sharp,color: Colors.orange,size: hsp(60),), ), ); } } class YSDocDetailView extends StatelessWidget { final String path; const YSDocDetailView({Key? key, required this.path}) : super(key: key); @override Widget build(BuildContext context) { return YSBase( ysTitle: '文件预览', ysColor: Colors.white, ysChild: SizedBox( height: ysHeight(context), width: ysWidth(context), child: FilePreviewWidget( width: ysHeight(context),//宽 height: ysWidth(context),//高 callBack: FilePreviewCallBack(onShow: () { LogUtil.d("文件打开成功"); }, onDownload: (progress) { LogUtil.d("文件下载进度$progress"); }, onFail: (code, msg) { LogUtil.d("文件打开失败 $code $msg"); }), path: path,//本地路径或者http链接 ), ), ); } } class YSImageView extends StatelessWidget { final String url; const YSImageView({Key? key, required this.url}) : super(key: key); @override Widget build(BuildContext context) { return GestureDetector( onTap: (){ Navigator.of(context).push( CupertinoPageRoute(builder: (context){ return YSPreviewImageView(url: url.contains('carbon')==true?'$fileUrl$url':url); }) ); }, child: url.contains('carbon')?Image.network( '$fileUrl$url', fit: BoxFit.cover, width: double.infinity, height: double.infinity, ):Image.file( File(url), fit: BoxFit.cover, width: double.infinity, height: double.infinity, ), ); } } class YSVideoView extends StatefulWidget { final String url; const YSVideoView({Key? key, required this.url}) : super(key: key); @override YSVideoViewState createState() => YSVideoViewState(); } class YSVideoViewState extends State { @override void initState() { super.initState(); _getImage(); } _getImage() async{ final uint8List = await VideoThumbnail.thumbnailData( video: widget.url, imageFormat: ImageFormat.JPEG, ); YSData().image = Image.memory(uint8List!,fit: BoxFit.fill,height: double.infinity,width: double.infinity,); } @override Widget build(BuildContext context) { return GestureDetector( onTap: (){ if(widget.url.contains('carbon')){ Navigator.of(context).push( CupertinoPageRoute(builder: (context){ return YSVideoHorizontal(url: '$fileUrl${widget.url}'); }) ); } }, behavior: HitTestBehavior.opaque, child: Center( child: Stack( alignment: Alignment.center, children: [ YSData().image, if(widget.url.contains('carbon'))Center( child: Icon(Icons.play_circle_fill,color: Colors.white,size: hsp(20),), ) ], ), ), ) ; } } class YSPreviewImageView extends StatelessWidget { final String url; const YSPreviewImageView({Key? key, required this.url}) : super(key: key); @override Widget build(BuildContext context) { return GestureDetector( onTap: (){ Navigator.pop(context); }, child: Container( height: ysHeight(context), width: ysHeight(context), color: Colors.black, child: url.contains('http')?Image.network( url, fit: BoxFit.cover, width: double.infinity, height: double.infinity, ):Image.file( File(url), fit: BoxFit.cover, width: double.infinity, height: double.infinity, ), ), ); } } class YSVideoHorizontal extends StatefulWidget { final String url; final String title; const YSVideoHorizontal({Key? key, required this.url, this.title = ''}) : super(key: key); @override YSVideoHorizontalState createState() => YSVideoHorizontalState(); } class YSVideoHorizontalState extends State { late StateSetter _playSet,_progressSet; String _startTime = '00:00:00'; String _endTime = '00:00:00'; late VideoPlayerController _controller; @override void initState() { // SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); // SystemChrome.setPreferredOrientations([ // DeviceOrientation.landscapeLeft, //全屏时旋转方向,左边 // ]); _getPlayer(); super.initState(); } _getPlayer() { // LogUtil.d(widget.url); //https://media.w3.org/2010/05/sintel/trailer.mp4 if(widget.url.contains('http')){ _controller = VideoPlayerController.network(widget.url)..initialize().then((_) { _controller.play(); setState(() {}); })..addListener(() { Duration duration = _controller.value.duration; Duration position = _controller.value.position; _endTime = '${'${duration.inHours}'.padLeft(2,'0')}:${'${duration.inMinutes}'.padLeft(2,'0')}:${'${duration.inSeconds}'.padLeft(2,'0')}'; _startTime = '${'${position.inHours}'.padLeft(2,'0')}:${'${position.inMinutes}'.padLeft(2,'0')}:${'${position.inSeconds}'.padLeft(2,'0')}'; if(mounted){ _progressSet(() {}); } }); }else{ _controller = VideoPlayerController.file(File(widget.url))..initialize().then((_) { _controller.play(); setState(() {}); })..addListener(() { Duration duration = _controller.value.duration; Duration position = _controller.value.position; _endTime = '${'${duration.inHours}'.padLeft(2,'0')}:${'${duration.inMinutes}'.padLeft(2,'0')}:${'${duration.inSeconds}'.padLeft(2,'0')}'; _startTime = '${'${position.inHours}'.padLeft(2,'0')}:${'${position.inMinutes}'.padLeft(2,'0')}:${'${position.inSeconds}'.padLeft(2,'0')}'; if(mounted){ _progressSet(() {}); } }); } } @override void dispose() { _controller.dispose(); // SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); // SystemChrome.setPreferredOrientations([ // DeviceOrientation.portraitUp, // ]); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, body: SizedBox( height: ysHeight(context), width: ysWidth(context), child: Stack( children: [ _controller.value.aspectRatio<1?Center( child: AspectRatio( aspectRatio: _controller.value.aspectRatio, child: VideoPlayer(_controller), ), ):VideoPlayer(_controller), _pauseView(controller: _controller), Container( width: ysWidth(context), height: hsp(30), margin: EdgeInsets.only(left: hsp(15),right: hsp(35),top: ysTOP(context)+hsp(10)), child: Row( children: [ GestureDetector( onTap: (){Navigator.pop(context);}, child: Icon(Icons.chevron_left,size: hsp(30),color: Colors.white,), ), SizedBox( width: ysWidth(context)-hsp(80), child: Text(widget.title,style: TextStyle(fontSize: zsp(16),color: Colors.white),), ) ], ), ), StatefulBuilder( builder: (context,progressSet){ _progressSet = progressSet; return Container( margin: EdgeInsets.only(top: ysHeight(context)-hsp(50),left: hsp(15),right: hsp(15)), child: Row( children: [ SizedBox( width: hsp(100), child: Row( children: [ GestureDetector( onTap: (){ _playSet(() { _controller.value.isPlaying?_controller.pause() : _controller.play(); }); progressSet(() {}); }, child: Icon(_controller.value.isPlaying?Icons.pause:Icons.play_arrow,size: hsp(25),color: Colors.white,), ), Container( alignment: Alignment.center, width: hsp(75), child: Text(_startTime,style: TextStyle(fontSize: zsp(12),color: Colors.white),), ) ], ), ), SizedBox( width: ysWidth(context)-hsp(230), height:6.5, child: VideoProgressIndicator( _controller, allowScrubbing: true, colors: const VideoProgressColors(playedColor: Colors.white,backgroundColor: Colors.black), ) ), SizedBox( width: hsp(100), child: Row( children: [ Container( alignment: Alignment.center, width: hsp(75), child: Text(_endTime,style: TextStyle(fontSize: zsp(12),color: Colors.white),), ), GestureDetector( onTap: (){Navigator.pop(context);}, child: Icon(Icons.api,size: hsp(20),color: Colors.white,), ) ], ) ), ], ), ); }, ), ], ), ), ); } _pauseView({required VideoPlayerController controller}) { return StatefulBuilder( builder: (context,playSet){ _playSet = playSet; return Stack( children: [ AnimatedSwitcher( duration: const Duration(milliseconds: 50), reverseDuration: const Duration(milliseconds: 200), child: controller.value.isPlaying? Container():Container( alignment: Alignment.center, color: Colors.transparent, child: const Icon( Icons.play_circle_filled, color: Colors.white, size: 50, ), ), ), GestureDetector( onTap: () { playSet(() { controller.value.isPlaying ? controller.pause() : controller.play(); }); _progressSet(() {}); }, ), ], ); }, ); } }