video_upload.dart 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. import 'dart:async';
  2. import 'dart:io';
  3. import 'package:chewie/chewie.dart';
  4. import 'package:flustars/flustars.dart' as FlutterStars;
  5. import 'package:flutter/material.dart';
  6. import 'package:flutter/services.dart';
  7. import 'package:flutter_screenutil/flutter_screenutil.dart';
  8. import 'package:flutter_spinkit/flutter_spinkit.dart';
  9. import 'package:image_picker/image_picker.dart';
  10. import 'package:liftmanager/common/common.dart';
  11. import 'package:liftmanager/net/api_service.dart';
  12. import 'package:liftmanager/res/iconfont.dart';
  13. import 'package:liftmanager/res/resources.dart';
  14. import 'package:liftmanager/utils/fast_notification.dart';
  15. import 'package:liftmanager/utils/oss_upload.dart';
  16. import 'package:liftmanager/utils/theme_utils.dart';
  17. import 'package:liftmanager/utils/toast.dart';
  18. import 'package:liftmanager/utils/utils.dart';
  19. import 'package:liftmanager/widgets/app_bar.dart';
  20. import 'package:liftmanager/widgets/selected_video_change.dart';
  21. import 'package:orientation/orientation.dart';
  22. import 'package:video_player/video_player.dart';
  23. import '../../brand_page.dart';
  24. class VideoUpload extends StatefulWidget {
  25. @override
  26. State<StatefulWidget> createState() {
  27. return VideoUploadState();
  28. }
  29. }
  30. class VideoUploadState extends State<VideoUpload> {
  31. String selectedBrandName = '';
  32. String brandName = "品牌";
  33. int brandIdss;
  34. bool showBrandSelectionPanel = false;
  35. VideoPlayerController _controller;
  36. VideoPlayerController _controllerFile;
  37. ChewieController _chewieController;
  38. String videoUrl;
  39. String str;
  40. String imagesUrl;
  41. double percent = 0.0;
  42. @override
  43. void initState() {
  44. super.initState();
  45. }
  46. List<dynamic> brandList;
  47. Future getBrandList() async {
  48. await NewApiService().getBrandListType(null, onSuccess: (res) {
  49. if (res != null) {
  50. brandList = res;
  51. setState(() {});
  52. }
  53. }, onError: (code, msg) {
  54. toasts(msg);
  55. });
  56. }
  57. ///选择视频
  58. void selectPicker() {
  59. showDialog(
  60. context: context,
  61. builder: (BuildContext context) {
  62. return SimpleDialog(
  63. title: Text("选择方式"),
  64. children: ["拍照", '从手机相册选择'].map((String value) {
  65. print("$value");
  66. return SimpleDialogOption(
  67. child: Text(
  68. "${value}",
  69. style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
  70. ),
  71. onPressed: () {
  72. _getImage(value == '拍照' ? 1 : 0);
  73. Navigator.of(context).pop();
  74. },
  75. );
  76. }).toList());
  77. });
  78. }
  79. void _getImage(int key) async {
  80. try {
  81. await ImagePicker.pickVideo(
  82. source: key == 1 ? ImageSource.camera : ImageSource.gallery,
  83. ).then((File f) async {
  84. if (f != null) {
  85. _controllerFile = VideoPlayerController.file(f);
  86. _controllerFile.initialize().then((val) {
  87. _controllerFile.setLooping(true);
  88. int seconds = _controllerFile.value.duration.inSeconds;
  89. print("视频时长:$seconds");
  90. int fileSize = f.lengthSync(); //单位B
  91. print("视频大小:${fileSize}");
  92. print("视频大小:${f.path}");
  93. if (seconds <= 300) {
  94. _uploadImage(f.path);
  95. } else {
  96. toasts("视频时长不能大于5分钟!");
  97. }
  98. }).catchError((error) {
  99. print(error);
  100. print("error");
  101. toasts("上传失败,不支持此格式");
  102. });
  103. }
  104. });
  105. } catch (e) {
  106. toasts("没有权限,无法打开相册!");
  107. }
  108. }
  109. void _uploadImage(filePath) async {
  110. showPercent(context, () {
  111. dismissLoading(context);
  112. toasts("上传失败");
  113. }, () {
  114. if (videoUrl == null && str != null) {
  115. setState(() {
  116. videoUrl = str;
  117. settingVideVc();
  118. print("videoUrl:" + videoUrl);
  119. dismissLoading(context);
  120. toasts("上传成功");
  121. });
  122. }
  123. });
  124. String uploadName = OssUtil.instance.getImageUploadName(filePath);
  125. await NewApiService.uploadImage(context, uploadName, filePath).then((data) {
  126. if (data.statusCode == 200) {
  127. str = NewApiUrl.URL_UPLOAD_IMAGE_OSS + "/" + uploadName;
  128. print("str:" + str);
  129. print(videoUrl);
  130. if (str != null) {
  131. Map obj = {"uploadName": uploadName, "success": true};
  132. FastNotification.push("percent", obj);
  133. }
  134. } else {
  135. Map obj = {"uploadName": uploadName, "success": false};
  136. FastNotification.push("percent", obj);
  137. }
  138. }).catchError((data) {
  139. Map obj = {"uploadName": uploadName, "success": false};
  140. FastNotification.push("percent", obj);
  141. });
  142. }
  143. settingVideVc() {
  144. _controller?.pause();
  145. _controller?.dispose();
  146. _chewieController?.dispose();
  147. _controller = VideoPlayerController.network(Utils.getImagePath(videoUrl));
  148. _chewieController = ChewieController(
  149. videoPlayerController: _controller,
  150. aspectRatio: 3 / 2,
  151. allowFullScreen: false,
  152. isLive: true,
  153. autoPlay: false,
  154. looping: true,
  155. // startAt: Duration(seconds: 1,minutes: 1),
  156. showControls: true,
  157. deviceOrientationsAfterFullScreen: [DeviceOrientation.portraitUp],
  158. // 是否在 UI 构建的时候就加载视频
  159. autoInitialize: true,
  160. // 拖动条样式颜色
  161. materialProgressColors: new ChewieProgressColors(
  162. playedColor: Colors.red,
  163. handleColor: Colors.blue,
  164. backgroundColor: Colors.grey,
  165. bufferedColor: Colors.lightGreen,
  166. ),
  167. );
  168. }
  169. @override
  170. void dispose() {
  171. _controller?.pause();
  172. _controller?.dispose();
  173. _chewieController.dispose();
  174. FlutterStars.SpUtil.putString('uploadName', "");
  175. // player.release();
  176. super.dispose();
  177. }
  178. // 焦点控制
  179. FocusNode focusNode1 = new FocusNode();
  180. GlobalKey _formKey = new GlobalKey<FormState>();
  181. TextEditingController _titleController = new TextEditingController();
  182. TextEditingController _descController = new TextEditingController();
  183. @override
  184. Widget build(BuildContext context) {
  185. double width = MediaQuery.of(context).size.width;
  186. double height = MediaQuery.of(context).size.height;
  187. if (width > height) {
  188. // SystemChrome.setPreferredOrientations([
  189. // DeviceOrientation.portraitUp,
  190. // ]);
  191. OrientationPlugin.forceOrientation(DeviceOrientation.portraitUp);
  192. }
  193. return Scaffold(
  194. resizeToAvoidBottomPadding: false, //不让键盘弹上去
  195. appBar: MyAppBar(
  196. centerTitle: "上传视频",
  197. ),
  198. body: GestureDetector(
  199. onTap: () {
  200. // 点击空白页面关闭键盘
  201. FocusScope.of(context).requestFocus(focusNode1);
  202. },
  203. child: Stack(
  204. children: <Widget>[
  205. Container(
  206. child: ListView(children: <Widget>[
  207. Form(
  208. key: _formKey, //设置globalKey,用于后面获取FormState
  209. // autovalidate: true, //开启自动校验
  210. child: Column(
  211. children: <Widget>[
  212. ChioseThisRight(
  213. label: "电梯品牌",
  214. value: selectedBrandName,
  215. fun: () {
  216. setState(() {
  217. showBrandSelectionPanel = true;
  218. });
  219. getBrandList();
  220. }),
  221. SizedBox(height: 10),
  222. Row(
  223. crossAxisAlignment: CrossAxisAlignment.start,
  224. mainAxisAlignment: MainAxisAlignment.start,
  225. children: <Widget>[
  226. // Container(height:13 ,width: 100,color:Color(0xff5589FF) ,),
  227. Container(
  228. padding: EdgeInsets.only(
  229. left: 10,
  230. ),
  231. decoration: BoxDecoration(
  232. border: Border(
  233. left: BorderSide(
  234. width: 2,
  235. color: Colors.blue,
  236. ),
  237. ),
  238. ),
  239. child: Text(
  240. "视频标题",
  241. style: TextStyle(
  242. fontSize: 14,
  243. color: Color(0xff333333),
  244. ),
  245. textAlign: TextAlign.left,
  246. ),
  247. ),
  248. ],
  249. ),
  250. Container(
  251. height: 80,
  252. padding: EdgeInsets.only(
  253. left: 12,
  254. right: 12,
  255. bottom: 20),
  256. child: TextFormField(
  257. // autofocus: true,
  258. maxLength: 50,
  259. cursorColor: Color(0xffcccccc),
  260. controller: _titleController,
  261. maxLines: 5,
  262. decoration: InputDecoration(
  263. contentPadding: EdgeInsets.all(0),
  264. hintText: '请输入你上传视频的标题',
  265. hintStyle: TextStyle(color: Color(0xffcccccc)),
  266. focusedBorder: InputBorder.none,
  267. border: InputBorder.none,
  268. // filled: true, // 背景色
  269. // fillColor: Colors.cyan.withAlpha(35),
  270. // icon: Icon(Icons.person)
  271. ),
  272. // 校验
  273. validator: (val) {
  274. return val.trim().length > 0 ? null : "不能为空";
  275. }),
  276. ),
  277. Divider(),
  278. SizedBox(height: 10),
  279. Row(
  280. crossAxisAlignment: CrossAxisAlignment.start,
  281. mainAxisAlignment: MainAxisAlignment.start,
  282. children: <Widget>[
  283. Container(
  284. padding: EdgeInsets.only(
  285. left: 10,
  286. ),
  287. decoration: BoxDecoration(
  288. border: Border(
  289. left: BorderSide(
  290. width: 2,
  291. color: Colors.blue,
  292. ),
  293. ),
  294. ),
  295. child: Text(
  296. "视频简介",
  297. style: TextStyle(
  298. fontSize: 14,
  299. color: Color(0xff333333),
  300. ),
  301. textAlign: TextAlign.left,
  302. ),
  303. ),
  304. ],
  305. ),
  306. Container(
  307. height: 120,
  308. padding: EdgeInsets.only(
  309. left: 12,
  310. right: 12,
  311. bottom: 20),
  312. child: TextFormField(
  313. // autofocus: true,
  314. maxLength: 500,
  315. cursorColor: Color(0xffcccccc),
  316. controller: _descController,
  317. maxLines: 5,
  318. decoration: InputDecoration(
  319. contentPadding: EdgeInsets.all(0),
  320. hintText: '请输入您上传视频的简介',
  321. hintStyle: TextStyle(color: Color(0xffcccccc)),
  322. focusedBorder: InputBorder.none,
  323. border: InputBorder.none,
  324. ),
  325. // 校验
  326. validator: (val) {
  327. return val.trim().length > 0 ? null : "不能为空";
  328. }),
  329. ),
  330. Divider(),
  331. SizedBox(
  332. height: 20,
  333. ),
  334. Container(
  335. color: ThemeUtils.getTabsBg(context),
  336. padding: EdgeInsets.symmetric(horizontal: 10),
  337. child: Row(
  338. crossAxisAlignment: CrossAxisAlignment.end,
  339. children: [
  340. Stack(
  341. children: <Widget>[
  342. Container(
  343. height: 150,
  344. width: 150,
  345. child: SelectedVideo(
  346. image: videoUrl,
  347. videoPlay: videoPlay(),
  348. onTap: () {
  349. if (videoUrl == null) {
  350. selectPicker();
  351. }
  352. },
  353. ),
  354. ),
  355. (videoUrl != null)
  356. ? Positioned(
  357. top: 0,
  358. right: 0,
  359. child: GestureDetector(
  360. onTap: () {
  361. // print(index);
  362. // imagesUrl = null;
  363. setState(() {
  364. videoUrl = null;
  365. str = null;
  366. _controller.pause();
  367. // player.reset();
  368. });
  369. },
  370. child: Icon(
  371. const IconData(0xe651,
  372. fontFamily: "Iconfont"),
  373. size: 24.0,
  374. color: Color(0xff999999),
  375. ),
  376. ))
  377. : Container()
  378. ],
  379. ),
  380. Container(
  381. padding: EdgeInsets.only(left: 10),
  382. child: Text(
  383. "(建议时长<3分钟,大小<50M)",
  384. style: TextStyle(
  385. fontSize: ScreenUtil().setSp(13),
  386. color: Color(0xffCCCCCC)),
  387. textAlign: TextAlign.left,
  388. ),
  389. ),
  390. ],
  391. )),
  392. SizedBox(
  393. height: ScreenUtil().setWidth(80),
  394. ),
  395. ],
  396. ),
  397. )
  398. ])),
  399. Positioned(
  400. bottom: 0,
  401. left: 0,
  402. child: Container(
  403. width: width,
  404. padding: EdgeInsets.only(
  405. top: ScreenUtil().setWidth(15),
  406. bottom: ScreenUtil().setWidth(10),
  407. left: ScreenUtil().setWidth(10),
  408. right: ScreenUtil().setWidth(10),
  409. ),
  410. color: ThemeUtils.getDialogTextFieldColor(context),
  411. child: Container(
  412. height: 45,
  413. decoration: BoxDecoration(
  414. borderRadius:
  415. BorderRadius.circular(ScreenUtil().setWidth(22)),
  416. color: Color(0xff5589FF),
  417. ),
  418. child: FlatButton(
  419. // padding: EdgeInsets.all(15.0),
  420. child: Text("确认上传"),
  421. textColor: Colors.white,
  422. onPressed: () {
  423. if (brandIdss == null) {
  424. toasts("请选择品牌");
  425. return;
  426. }
  427. if (videoUrl == null || videoUrl == "") {
  428. toasts("请上传视频");
  429. return;
  430. }
  431. if ((_formKey.currentState as FormState).validate()) {
  432. dynamic obj = {
  433. "brandId": brandIdss,
  434. "title": _titleController.text,
  435. "descr": _descController.text,
  436. "url": videoUrl,
  437. // "cover": images,
  438. "checkFlag": 2,
  439. "statuz": 1,
  440. "platformFlag": 1,
  441. "userId":
  442. FlutterStars.SpUtil.getString(Constant.userId),
  443. };
  444. showLoading(context, "正在提交...");
  445. NewApiService().addVideo(obj, onSuccess: (res) {
  446. dismissLoading(context);
  447. toasts("提交成功");
  448. if (_controller != null) {
  449. _controller.pause();
  450. }
  451. Navigator.pop(context);
  452. }, onError: (code, msg) {
  453. dismissLoading(context);
  454. toasts(msg);
  455. });
  456. }
  457. },
  458. ),
  459. ),
  460. )),
  461. if (showBrandSelectionPanel)
  462. Positioned(
  463. top: 0,
  464. left: 0,
  465. child: GestureDetector(
  466. onTap: () {
  467. setState(() {
  468. showBrandSelectionPanel = false;
  469. });
  470. },
  471. child: Container(
  472. width: width,
  473. height: height,
  474. color: Color.fromRGBO(0, 0, 0, 0.5),
  475. ),
  476. ),
  477. ),
  478. if (showBrandSelectionPanel)
  479. Positioned(
  480. top: 0,
  481. right: 0,
  482. child: Container(
  483. width: width * 0.8,
  484. height: height,
  485. color: Colors.white,
  486. child: brandList == null
  487. ? loadCircle()
  488. : BrandSelectionPanel(
  489. brandList: brandList,
  490. onTapBrand: (records) {
  491. setState(() {
  492. selectedBrandName = records.name;
  493. brandIdss = records.id;
  494. showBrandSelectionPanel = false;
  495. });
  496. },
  497. ),
  498. ),
  499. ),
  500. ],
  501. ),
  502. ),
  503. );
  504. }
  505. Widget loadCircle() {
  506. return Container(
  507. padding: EdgeInsets.only(top: 10, bottom: 10),
  508. color: ThemeUtils.getTabsBg(context),
  509. child: Center(
  510. child: SpinKitFadingCircle(
  511. color: Colors.blueAccent,
  512. size: 30.0,
  513. ),
  514. ),
  515. );
  516. }
  517. Widget videoPlay() {
  518. if (_controller == null) return Container();
  519. return Container(
  520. child: ClipRRect(
  521. borderRadius: BorderRadius.circular(5),
  522. child: new Chewie(controller: _chewieController),
  523. ));
  524. }
  525. }
  526. class ChioseThisRight extends StatelessWidget {
  527. ChioseThisRight(
  528. {Key key, this.value, this.label, this.fun, this.labelText = '请选择'})
  529. : super(key: key);
  530. String value;
  531. String label;
  532. Function fun;
  533. String labelText;
  534. @override
  535. Widget build(BuildContext context) {
  536. double width = MediaQuery.of(context).size.width;
  537. return InkWell(
  538. onTap: () {
  539. fun();
  540. },
  541. child: Container(
  542. padding: EdgeInsets.only(
  543. top: ScreenUtil().setWidth(15), bottom: ScreenUtil().setWidth(15)),
  544. margin: EdgeInsets.only(left: ScreenUtil().setWidth(15)),
  545. decoration: BoxDecoration(
  546. border: Border(
  547. bottom: BorderSide(width: 0.5, color: Colours.line),
  548. ),
  549. ),
  550. child: Row(
  551. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  552. children: <Widget>[
  553. Text(
  554. label,
  555. style: TextStyle(
  556. fontSize: 14,
  557. color: Color(0xff333333),
  558. ),
  559. textAlign: TextAlign.start,
  560. ),
  561. value.isEmpty
  562. ? Container(
  563. child: Row(children: <Widget>[
  564. Text(
  565. labelText,
  566. style:
  567. TextStyle(color: Color(0xff666666), fontSize: 13),
  568. textAlign: TextAlign.start,
  569. ),
  570. Icon(
  571. Iconfont.gengduo,
  572. size: 13.0,
  573. // color: Color(0xffcccccc),
  574. ),
  575. // Container(
  576. // padding: EdgeInsets.only(top: 3),
  577. // ),
  578. SizedBox(width: 10)
  579. ]),
  580. )
  581. : Container(
  582. padding:
  583. EdgeInsets.only(right: ScreenUtil().setWidth(15)),
  584. child: Row(children: <Widget>[
  585. Text(
  586. value,
  587. style: TextStyle(
  588. color: Color(0xff222222),
  589. fontSize: 13,
  590. ),
  591. textAlign: TextAlign.start,
  592. ),
  593. ]),
  594. ),
  595. ]),
  596. ),
  597. );
  598. }
  599. }