Hibok
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

909 lines
41 KiB

  1. import 'dart:async';
  2. import 'dart:io';
  3. import 'dart:math';
  4. import 'package:chat/data/UserData.dart';
  5. import 'package:chat/data/WebData.dart';
  6. import 'package:chat/data/constants.dart';
  7. import 'package:chat/generated/i18n.dart';
  8. import 'package:chat/home/VipPage.dart';
  9. import 'package:chat/models/money_change.dart';
  10. import 'package:chat/utils/CustomUI.dart';
  11. import 'package:chat/utils/HttpUtil.dart';
  12. import 'package:chat/utils/MessageMgr.dart';
  13. import 'package:chat/utils/TokenMgr.dart';
  14. import 'package:chat/utils/flutter_windowmanager.dart';
  15. import 'package:chat/utils/screen.dart';
  16. import 'package:dio/dio.dart';
  17. import 'package:extended_image/extended_image.dart';
  18. import 'dart:ui' as ui;
  19. import 'package:flutter/material.dart';
  20. import 'package:flutter/rendering.dart';
  21. import 'package:provider/provider.dart';
  22. import 'ChargeMoney.dart';
  23. double initScale({Size imageSize, Size size, double initialScale}) {
  24. var n1 = imageSize.height / imageSize.width;
  25. var n2 = size.height / size.width;
  26. if (n1 > n2) {
  27. final FittedSizes fittedSizes =
  28. applyBoxFit(BoxFit.contain, imageSize, size);
  29. //final Size sourceSize = fittedSizes.source;
  30. Size destinationSize = fittedSizes.destination;
  31. return size.width / destinationSize.width;
  32. } else if (n1 / n2 < 1 / 4) {
  33. final FittedSizes fittedSizes =
  34. applyBoxFit(BoxFit.contain, imageSize, size);
  35. //final Size sourceSize = fittedSizes.source;
  36. Size destinationSize = fittedSizes.destination;
  37. return size.height / destinationSize.height;
  38. }
  39. return initialScale;
  40. }
  41. class PicSwiper extends StatefulWidget {
  42. final int id;
  43. final List<PicSwiperItem> pics;
  44. PicSwiper({this.id, this.pics});
  45. @override
  46. _PicSwiperState createState() => _PicSwiperState();
  47. }
  48. class _PicSwiperState extends State<PicSwiper>
  49. with SingleTickerProviderStateMixin {
  50. var rebuildIndex = StreamController<int>.broadcast();
  51. var rebuildSwiper = StreamController<bool>.broadcast();
  52. AnimationController _animationController;
  53. Animation<double> _animation;
  54. Function animationListener;
  55. // CancellationToken _cancelToken;
  56. // CancellationToken get cancelToken {
  57. // if (_cancelToken == null || _cancelToken.isCanceled)
  58. // _cancelToken = CancellationToken();
  59. //
  60. // return _cancelToken;
  61. // }
  62. List<double> doubleTapScales = <double>[1.0, 2.0];
  63. GlobalKey<ExtendedImageSlidePageState> slidePagekey =
  64. GlobalKey<ExtendedImageSlidePageState>();
  65. int currentIndex;
  66. bool _showSwiper = true;
  67. int _seconds = 0;
  68. bool isMyself = false;
  69. @override
  70. void initState() {
  71. setDisableScreenshots();
  72. for (int i = 0; i < widget.pics.length; i++) {
  73. if (widget.id == widget.pics[i].id) {
  74. currentIndex = i;
  75. break;
  76. }
  77. }
  78. isMyself = widget.pics[0].userId == UserData().basicInfo.userId;
  79. _animationController = AnimationController(
  80. duration: const Duration(milliseconds: 150), vsync: this);
  81. super.initState();
  82. }
  83. setDisableScreenshots() async {
  84. print('Platform.isAndroid ${Platform.isAndroid}');
  85. if (Platform.isAndroid) {
  86. await FlutterWindowManager.addFlags(FlutterWindowManager.FLAG_SECURE);
  87. }
  88. }
  89. clearFalgs() async {
  90. if (Platform.isAndroid) {
  91. await FlutterWindowManager.clearFlags(FlutterWindowManager.FLAG_SECURE);
  92. }
  93. }
  94. @override
  95. void dispose() {
  96. rebuildIndex.close();
  97. rebuildSwiper.close();
  98. _animationController?.dispose();
  99. clearGestureDetailsCache();
  100. clearFalgs();
  101. //cancelToken?.cancel();
  102. super.dispose();
  103. }
  104. void browsePhoto(id, userId, type, callback, {price = 0}) async {
  105. if (Provider.of<MoneyChangeProvider>(context).money < price) {
  106. CustomUI.buildOneConfirm(context, I18n.of(context).balance_insufficien,
  107. I18n.of(context).recharge, () {
  108. Navigator.of(context).pop();
  109. ChargeMoney.showChargeSheet(context, () {
  110. setState(() {});
  111. });
  112. });
  113. return;
  114. }
  115. var data = {
  116. "visitUserId": UserData().basicInfo.userId,
  117. "userId": userId,
  118. "pId": id,
  119. 'type': type,
  120. };
  121. data['sign'] = TokenMgr().getSign(data);
  122. data['price'] = price;
  123. Response res = await HttpUtil().post('user/browse/photo', data: data);
  124. Map resData = res.data;
  125. print(resData);
  126. if (resData['code'] == 0) {
  127. MessageMgr().emit('refresh_photo', id);
  128. callback();
  129. }
  130. }
  131. @override
  132. Widget build(BuildContext context) {
  133. var size = MediaQuery.of(context).size;
  134. bool isAgree = (widget.pics[currentIndex].type == PhotoType.destroy.index ||
  135. widget.pics[currentIndex].type == PhotoType.destroyMoney.index);
  136. var id = widget.pics[currentIndex].id;
  137. Widget result = Scaffold(
  138. // StreamBuilder(
  139. // builder: (BuildContext context, data) {},
  140. // initialData: true,
  141. // stream: rebuildSwiper.stream,
  142. // ),
  143. appBar: AppBar(
  144. backgroundColor: AppColors.NewAppbarBgColor,
  145. title: StreamBuilder<int>(
  146. builder: (BuildContext context, data) {
  147. return Text(
  148. '${data.data + 1} / ${widget.pics.length}',
  149. style: TextStyle(
  150. fontSize: 16, color: AppColors.NewAppbarTextColor),
  151. textScaleFactor: 1.0,
  152. );
  153. },
  154. initialData: currentIndex,
  155. stream: rebuildIndex.stream,
  156. ),
  157. leading: CustomUI.buildCustomLeading(context),
  158. centerTitle: true,
  159. elevation: 1,
  160. actions: <Widget>[
  161. isMyself
  162. ? InkWell(
  163. onTap: () {
  164. CustomUI.buildOneConfirm(
  165. context,
  166. I18n.of(context).sure_delete,
  167. I18n.of(context).determine, () {
  168. var id = widget.pics[currentIndex].id;
  169. HttpUtil().setPhote(context, id, 2, () {
  170. widget.pics.removeAt(currentIndex);
  171. MessageMgr().emit('refresh_photo', id);
  172. if (widget.pics.length == 0) {
  173. Navigator.of(context).pop();
  174. } else {
  175. setState(() {
  176. if (currentIndex != 0) currentIndex--;
  177. });
  178. }
  179. });
  180. Navigator.of(context).pop();
  181. });
  182. },
  183. child: Container(
  184. margin: EdgeInsets.only(right: 10),
  185. child: CircleAvatar(
  186. backgroundColor: Constants.GreyBackgroundColor,
  187. radius: 13.75,
  188. child: Icon(
  189. Icons.delete,
  190. color: Constants.BlackTextColor,
  191. size: 20,
  192. ))),
  193. )
  194. : Container()
  195. ],
  196. ),
  197. backgroundColor: Colors.black,
  198. /// if you use ExtendedImageSlidePage and slideType =SlideType.onlyImage,
  199. /// make sure your page is transparent background
  200. // color: Colors.white,
  201. // shadowColor: Colors.transparent,
  202. bottomNavigationBar: isMyself
  203. ? Container(
  204. decoration: BoxDecoration(
  205. color: Colors.white,
  206. border: Border(top: Constants.GreyBorderSide)),
  207. height: 40,
  208. child: Row(
  209. mainAxisAlignment: MainAxisAlignment.start,
  210. children: <Widget>[
  211. Checkbox(
  212. value: isAgree,
  213. activeColor: Colors.blue,
  214. onChanged: (bool val) {
  215. HttpUtil().setPhote(context, id, isAgree ? 0 : 1, () {
  216. this.setState(() {
  217. isAgree = !isAgree;
  218. //如果是红包照片焚阅照片则变成红包照片
  219. //如果是普通焚阅照片则变成普通照片
  220. MessageMgr().emit('refresh_photo');
  221. if (isAgree) {
  222. if (widget.pics[currentIndex].type ==
  223. PhotoType.free.index) {
  224. widget.pics[currentIndex].type =
  225. PhotoType.destroy.index;
  226. }
  227. if (widget.pics[currentIndex].type ==
  228. PhotoType.money.index) {
  229. widget.pics[currentIndex].type =
  230. PhotoType.destroyMoney.index;
  231. }
  232. } else {
  233. if (widget.pics[currentIndex].type ==
  234. PhotoType.destroy.index) {
  235. widget.pics[currentIndex].type =
  236. PhotoType.free.index;
  237. }
  238. if (widget.pics[currentIndex].type ==
  239. PhotoType.destroyMoney.index) {
  240. widget.pics[currentIndex].type =
  241. PhotoType.money.index;
  242. }
  243. }
  244. });
  245. });
  246. },
  247. ),
  248. fixedText(I18n.of(context).destroy_after)
  249. ],
  250. ),
  251. )
  252. : Container(
  253. height: 0,
  254. ),
  255. body: Stack(
  256. //fit: StackFit.expand,
  257. children: <Widget>[
  258. ExtendedImageGesturePageView.builder(
  259. itemBuilder: (BuildContext context, int index) {
  260. var item = widget.pics[index];
  261. var picUrl = item.picUrl;
  262. var file = item.file;
  263. var _timer;
  264. bool isShow = _seconds != 0;
  265. _cancelTimer() {
  266. item.isWatch = true;
  267. _seconds = 0;
  268. _timer?.cancel();
  269. }
  270. _startTimer() {
  271. if (UserData().isMan()) {
  272. _seconds =
  273. UserData().isSuperVip ? 6 : (UserData().isVip ? 4 : 2);
  274. } else {
  275. _seconds = UserData().basicInfo.isAttestation ? 6 : 2;
  276. }
  277. _timer =
  278. new Timer.periodic(new Duration(seconds: 1), (timer) {
  279. _seconds--;
  280. setState(() {});
  281. if (_seconds <= 0) {
  282. _cancelTimer();
  283. }
  284. });
  285. }
  286. Widget image;
  287. if (file != null) {
  288. image = ExtendedImage.file(
  289. file,
  290. fit: BoxFit.contain,
  291. //enableSlideOutPage: true,
  292. mode: ExtendedImageMode.gesture,
  293. initGestureConfigHandler: (state) {
  294. double initialScale = 1.0;
  295. if (state.extendedImageInfo != null &&
  296. state.extendedImageInfo.image != null) {
  297. initialScale = initScale(
  298. size: size,
  299. initialScale: initialScale,
  300. imageSize: Size(
  301. state.extendedImageInfo.image.width.toDouble(),
  302. state.extendedImageInfo.image.height
  303. .toDouble()));
  304. }
  305. return GestureConfig(
  306. inPageView: true,
  307. initialScale: initialScale,
  308. maxScale: max(initialScale, 5.0),
  309. initialAlignment: InitialAlignment.topCenter,
  310. animationMaxScale: max(initialScale, 5.0),
  311. //you can cache gesture state even though page view page change.
  312. //remember call clearGestureDetailsCache() method at the right time.(for example,this page dispose)
  313. cacheGesture: false);
  314. },
  315. onDoubleTap: (ExtendedImageGestureState state) {
  316. //you can use define pointerDownPosition as you can,
  317. //default value is double tap pointer down postion.
  318. var pointerDownPosition = state.pointerDownPosition;
  319. double begin = state.gestureDetails.totalScale;
  320. double end;
  321. //remove old
  322. _animation?.removeListener(animationListener);
  323. //stop pre
  324. _animationController.stop();
  325. //reset to use
  326. _animationController.reset();
  327. if (begin == doubleTapScales[0]) {
  328. end = doubleTapScales[1];
  329. } else {
  330. end = doubleTapScales[0];
  331. }
  332. animationListener = () {
  333. //print(_animation.value);
  334. state.handleDoubleTap(
  335. scale: _animation.value,
  336. doubleTapPosition: pointerDownPosition);
  337. };
  338. _animation = _animationController
  339. .drive(Tween<double>(begin: begin, end: end));
  340. _animation.addListener(animationListener);
  341. _animationController.forward();
  342. },
  343. );
  344. } else {
  345. image = ExtendedImage.network(
  346. picUrl,
  347. fit: BoxFit.contain,
  348. // enableSlideOutPage: true,
  349. mode: ExtendedImageMode.gesture,
  350. initGestureConfigHandler: (state) {
  351. double initialScale = 1.0;
  352. if (state.extendedImageInfo != null &&
  353. state.extendedImageInfo.image != null) {
  354. initialScale = initScale(
  355. size: size,
  356. initialScale: initialScale,
  357. imageSize: Size(
  358. state.extendedImageInfo.image.width.toDouble(),
  359. state.extendedImageInfo.image.height
  360. .toDouble()));
  361. }
  362. return GestureConfig(
  363. inPageView: true,
  364. initialScale: initialScale,
  365. maxScale: max(initialScale, 5.0),
  366. initialAlignment: InitialAlignment.topCenter,
  367. animationMaxScale: max(initialScale, 5.0),
  368. //you can cache gesture state even though page view page change.
  369. //remember call clearGestureDetailsCache() method at the right time.(for example,this page dispose)
  370. cacheGesture: false);
  371. },
  372. onDoubleTap: (ExtendedImageGestureState state) {
  373. //you can use define pointerDownPosition as you can,
  374. //default value is double tap pointer down postion.
  375. var pointerDownPosition = state.pointerDownPosition;
  376. double begin = state.gestureDetails.totalScale;
  377. double end;
  378. //remove old
  379. _animation?.removeListener(animationListener);
  380. //stop pre
  381. _animationController.stop();
  382. //reset to use
  383. _animationController.reset();
  384. if (begin == doubleTapScales[0]) {
  385. end = doubleTapScales[1];
  386. } else {
  387. end = doubleTapScales[0];
  388. }
  389. animationListener = () {
  390. //print(_animation.value);
  391. state.handleDoubleTap(
  392. scale: _animation.value,
  393. doubleTapPosition: pointerDownPosition);
  394. };
  395. _animation = _animationController
  396. .drive(Tween<double>(begin: begin, end: end));
  397. _animation.addListener(animationListener);
  398. _animationController.forward();
  399. },
  400. );
  401. }
  402. image = GestureDetector(
  403. child: Container(
  404. child: image,
  405. ),
  406. onTap: () {
  407. slidePagekey.currentState.popPage();
  408. Navigator.pop(context);
  409. },
  410. );
  411. //滤镜背景
  412. var bg = Center(
  413. child: ClipRect(
  414. //裁切长方形
  415. child: BackdropFilter(
  416. //背景滤镜器
  417. filter: ui.ImageFilter.blur(
  418. sigmaX: 20.0, sigmaY: 20.0), //图片模糊过滤,横向竖向都设置5.0
  419. child: Opacity(
  420. //透明控件
  421. opacity: 0.5,
  422. child: Container(
  423. alignment: Alignment.center,
  424. width: Screen.width,
  425. height: Screen.height,
  426. color: Colors.black,
  427. ),
  428. ),
  429. ),
  430. ),
  431. );
  432. //焚阅照片
  433. if ((item.type == PhotoType.destroy.index ||
  434. item.type == PhotoType.destroyMoney.index &&
  435. item.isBuy) &&
  436. item.userId != UserData().basicInfo.userId) {
  437. image = GestureDetector(
  438. onLongPress: item.isWatch
  439. ? null
  440. : () {
  441. browsePhoto(item.id, item.userId, 1, () {
  442. _startTimer();
  443. setState(() {});
  444. });
  445. },
  446. onLongPressEnd: item.isWatch
  447. ? null
  448. : (detail) {
  449. _cancelTimer();
  450. setState(() {});
  451. },
  452. onTap: () {
  453. slidePagekey.currentState.popPage();
  454. Navigator.pop(context);
  455. },
  456. child: Container(
  457. color: Colors.grey.shade200,
  458. child: Stack(
  459. alignment: Alignment.center,
  460. children: <Widget>[
  461. image,
  462. isShow
  463. ? Container()
  464. : Stack(
  465. alignment: Alignment.center,
  466. children: <Widget>[
  467. bg,
  468. item.isWatch
  469. ? Container(
  470. height: 211,
  471. width: 275.5,
  472. decoration: BoxDecoration(
  473. color: Colors.white,
  474. borderRadius:
  475. BorderRadius.all(
  476. Radius.circular(
  477. 5))),
  478. child: Column(
  479. mainAxisAlignment:
  480. MainAxisAlignment.center,
  481. children: <Widget>[
  482. Icon(
  483. IconData(
  484. 0xe634,
  485. fontFamily: 'iconfont',
  486. ),
  487. color: const Color(
  488. 0xFFA7A7A7),
  489. size: 50,
  490. ),
  491. fixedText(
  492. I18n.of(context)
  493. .destroyed,
  494. fontSize: 16,
  495. color: const Color(
  496. 0xFFA7A7A7)),
  497. UserData().isVip ||
  498. UserData()
  499. .basicInfo
  500. .sex ==
  501. 2
  502. ? Container()
  503. : fixedText(
  504. I18n.of(context)
  505. .longTime,
  506. color: Colors
  507. .grey[700],
  508. fontSize: 12),
  509. UserData().isVip ||
  510. UserData()
  511. .basicInfo
  512. .sex ==
  513. 2
  514. ? Container()
  515. : SizedBox(height: 10),
  516. UserData().isVip ||
  517. UserData()
  518. .basicInfo
  519. .sex ==
  520. 2
  521. ? Container()
  522. : RaisedButton(
  523. color: Colors.blue,
  524. onPressed: () {
  525. Navigator.of(
  526. context)
  527. .push(
  528. new MaterialPageRoute(
  529. builder:
  530. (context) {
  531. return VipPage();
  532. },
  533. ),
  534. );
  535. },
  536. child: fixedText(
  537. I18n.of(context)
  538. .joinvip,
  539. color: Colors
  540. .white),
  541. )
  542. ],
  543. ))
  544. : Container(
  545. height: 211,
  546. width: 275.5,
  547. decoration: BoxDecoration(
  548. color: Colors.white,
  549. borderRadius:
  550. BorderRadius.all(
  551. Radius.circular(
  552. 5))),
  553. child: Column(
  554. mainAxisAlignment:
  555. MainAxisAlignment.start,
  556. children: <Widget>[
  557. Padding(
  558. padding:
  559. EdgeInsets.only(
  560. top: 10,
  561. bottom: 2),
  562. child: Icon(
  563. IconData(
  564. 0xe634,
  565. fontFamily:
  566. 'iconfont',
  567. ),
  568. color: const Color(
  569. 0xFFF44236),
  570. size: 50,
  571. )),
  572. fixedText(
  573. I18n.of(context)
  574. .destroy_after,
  575. color: const Color(
  576. 0xFFF44236),
  577. fontSize: 15),
  578. Padding(
  579. padding: EdgeInsets.only(
  580. top: 25, bottom: 15),
  581. child: fixedText(
  582. I18n.of(context)
  583. .longClick,
  584. color: const Color(
  585. 0xFFFA8880),
  586. fontSize: 12),
  587. ),
  588. Image.asset(
  589. 'assets/images/zhiwen.png',
  590. height: 55,
  591. )
  592. ],
  593. ))
  594. ],
  595. )
  596. ],
  597. )));
  598. }
  599. //红包照片
  600. if ((item.type == PhotoType.money.index ||
  601. (item.type == PhotoType.destroyMoney.index &&
  602. !item.isBuy)) &&
  603. item.userId != UserData().basicInfo.userId) {
  604. image = GestureDetector(
  605. onTap: () {
  606. slidePagekey.currentState.popPage();
  607. Navigator.pop(context);
  608. },
  609. child: Container(
  610. color: Colors.grey.shade200,
  611. child: Stack(
  612. alignment: Alignment.center,
  613. children: <Widget>[
  614. image,
  615. item.isBuy
  616. ? Container()
  617. : Stack(
  618. alignment: Alignment.center,
  619. children: <Widget>[
  620. bg,
  621. Stack(
  622. alignment: Alignment.center,
  623. children: <Widget>[
  624. Image.asset(
  625. 'assets/images/login/money.png',
  626. fit: BoxFit.fitWidth,
  627. width: 220,
  628. ),
  629. Container(
  630. margin: EdgeInsets.only(top: 65),
  631. child: fixedText(
  632. I18n.of(context)
  633. .less_coin
  634. .replaceFirst(
  635. '/s1',
  636. UserData()
  637. .redPhotoPrice
  638. .toString()),
  639. color:
  640. const Color(0xFFFAE6B4),
  641. fontSize: 25),
  642. ),
  643. InkWell(
  644. onTap: () {
  645. CustomUI.buildOneConfirm(
  646. context,
  647. I18n.of(context)
  648. .pay_unlock
  649. .replaceFirst(
  650. '/s1',
  651. UserData()
  652. .redPhotoPrice
  653. .toString()),
  654. I18n.of(context)
  655. .confirm_pay, () {
  656. browsePhoto(
  657. item.id, item.userId, 2,
  658. () {
  659. setState(() {
  660. Navigator.of(context)
  661. .pop();
  662. MessageMgr().emit(
  663. 'refresh_photo',
  664. item.id);
  665. item.isBuy = true;
  666. });
  667. },
  668. price: UserData()
  669. .redPhotoPrice);
  670. });
  671. },
  672. child: Container(
  673. decoration: BoxDecoration(
  674. color: const Color(
  675. 0xFFFAE6B4),
  676. borderRadius:
  677. BorderRadius.all(
  678. Radius.circular(
  679. 30))),
  680. padding: EdgeInsets.only(
  681. left: 40,
  682. right: 40,
  683. top: 5,
  684. bottom: 5),
  685. margin:
  686. EdgeInsets.only(top: 140),
  687. child: fixedText(
  688. I18n.of(context)
  689. .determine,
  690. color: const Color(
  691. 0xFF7B0408)),
  692. ))
  693. ],
  694. )
  695. ],
  696. )
  697. ],
  698. )));
  699. }
  700. if (index == currentIndex) {
  701. return Hero(
  702. tag: picUrl + index.toString(),
  703. child: image,
  704. flightShuttleBuilder: (BuildContext flightContext,
  705. Animation<double> animation,
  706. HeroFlightDirection flightDirection,
  707. BuildContext fromHeroContext,
  708. BuildContext toHeroContext) {
  709. final Hero hero =
  710. flightDirection == HeroFlightDirection.pop
  711. ? fromHeroContext.widget
  712. : toHeroContext.widget;
  713. return hero.child;
  714. },
  715. );
  716. } else {
  717. return image;
  718. }
  719. },
  720. itemCount: widget.pics.length,
  721. onPageChanged: (int index) {
  722. currentIndex = index;
  723. rebuildIndex.add(index);
  724. },
  725. controller: PageController(
  726. initialPage: currentIndex,
  727. ),
  728. scrollDirection: Axis.horizontal,
  729. physics: BouncingScrollPhysics(),
  730. ),
  731. _seconds == 0
  732. ? Container()
  733. : Container(
  734. padding: EdgeInsets.only(bottom: 30),
  735. alignment: Alignment.bottomCenter,
  736. child: Stack(
  737. alignment: Alignment.center,
  738. children: <Widget>[
  739. CircularProgressIndicator(
  740. strokeWidth: 4.0,
  741. backgroundColor: Colors.grey,
  742. value: _seconds / 6,
  743. valueColor:
  744. new AlwaysStoppedAnimation<Color>(Colors.red),
  745. ),
  746. fixedText(_seconds.toString(), color: Colors.red)
  747. // Positioned(
  748. // top: 8,
  749. // left: 13,
  750. // child:
  751. // fixedText(_seconds.toString(), color: Colors.red),
  752. // )
  753. ],
  754. )),
  755. ],
  756. ));
  757. result = ExtendedImageSlidePage(
  758. key: slidePagekey,
  759. child: result,
  760. slideAxis: SlideAxis.both,
  761. slideType: SlideType.onlyImage,
  762. onSlidingPage: (state) {
  763. ///you can change other widgets' state on page as you want
  764. ///base on offset/isSliding etc
  765. //var offset= state.offset;
  766. var showSwiper = !state.isSliding;
  767. if (showSwiper != _showSwiper) {
  768. // do not setState directly here, the image state will change,
  769. // you should only notify the widgets which are needed to change
  770. // setState(() {
  771. // _showSwiper = showSwiper;
  772. // });
  773. _showSwiper = showSwiper;
  774. rebuildSwiper.add(_showSwiper);
  775. }
  776. },
  777. );
  778. return result;
  779. }
  780. }
  781. class MySwiperPlugin extends StatelessWidget {
  782. final List<PicSwiperItem> pics;
  783. final int index;
  784. final StreamController<int> reBuild;
  785. final bool isMyself;
  786. final callback;
  787. MySwiperPlugin(
  788. this.pics, this.index, this.reBuild, this.isMyself, this.callback);
  789. @override
  790. Widget build(BuildContext context) {
  791. return StreamBuilder<int>(
  792. builder: (BuildContext context, data) {
  793. return DefaultTextStyle(
  794. style: TextStyle(color: Colors.white),
  795. child: Container(
  796. //alignment: Alignment.center,
  797. height: 50.0,
  798. width: double.infinity,
  799. color: Colors.white,
  800. child: Row(
  801. children: <Widget>[
  802. InkWell(
  803. onTap: () {
  804. Navigator.of(context).pop();
  805. },
  806. child: Container(
  807. margin: EdgeInsets.only(left: 10),
  808. child: Icon(
  809. Icons.chevron_left,
  810. color: Constants.BlackTextColor,
  811. )),
  812. ),
  813. Expanded(
  814. child: Container(
  815. alignment: Alignment.center,
  816. child: fixedText("${data.data + 1} / ${pics.length}",
  817. color: Constants.BlackTextColor))),
  818. isMyself
  819. ? InkWell(
  820. onTap: () {
  821. CustomUI.buildOneConfirm(
  822. context,
  823. I18n.of(context).sure_delete,
  824. I18n.of(context).determine, () {
  825. callback(index);
  826. Navigator.of(context).pop();
  827. });
  828. },
  829. child: Container(
  830. margin: EdgeInsets.only(right: 10),
  831. child: Icon(
  832. Icons.delete,
  833. color: Constants.BlackTextColor,
  834. )),
  835. )
  836. : Container(),
  837. ],
  838. )),
  839. );
  840. },
  841. initialData: index,
  842. stream: reBuild.stream,
  843. );
  844. }
  845. }
  846. class PicSwiperItem {
  847. var userId;
  848. int id;
  849. String picUrl;
  850. String des;
  851. File file;
  852. int type;
  853. bool isBuy; //是否购买
  854. bool isWatch; //是否观看
  855. PicSwiperItem(
  856. this.picUrl, {
  857. this.file,
  858. this.id,
  859. this.des = "",
  860. this.type = 0,
  861. this.isBuy = false,
  862. this.isWatch = false,
  863. this.userId,
  864. });
  865. }