video_detail.dart 28 KB

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