home_page.dart 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. import 'dart:async';
  2. import 'dart:convert';
  3. import 'package:bbyyy/beans/ad_bean_entity.dart';
  4. import 'package:bbyyy/beans/commodity_category_bean_entity.dart';
  5. import 'package:bbyyy/beans/goods_bean_entity.dart';
  6. import 'package:bbyyy/beans/home_carousel_bean_entity.dart';
  7. import 'package:bbyyy/beans/my_shop_bean_entity.dart';
  8. import 'package:bbyyy/beans/store_bean_entity.dart';
  9. import 'package:bbyyy/https/MyDio.dart';
  10. import 'package:bbyyy/https/my_request.dart';
  11. import 'package:bbyyy/https/url.dart';
  12. import 'package:bbyyy/my_tools/const.dart';
  13. import 'package:bbyyy/my_tools/dims.dart';
  14. import 'package:bbyyy/my_tools/event_bus.dart';
  15. import 'package:bbyyy/my_tools/my_colors.dart';
  16. import 'package:bbyyy/my_tools/my_cookie.dart';
  17. import 'package:bbyyy/my_tools/my_tools.dart';
  18. import 'package:bbyyy/my_tools/my_views.dart';
  19. import 'package:bbyyy/paegs/root_page/root_page_view.dart';
  20. import 'package:flutter/cupertino.dart';
  21. import 'package:flutter/material.dart';
  22. import 'package:flutter_svg/flutter_svg.dart';
  23. import 'package:flutter_swiper/flutter_swiper.dart';
  24. import 'package:pull_to_refresh/pull_to_refresh.dart';
  25. class HomePage extends StatefulWidget {
  26. @override
  27. _HomePageState createState() => _HomePageState();
  28. }
  29. class _HomePageState extends State<HomePage>
  30. with AutomaticKeepAliveClientMixin {
  31. var data = [];
  32. var container = [];
  33. var puShop = [];
  34. var imgs = ['images/banner1.png', 'images/banner2.png', 'images/banner3.png'];
  35. var netImgs = [];
  36. int selectedIndex = 0;
  37. var tabs = ['全部'];
  38. var types = ['货帮', '货品'];
  39. List<DropdownMenuItem<String>> sortItems = [];
  40. int typeIndex = 1;
  41. List<MyShopBeanDataData> shops = [];
  42. ScrollController _controller = ScrollController();
  43. double maxH;
  44. double minH = 164;
  45. double H = 0;
  46. bool showInput = false;
  47. TextEditingController _description = TextEditingController();
  48. FocusNode _descriptionFocus = FocusNode();
  49. RefreshController _reController = RefreshController(initialRefresh: true);
  50. int page = 1;
  51. int pageIndex = 0;
  52. bool showS = false;
  53. @override
  54. void initState() {
  55. super.initState();
  56. EventBus().on('commodity_category', (arg) {
  57. setState(() {});
  58. });
  59. EventBus().on('uploadGoods', (arg) {
  60. _reController.requestRefresh();
  61. });
  62. EventBus().on('toTop', (arg) {
  63. _controller.animateTo(0.0,
  64. duration: Duration(milliseconds: 200), curve: Curves.easeIn);
  65. });
  66. EventBus().on('homeCarousel', (arg) {
  67. if (arg is HomeCarouselBeanEntity) {
  68. arg.data.forEach((element) {
  69. netImgs.add(element.path);
  70. });
  71. setState(() {});
  72. }
  73. });
  74. EventBus().on('商品变动', (arg) {
  75. _reController.requestRefresh();
  76. });
  77. _controller.addListener(() {
  78. setState(() {
  79. if (_controller.offset == 0) {
  80. RootPageView().toTop = false;
  81. EventBus().emit('ChangePage');
  82. } else {
  83. RootPageView().toTop = true;
  84. EventBus().emit('ChangePage');
  85. }
  86. H = maxH - _controller.offset;
  87. if (H < minH) {
  88. H = minH;
  89. } else if (H > maxH) {
  90. H = maxH;
  91. }
  92. });
  93. });
  94. types.forEach((element) {
  95. sortItems.add(DropdownMenuItem(
  96. child: Text(
  97. element,
  98. style: TextStyle(color: MyColors.c666666, fontSize: 14),
  99. ),
  100. value: element,
  101. ));
  102. });
  103. _descriptionFocus.addListener(() {
  104. if (_descriptionFocus.hasFocus) {
  105. } else {
  106. if (_description.text.isEmpty) {
  107. showInput = false;
  108. }
  109. }
  110. });
  111. homeCarousel();
  112. }
  113. @override
  114. void dispose() {
  115. // TODO: implement dispose
  116. super.dispose();
  117. EventBus().off('commodity_category');
  118. EventBus().off('uploadGoods');
  119. EventBus().off('toTop');
  120. EventBus().off('homeCarousel');
  121. EventBus().off('商品变动');
  122. }
  123. @override
  124. Widget build(BuildContext context) {
  125. maxH = MediaQuery.of(context).size.width * (520 / 750);
  126. minH = MediaQuery.of(context).padding.top + 64;
  127. if (H == 0) {
  128. H = maxH;
  129. }
  130. return GestureDetector(
  131. onTap: () {
  132. MyTools().hideKeyboard(context);
  133. },
  134. behavior: HitTestBehavior.translucent,
  135. child: Scaffold(
  136. resizeToAvoidBottomInset: false,
  137. body: Column(
  138. children: [
  139. Stack(
  140. children: [
  141. AnimatedContainer(
  142. height: H,
  143. duration: Duration(milliseconds: 200),
  144. child: Swiper(
  145. itemBuilder: (BuildContext context, int index) {
  146. return netImgs.length == 0
  147. ? Image.asset(
  148. "${imgs[index]}",
  149. fit: BoxFit.cover,
  150. )
  151. : MyViews().netImg(
  152. imgURL(netImgs[index]), H, double.infinity,
  153. placeholder: 'images/svg/goodsDefImg.svg');
  154. },
  155. itemCount:
  156. netImgs.length == 0 ? imgs.length : netImgs.length,
  157. viewportFraction: 1,
  158. scale: 1,
  159. autoplay: true,
  160. ),
  161. ),
  162. SafeArea(
  163. bottom: false,
  164. child: Stack(
  165. children: [
  166. AnimatedOpacity(
  167. duration: Duration(milliseconds: 200),
  168. opacity: showS ? 0.0 : 1.0,
  169. child: Container(
  170. margin: EdgeInsets.only(top: 18),
  171. width: double.infinity,
  172. child: Row(
  173. children: [
  174. GestureDetector(
  175. onTap: () {
  176. setState(() {
  177. pageIndex = 0;
  178. _reController.requestRefresh();
  179. });
  180. },
  181. behavior: HitTestBehavior.translucent,
  182. child: Container(
  183. height: 28,
  184. width: 60,
  185. alignment: Alignment.center,
  186. child: Column(
  187. children: [
  188. Text(
  189. '货帮',
  190. style: TextStyle(
  191. color: pageIndex == 0
  192. ? MyColors.cFF4233
  193. : MyColors.c333333,
  194. fontSize: 16,
  195. fontWeight: FontWeight.bold),
  196. ),
  197. Visibility(
  198. child: Container(
  199. width: 32,
  200. height: 2,
  201. decoration: BoxDecoration(
  202. color: MyColors.cFF4233,
  203. borderRadius:
  204. BorderRadius.circular(1)),
  205. ),
  206. visible: pageIndex == 0,
  207. ),
  208. ],
  209. ),
  210. ),
  211. ),
  212. Container(
  213. width: 40,
  214. ),
  215. GestureDetector(
  216. onTap: () {
  217. setState(() {
  218. pageIndex = 1;
  219. _reController.requestRefresh();
  220. });
  221. },
  222. behavior: HitTestBehavior.translucent,
  223. child: Container(
  224. height: 28,
  225. width: 60,
  226. alignment: Alignment.center,
  227. child: Column(
  228. children: [
  229. Text(
  230. '商品',
  231. style: TextStyle(
  232. color: pageIndex == 1
  233. ? MyColors.cFF4233
  234. : MyColors.c333333,
  235. fontSize: 16,
  236. fontWeight: FontWeight.bold),
  237. ),
  238. Visibility(
  239. child: Container(
  240. width: 32,
  241. height: 2,
  242. decoration: BoxDecoration(
  243. color: MyColors.cFF4233,
  244. borderRadius:
  245. BorderRadius.circular(1)),
  246. ),
  247. visible: pageIndex == 1,
  248. ),
  249. ],
  250. ),
  251. ),
  252. ),
  253. ],
  254. mainAxisAlignment: MainAxisAlignment.center,
  255. ),
  256. ),
  257. ),
  258. Container(
  259. padding: EdgeInsets.only(left: 10, right: 10, top: 12),
  260. child: GestureDetector(
  261. onTap: () {
  262. showS = !showS;
  263. if (!showS) {
  264. _description.clear();
  265. }
  266. setState(() {});
  267. },
  268. behavior: HitTestBehavior.translucent,
  269. child: AnimatedContainer(
  270. height: 40,
  271. width:
  272. !showS ? 40 : MediaQuery.of(context).size.width,
  273. child: Row(
  274. children: [
  275. SvgPicture.asset(
  276. showS
  277. ? 'images/svg/箭头.svg'
  278. : 'images/svg/搜索.svg',
  279. height: 15,
  280. width: 15,
  281. color:
  282. showS ? MyColors.cFF4233 : Colors.white,
  283. ),
  284. Visibility(
  285. visible: showS,
  286. child: Expanded(
  287. child: TextField(
  288. controller: _description,
  289. cursorColor: MyColors.cFF4233,
  290. cursorWidth: 1.0,
  291. onTap: () {},
  292. decoration: InputDecoration(
  293. border: InputBorder.none,
  294. disabledBorder: InputBorder.none,
  295. enabledBorder: InputBorder.none,
  296. focusedBorder: InputBorder.none,
  297. isDense: true,
  298. hintText: '请输入...',
  299. hintStyle: TextStyle(
  300. color: MyColors.c999999,
  301. fontSize: 16),
  302. contentPadding:
  303. const EdgeInsets.fromLTRB(
  304. 14, 4.5, 8, 4.5),
  305. ),
  306. maxLines: 1,
  307. style: TextStyle(
  308. color: MyColors.c333333,
  309. fontSize: 16,
  310. height: 1.3,
  311. letterSpacing: 0.2),
  312. keyboardType: TextInputType.text,
  313. onChanged: (t) {
  314. setState(() {});
  315. },
  316. ),
  317. ),
  318. ),
  319. Visibility(
  320. visible:
  321. showS && _description.text.isNotEmpty,
  322. child: GestureDetector(
  323. onTap: () {
  324. MyTools().hideKeyboard(context);
  325. _reController.requestRefresh();
  326. },
  327. behavior: HitTestBehavior.translucent,
  328. child: Container(
  329. child: MyViews()
  330. .myText('搜索', Colors.white, 13),
  331. decoration: BoxDecoration(
  332. color: MyColors.cFF4233,
  333. borderRadius: BorderRadius.circular(20),
  334. ),
  335. height: 40,
  336. width: 80,
  337. alignment: Alignment.center,
  338. ),
  339. ),
  340. )
  341. ],
  342. mainAxisAlignment: MainAxisAlignment.center,
  343. ),
  344. alignment: !showS
  345. ? Alignment.center
  346. : Alignment.centerLeft,
  347. padding: EdgeInsets.only(left: !showS ? 0 : 12),
  348. decoration: BoxDecoration(
  349. borderRadius:
  350. BorderRadius.all(Radius.circular(20)),
  351. color: showS ? Colors.white : MyColors.cFF4233),
  352. duration: Duration(milliseconds: 200),
  353. ),
  354. ),
  355. alignment: Alignment.centerRight,
  356. ),
  357. ],
  358. ),
  359. ),
  360. ],
  361. ),
  362. Column(
  363. children: [
  364. Container(
  365. height: 53,
  366. child: ListView.builder(
  367. padding: EdgeInsets.only(left: 12, right: 12),
  368. itemBuilder: (c, index) {
  369. return GestureDetector(
  370. onTap: () {
  371. setState(() {
  372. selectedIndex = index;
  373. _reController.requestRefresh();
  374. });
  375. },
  376. behavior: HitTestBehavior.translucent,
  377. child: Container(
  378. padding:
  379. EdgeInsets.only(right: 15, left: 15, bottom: 9),
  380. child: Column(
  381. children: [
  382. Text(
  383. tabs[index],
  384. style: TextStyle(
  385. color: index == selectedIndex
  386. ? MyColors.cFF4233
  387. : MyColors.c666666,
  388. fontSize: 14),
  389. ),
  390. Container(
  391. height: 10,
  392. child: Visibility(
  393. child: SvgPicture.asset('images/svg/tab.svg'),
  394. visible: index == selectedIndex,
  395. ),
  396. )
  397. ],
  398. mainAxisAlignment: MainAxisAlignment.end,
  399. ),
  400. height: 53,
  401. ),
  402. );
  403. },
  404. itemCount: tabs.length,
  405. scrollDirection: Axis.horizontal,
  406. ),
  407. ),
  408. Container(
  409. height: 1,
  410. color: MyColors.cf2f2f2,
  411. ),
  412. ],
  413. ),
  414. Expanded(
  415. flex: 1,
  416. child: SmartRefresher(
  417. controller: _reController,
  418. onRefresh: onRefresh,
  419. onLoading: onLoading,
  420. enablePullDown: true,
  421. enablePullUp: true,
  422. child: body(),
  423. ),
  424. )
  425. ],
  426. ),
  427. ),
  428. );
  429. }
  430. @override
  431. // TODO: implement wantKeepAlive
  432. bool get wantKeepAlive => true;
  433. void getGoods(List<dynamic> shopUID) {
  434. var qData;
  435. if (shopUID.length == 0) {
  436. var conditions = ["public == true", "on_sale == true"];
  437. if (selectedIndex != 0) {
  438. conditions.add("category == ${tabs[selectedIndex]}");
  439. }
  440. if (_description.text.isNotEmpty) {
  441. conditions.add('title LIKE ${_description.text.toString()}');
  442. }
  443. qData = {
  444. "key": "commodity",
  445. "filters": {"conditions": conditions},
  446. "dims": commodityDims,
  447. "paging": [page, 20]
  448. };
  449. } else {
  450. var conditions = ["shop_uid in $shopUID", "on_sale == true"];
  451. var conditions2 = ["public == true", "on_sale == true"];
  452. if (selectedIndex != 0) {
  453. conditions.add("category == ${tabs[selectedIndex]}");
  454. conditions2.add("category == ${tabs[selectedIndex]}");
  455. }
  456. if (_description.text.isNotEmpty) {
  457. conditions.add('title LIKE ${_description.text.toString()}');
  458. conditions2.add('title LIKE ${_description.text.toString()}');
  459. }
  460. qData = {
  461. "key": "commodity",
  462. "filters": {
  463. "or": true,
  464. "conditions": conditions,
  465. "filters": [
  466. {"conditions": conditions2}
  467. ]
  468. },
  469. "dims": commodityDims,
  470. "paging": [page, 20]
  471. };
  472. }
  473. MyDio().query(qData, (response, hasError) {
  474. if (!hasError) {
  475. GoodsBeanEntity entity =
  476. GoodsBeanEntity().fromJson(json.decode(response.data.toString()));
  477. container.clear();
  478. container.addAll(entity.data.data);
  479. }
  480. queryAd();
  481. }, (error) {
  482. queryAd();
  483. });
  484. }
  485. void onRefresh() {
  486. page = 1;
  487. if (pageIndex == 1) {
  488. initTabs();
  489. findAStore();
  490. } else {
  491. storeType();
  492. checkPublicStores();
  493. }
  494. }
  495. void onLoading() {
  496. page++;
  497. if (pageIndex == 1) {
  498. findAStore();
  499. } else {
  500. checkPublicStores();
  501. }
  502. }
  503. Future<void> initTabs() async {
  504. List<CommodityCategoryBeanData> commodityCategoryBeanData = [];
  505. MyDio().query({
  506. "key": "commodity_category",
  507. "filters": {},
  508. "dims": [
  509. "name",
  510. ]
  511. }, (response, hasError) {
  512. if (!hasError) {
  513. CommodityCategoryBeanEntity entity = CommodityCategoryBeanEntity()
  514. .fromJson(json.decode(response.data.toString()));
  515. commodityCategoryBeanData = entity.data;
  516. tabs.clear();
  517. tabs.add('全部');
  518. commodityCategoryBeanData.forEach((element) {
  519. tabs.insert(1, element.name);
  520. });
  521. setState(() {});
  522. } else {
  523. return commodityCategoryBeanData;
  524. }
  525. }, (error) {
  526. return commodityCategoryBeanData;
  527. });
  528. }
  529. findAStore() {
  530. MyDio().query({
  531. "key": "shop_user",
  532. "filters": {
  533. "or": true,
  534. "conditions": [
  535. "role!=$shopUserOwner",
  536. "user_uid==${MyCookie().getUID()}",
  537. "review_state==1"
  538. ],
  539. "filters": [
  540. {
  541. "conditions": [
  542. "role==$shopUserOwner",
  543. "user_uid==${MyCookie().getUID()}"
  544. ]
  545. }
  546. ]
  547. },
  548. "dims": shopUserDims,
  549. "paging": [1, 20000]
  550. }, (response, hasError) {
  551. if (!hasError) {
  552. MyShopBeanEntity entity =
  553. MyShopBeanEntity().fromJson(json.decode(response.data.toString()));
  554. shops = entity.data.data;
  555. var shopUID = [];
  556. shops.forEach((element) {
  557. shopUID.add(element.shopUid);
  558. });
  559. getGoods(shopUID);
  560. }
  561. }, (error) {});
  562. }
  563. queryAd() {
  564. MyDio().query({
  565. "key": "ad",
  566. "filters": {
  567. "conditions": ['on_show == true']
  568. },
  569. "dims": adDims,
  570. "paging": [page, 2]
  571. }, (response, hasError) {
  572. if (!hasError) {
  573. AdBeanEntity entity =
  574. AdBeanEntity().fromJson(json.decode(response.data.toString()));
  575. container.addAll(entity.data.data);
  576. container.shuffle();
  577. }
  578. if (page == 1) {
  579. data.clear();
  580. puShop.clear();
  581. }
  582. if (pageIndex == 1) {
  583. data.addAll(container);
  584. } else {
  585. puShop.addAll(container);
  586. }
  587. setState(() {});
  588. endRe(_reController);
  589. }, (error) {
  590. if (page == 1) {
  591. data.clear();
  592. }
  593. data.addAll(container);
  594. setState(() {});
  595. endRe(_reController);
  596. });
  597. }
  598. void checkPublicStores() {
  599. var conditions = ['private==false', 'state == $shopStateNormal'];
  600. if (selectedIndex != 0) {
  601. conditions.add("category == ${tabs[selectedIndex]}");
  602. }
  603. if (_description.text.isNotEmpty) {
  604. conditions.add('name LIKE ${_description.text.toString()}');
  605. }
  606. MyDio().query({
  607. "key": "shop",
  608. "filters": {"conditions": conditions},
  609. "dims": shopDims,
  610. "paging": [page, 20]
  611. }, (response, hasError) {
  612. if (!hasError) {
  613. StoreBeanEntity entity =
  614. StoreBeanEntity().fromJson(json.decode(response.data.toString()));
  615. container.clear();
  616. container.addAll(entity.data.data);
  617. }
  618. queryAd();
  619. }, (error) {
  620. queryAd();
  621. });
  622. }
  623. void storeType() {
  624. List<CommodityCategoryBeanData> commodityCategoryBeanData = [];
  625. MyDio().query({
  626. "key": "shop_category",
  627. "filters": {},
  628. "dims": [
  629. "name",
  630. ]
  631. }, (response, hasError) {
  632. if (!hasError) {
  633. CommodityCategoryBeanEntity entity = CommodityCategoryBeanEntity()
  634. .fromJson(json.decode(response.data.toString()));
  635. commodityCategoryBeanData = entity.data;
  636. tabs.clear();
  637. tabs.add('全部');
  638. commodityCategoryBeanData.forEach((element) {
  639. tabs.insert(1, element.name);
  640. });
  641. setState(() {});
  642. }
  643. }, (error) {});
  644. }
  645. body() {
  646. if (pageIndex == 1) {
  647. return body1();
  648. } else if (pageIndex == 0) {
  649. return body2();
  650. }
  651. }
  652. body1() {
  653. if (data.length == 0) {
  654. return SingleChildScrollView(child: noData());
  655. } else {
  656. return GridView.builder(
  657. controller: _controller,
  658. gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
  659. crossAxisCount: 2,
  660. childAspectRatio: 164 / 261,
  661. mainAxisSpacing: 8,
  662. crossAxisSpacing: 8),
  663. itemCount: data.length,
  664. padding: EdgeInsets.only(left: 14, right: 14, top: 14, bottom: 65),
  665. itemBuilder: (context, index) {
  666. return MyViews().getGoodsItem(data[index], context);
  667. });
  668. }
  669. }
  670. body2() {
  671. if (puShop.length == 0) {
  672. return SingleChildScrollView(child: noData());
  673. } else {
  674. return ListView.builder(
  675. controller: _controller,
  676. itemBuilder: (BuildContext context, int index) {
  677. return MyViews().pubShopItem(puShop[index], context);
  678. },
  679. itemCount: puShop.length,
  680. padding: EdgeInsets.all(10),
  681. );
  682. }
  683. }
  684. }