video_upload.dart 22 KB

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