video_detail.dart 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. import 'dart:async';
  2. import 'dart:math';
  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:liftmanager/common/common.dart';
  9. import 'package:liftmanager/internal/account/account_router.dart';
  10. import 'package:liftmanager/internal/bbs/model/video_detail.dart';
  11. import 'package:liftmanager/internal/bbs/page/tab/question/question_pay.dart';
  12. import 'package:liftmanager/internal/wode/wode_router.dart';
  13. import 'package:liftmanager/net/api_service.dart';
  14. import 'package:liftmanager/res/iconfont.dart';
  15. import 'package:liftmanager/res/resources.dart';
  16. import 'package:liftmanager/routers/fluro_navigator.dart';
  17. import 'package:liftmanager/utils/fast_notification.dart';
  18. import 'package:liftmanager/utils/time_format.dart';
  19. import 'package:liftmanager/utils/toast.dart';
  20. import 'package:liftmanager/utils/utils.dart';
  21. import 'package:liftmanager/widgets/app_bar.dart';
  22. import 'package:liftmanager/widgets/load_image.dart';
  23. import 'package:orientation/orientation.dart';
  24. import 'package:umeng_common_sdk/umeng_common_sdk.dart';
  25. import 'package:video_player/video_player.dart';
  26. import 'package:flustars/flustars.dart' as flustars;
  27. import 'package:liftmanager/internal/bbs/model/expert_model.dart'
  28. as ExportModel;
  29. class VideoDetail extends StatefulWidget {
  30. VideoDetail(this.id);
  31. final String id;
  32. @override
  33. State<StatefulWidget> createState() {
  34. return VideoDetailState();
  35. }
  36. }
  37. class VideoDetailState extends State<VideoDetail> {
  38. @override
  39. void initState() {
  40. UmengCommonSdk.onPageStart("电梯学堂");
  41. super.initState();
  42. Future.delayed(Duration(milliseconds: 100), () {
  43. getVideoDetail();
  44. });
  45. }
  46. @override
  47. void dispose() {
  48. UmengCommonSdk.onPageEnd("电梯学堂");
  49. _controller?.pause();
  50. _controller?.dispose();
  51. super.dispose();
  52. }
  53. bool _hasData = false;
  54. VideoDetailModel detailObj;
  55. VideoPlayerController _controller;
  56. bool showBuyVipAd = false;
  57. bool allowFullScreen = false;
  58. void getUserInfo(Function(ExportModel.Records userInfo) onCompletion) {
  59. NewApiService().getExpertDetail(flustars.SpUtil.getString(Constant.userId),
  60. onSuccess: (res) {
  61. if (onCompletion != null) {
  62. onCompletion(res);
  63. }
  64. }, onError: (code, msg) {
  65. toasts(msg);
  66. });
  67. }
  68. Future getVideoDetail() async {
  69. await NewApiService().getVideoDetail(int.parse(widget.id), 1,
  70. onSuccess: (res) {
  71. if (res != null) {
  72. _hasData = true;
  73. detailObj = res;
  74. if (_controller == null) {
  75. _controller =
  76. VideoPlayerController.network(Utils.getImagePath(detailObj.url));
  77. var callback = () {
  78. if (_controller.value.isPlaying &&
  79. _controller.value.position >= Duration(minutes: 3)) {
  80. _controller.pause();
  81. setState(() {
  82. showBuyVipAd = true;
  83. });
  84. }
  85. };
  86. _controller.addListener(callback);
  87. getUserInfo((userInfo) {
  88. if (userInfo.vipFlag == 2) {
  89. if (_controller != null) {
  90. _controller.removeListener(callback);
  91. }
  92. setState(() {
  93. showBuyVipAd = false;
  94. allowFullScreen = true;
  95. });
  96. }
  97. });
  98. }
  99. setState(() {});
  100. }
  101. }, onError: (code, msg) {
  102. toasts(msg);
  103. });
  104. }
  105. Future changeLike(type) async {
  106. await NewApiService().videoLike(detailObj.id, type, 1, onSuccess: (res) {
  107. String textLike;
  108. if (type == 2) {
  109. textLike = "点赞";
  110. } else if (type == 3) {
  111. textLike = "收藏";
  112. initCollect();
  113. }
  114. toasts("$textLike成功");
  115. getVideoDetail();
  116. }, onError: (code, msg) {
  117. toasts(msg);
  118. });
  119. }
  120. showAlertEvent() {
  121. showAlert(
  122. context,
  123. "提示",
  124. "确定登录?",
  125. "确定",
  126. () {
  127. if (_controller != null) {
  128. _controller.pause();
  129. }
  130. NavigatorUtils.push(context, AccountRouter.loginPage, clearStack: true);
  131. },
  132. txt2: "取消",
  133. onPre2: () {
  134. NavigatorUtils.goBack(context);
  135. },
  136. );
  137. }
  138. Future cancelLike(type) async {
  139. var idChiose;
  140. String textLike;
  141. if (type == 2) {
  142. idChiose = detailObj.likeId;
  143. textLike = "点赞";
  144. } else if (type == 3) {
  145. idChiose = detailObj.favoriteId;
  146. textLike = "收藏";
  147. }
  148. await NewApiService().videoLikeCancel(idChiose, onSuccess: (res) {
  149. toasts("取消$textLike成功");
  150. if (type == 3) {
  151. initCollect();
  152. }
  153. getVideoDetail();
  154. }, onError: (code, msg) {
  155. toasts(msg);
  156. });
  157. }
  158. initCollect() {
  159. String collectInit = randomInt(1111, 9999).toString() +
  160. DateTime.now().millisecondsSinceEpoch.toString();
  161. FastNotification.push("collectAction", collectInit);
  162. }
  163. randomInt(int min, int max) {
  164. return new Random().nextInt(max) % (max - min + 1) + min;
  165. }
  166. @override
  167. Widget build(BuildContext context) {
  168. double width = MediaQuery.of(context).size.width;
  169. double height = MediaQuery.of(context).size.height;
  170. print(width);
  171. print(height);
  172. if (width > height) {
  173. OrientationPlugin.forceOrientation(DeviceOrientation.portraitUp);
  174. }
  175. return Scaffold(
  176. resizeToAvoidBottomPadding: false, //不让键盘弹上去
  177. appBar: MyAppBar(
  178. centerTitle: "电梯学堂",
  179. ),
  180. body: _hasData
  181. ? Stack(
  182. children: <Widget>[
  183. Container(
  184. child: ListView(
  185. children: <Widget>[
  186. Column(
  187. mainAxisAlignment: MainAxisAlignment.start,
  188. crossAxisAlignment: CrossAxisAlignment.start,
  189. children: <Widget>[
  190. Container(
  191. padding: EdgeInsets.symmetric(horizontal: 10),
  192. child: Stack(
  193. children: [
  194. Chewie(
  195. controller: ChewieController(
  196. videoPlayerController: _controller,
  197. aspectRatio: 3 / 2,
  198. allowFullScreen: allowFullScreen,
  199. autoPlay: false,
  200. looping: true,
  201. // startAt: Duration(seconds: 1,minutes: 1),
  202. showControls: true,
  203. deviceOrientationsAfterFullScreen: [
  204. DeviceOrientation.portraitUp
  205. ],
  206. // 占位图
  207. // placeholder: Image.network(
  208. // imgFontUrl+detailObj.cover,
  209. // fit: BoxFit.contain,
  210. // ),
  211. // 是否在 UI 构建的时候就加载视频
  212. autoInitialize: true,
  213. // 拖动条样式颜色
  214. materialProgressColors:
  215. new ChewieProgressColors(
  216. playedColor: Colors.blue,
  217. handleColor: Colors.blue,
  218. backgroundColor: Colors.transparent,
  219. bufferedColor: Colors.grey,
  220. ),
  221. ),
  222. ),
  223. if (showBuyVipAd)
  224. Container(
  225. width: width,
  226. height: 270,
  227. decoration: BoxDecoration(
  228. color: Color.fromARGB(200, 0, 0, 0),
  229. borderRadius: BorderRadius.circular(4),
  230. ),
  231. child: Column(
  232. mainAxisAlignment:
  233. MainAxisAlignment.center,
  234. children: [
  235. Text(
  236. '您的试看时间已用完,升级会员查看完整视频吧~',
  237. style: TextStyle(
  238. fontSize: 13,
  239. color: Color(0xffffffff),
  240. ),
  241. ),
  242. SizedBox(
  243. height: 10,
  244. ),
  245. Stack(
  246. overflow: Overflow.visible,
  247. children: [
  248. GestureDetector(
  249. onTap: () {
  250. NavigatorUtils.push(context,
  251. '${WodeRouter.vip}?id=');
  252. },
  253. child: Container(
  254. width: 50,
  255. height: 50,
  256. decoration: BoxDecoration(
  257. gradient: LinearGradient(
  258. colors: [
  259. Color(0xffE6C8A0),
  260. Color(0xffDCB885)
  261. ]),
  262. borderRadius:
  263. BorderRadius.circular(
  264. 25),
  265. ),
  266. child: Icon(
  267. Iconfont.huiyuan101,
  268. color: Colors.white,
  269. ),
  270. ),
  271. ),
  272. Positioned(
  273. top: 0,
  274. left: 30,
  275. child: Container(
  276. padding: EdgeInsets.all(2),
  277. color: Color(0xffF95046),
  278. child: Text(
  279. '最低仅需40元/月',
  280. style: TextStyle(
  281. color: Colors.white,
  282. fontSize: 9),
  283. ),
  284. ),
  285. ),
  286. ],
  287. ),
  288. SizedBox(
  289. height: 10,
  290. ),
  291. Text(
  292. '成为会员无限看',
  293. style: TextStyle(
  294. fontSize: 13,
  295. color: Color(0xffffffff),
  296. ),
  297. )
  298. ],
  299. ),
  300. ),
  301. ],
  302. )),
  303. Container(
  304. width: width,
  305. padding: EdgeInsets.symmetric(horizontal: 10),
  306. decoration: BoxDecoration(
  307. border: Border(
  308. bottom:
  309. BorderSide(width: 0.5, color: Colours.line),
  310. ),
  311. ),
  312. child: Column(
  313. mainAxisAlignment: MainAxisAlignment.start,
  314. crossAxisAlignment: CrossAxisAlignment.start,
  315. children: <Widget>[
  316. SizedBox(
  317. height: 10,
  318. ),
  319. Container(
  320. width: width * 0.65,
  321. child: Text(
  322. detailObj.title ?? "",
  323. style: TextStyle(
  324. fontSize: 16,
  325. color: Color(0xff333333),
  326. ),
  327. textAlign: TextAlign.start,
  328. maxLines: 1,
  329. overflow: TextOverflow.ellipsis,
  330. ),
  331. ),
  332. SizedBox(height: 10),
  333. Row(
  334. mainAxisAlignment:
  335. MainAxisAlignment.spaceBetween,
  336. children: [
  337. Container(
  338. padding: EdgeInsets.all(3),
  339. decoration: BoxDecoration(
  340. color: Color(0x33448EFA),
  341. borderRadius: BorderRadius.circular(3),
  342. ),
  343. child: Text(
  344. detailObj.brandName ?? "",
  345. overflow: TextOverflow.ellipsis,
  346. style: TextStyle(
  347. fontSize: 11,
  348. color: Color(0xff5888FF),
  349. ),
  350. ),
  351. ),
  352. Text(
  353. "${detailObj.browseNum ?? "0"}浏览·${detailObj.likeNum ?? "0"}赞",
  354. style: TextStyle(
  355. color: Color(0xffcccccc),
  356. fontSize: 11,
  357. ),
  358. textAlign: TextAlign.start,
  359. ),
  360. ],
  361. ),
  362. SizedBox(
  363. height: 10,
  364. ),
  365. ],
  366. ),
  367. ),
  368. Container(
  369. padding: EdgeInsets.symmetric(
  370. horizontal: 10, vertical: 10),
  371. decoration: BoxDecoration(
  372. border: Border(
  373. bottom:
  374. BorderSide(width: 0.5, color: Colours.line),
  375. ),
  376. ),
  377. child: Column(
  378. crossAxisAlignment: CrossAxisAlignment.start,
  379. children: [
  380. Row(
  381. children: <Widget>[
  382. Container(
  383. child: ClipRRect(
  384. borderRadius: BorderRadius.circular(16),
  385. child: LoadNetworkImage(
  386. detailObj.avatarUrl,
  387. // fit: BoxFit.cover,
  388. width: 32,
  389. height: 32,
  390. ),
  391. ),
  392. ),
  393. SizedBox(width: 10),
  394. Text(
  395. detailObj.nickname ?? "",
  396. style: TextStyle(
  397. fontSize: 14,
  398. color: Color(0xff555A64)),
  399. ),
  400. ],
  401. ),
  402. SizedBox(
  403. height: 20,
  404. ),
  405. Text(
  406. '${detailObj.createTime != null ? DateUtils.instance.getFormartData(timeSamp: detailObj.createTime, format: "yyyy-MM-dd") : ""} 发布',
  407. style: TextStyle(
  408. fontSize: 12,
  409. color: Color(0xff989898),
  410. ),
  411. ),
  412. ],
  413. ),
  414. ),
  415. SizedBox(
  416. height: 10,
  417. ),
  418. Column(
  419. crossAxisAlignment: CrossAxisAlignment.start,
  420. mainAxisAlignment: MainAxisAlignment.start,
  421. children: <Widget>[
  422. Container(
  423. padding: EdgeInsets.symmetric(horizontal: 10),
  424. decoration: BoxDecoration(
  425. border: Border(
  426. left: BorderSide(
  427. width: 2, color: Colors.blue),
  428. ),
  429. ),
  430. child: Text(
  431. "视频简介",
  432. style: TextStyle(
  433. fontSize: 15,
  434. color: Color(0xff333333),
  435. ),
  436. textAlign: TextAlign.left,
  437. ),
  438. ),
  439. SizedBox(
  440. height: 10,
  441. ),
  442. Container(
  443. padding: EdgeInsets.symmetric(horizontal: 10),
  444. child: Text(
  445. detailObj.descr ?? "",
  446. style: TextStyle(
  447. color: Color(0xff333333),
  448. fontSize: 13,
  449. ),
  450. textAlign: TextAlign.left,
  451. ),
  452. ),
  453. ],
  454. ),
  455. ],
  456. ),
  457. ],
  458. ),
  459. ),
  460. Positioned(
  461. bottom: 0,
  462. left: 0,
  463. child: Container(
  464. width: width,
  465. color: Colors.white,
  466. child: Row(children: <Widget>[
  467. Container(
  468. height: 60,
  469. width: width * .35,
  470. color: Colors.white,
  471. padding: EdgeInsets.only(
  472. left: ScreenUtil().setWidth(10),
  473. right: ScreenUtil().setWidth(10),
  474. top: ScreenUtil().setWidth(10)),
  475. child: Row(
  476. mainAxisAlignment:
  477. MainAxisAlignment.spaceAround,
  478. children: <Widget>[
  479. GestureDetector(
  480. onTap: () {
  481. if (FlutterStars.SpUtil.getString(
  482. Constant.userId) ==
  483. "-1") {
  484. showAlertEvent();
  485. } else {
  486. if (detailObj.isLike == 1) {
  487. cancelLike(2);
  488. } else {
  489. changeLike(2);
  490. }
  491. }
  492. },
  493. child: Container(
  494. child: Column(children: <Widget>[
  495. Icon(
  496. // : 0xe608,
  497. detailObj.isLike == 1
  498. ? Iconfont.dianzan
  499. : Iconfont.dianzan35,
  500. size: 20.0,
  501. color: detailObj.isLike == 1
  502. ? Color(0xff5589FF)
  503. : Color(0xff555A64),
  504. ),
  505. Text(
  506. detailObj.isLike == 1 ? "已点赞" : "点赞",
  507. style: TextStyle(
  508. color: Color(detailObj.isLike == 1
  509. ? 0xff5589FF
  510. : 0xff555A64),
  511. fontSize: 12,
  512. ),
  513. textAlign: TextAlign.start,
  514. ),
  515. ])),
  516. ),
  517. GestureDetector(
  518. onTap: () {
  519. if (FlutterStars.SpUtil.getString(
  520. Constant.userId) ==
  521. "-1") {
  522. showAlertEvent();
  523. } else {
  524. if (detailObj.isFavorite == 1) {
  525. cancelLike(3);
  526. } else {
  527. changeLike(3);
  528. }
  529. }
  530. },
  531. child: Container(
  532. child: Column(children: <Widget>[
  533. Icon(
  534. // : 0xe604,
  535. detailObj.isFavorite == 1
  536. ? const IconData(0xe62a,
  537. fontFamily: "Iconfont")
  538. : const IconData(0xe6b7,
  539. fontFamily: "Iconfont"),
  540. size: 20.0,
  541. color: Color(detailObj.isFavorite == 1
  542. ? 0xff5589FF
  543. : 0xff555A64),
  544. ),
  545. Text(
  546. detailObj.isFavorite == 1
  547. ? "已收藏"
  548. : "收藏",
  549. style: TextStyle(
  550. color: Color(detailObj.isFavorite == 1
  551. ? 0xff5589FF
  552. : 0xff555A64),
  553. fontSize: 12,
  554. ),
  555. textAlign: TextAlign.start,
  556. ),
  557. ])),
  558. )
  559. ],
  560. )),
  561. Container(
  562. width: width * 0.65,
  563. height: 45,
  564. padding: EdgeInsets.only(right: 10),
  565. child: ClipRRect(
  566. borderRadius: BorderRadius.circular(40),
  567. child: FlatButton(
  568. color: Color(0xff5589FF),
  569. child: Text(
  570. "打赏",
  571. style: TextStyle(
  572. fontSize: 16,
  573. ),
  574. ),
  575. textColor: Colors.white,
  576. onPressed: () {
  577. if (FlutterStars.SpUtil.getString(
  578. Constant.userId) ==
  579. "-1") {
  580. showAlertEvent();
  581. } else {
  582. var nickname;
  583. if (detailObj.nickname != null) {
  584. nickname = Uri.encodeComponent(
  585. detailObj.nickname);
  586. }
  587. if (_controller != null) {
  588. _controller.pause();
  589. }
  590. // ym_reward_onClickPay
  591. UmengCommonSdk.onEvent(
  592. "ym_reward_onClickPay",
  593. {
  594. "formUserName": detailObj.nickname,
  595. "formUserId": detailObj.userId,
  596. "title": detailObj.title,
  597. "typeName": 'video',
  598. "formId": detailObj.id.toString(),
  599. },
  600. );
  601. // toasts("点击打赏");
  602. Navigator.push(
  603. context,
  604. MaterialPageRoute(
  605. builder: (context) => QuestionPay(
  606. detailObj.id.toString(),
  607. "video",
  608. detailObj.nickname,
  609. detailObj.avatarUrl,
  610. expert: detailObj.userId,
  611. title: detailObj.title,
  612. )));
  613. // NavigatorUtils.push(context,
  614. // "${BbsRouter.questionPay}?id=${detailObj.id}&videoModel-${detailObj.toJson()}&type=video&name=$nickname");
  615. }
  616. },
  617. ),
  618. ),
  619. ),
  620. ])))
  621. ],
  622. )
  623. : Center(
  624. child: Text("正在加载..."),
  625. ),
  626. );
  627. }
  628. }