import 'dart:async'; import 'dart:convert'; import 'dart:math'; import 'package:address_picker/address_picker.dart'; import 'package:bbyyy/beans/ad_bean_entity.dart'; import 'package:bbyyy/beans/commodity_category_bean_entity.dart'; import 'package:bbyyy/beans/goods_bean_entity.dart'; import 'package:bbyyy/beans/home_carousel_bean_entity.dart'; import 'package:bbyyy/beans/my_shop_bean_entity.dart'; import 'package:bbyyy/beans/store_bean_entity.dart'; import 'package:bbyyy/https/MyDio.dart'; import 'package:bbyyy/https/my_request.dart'; import 'package:bbyyy/https/url.dart'; import 'package:bbyyy/my_tools/const.dart'; import 'package:bbyyy/my_tools/dims.dart'; import 'package:bbyyy/my_tools/event_bus.dart'; import 'package:bbyyy/my_tools/my_colors.dart'; import 'package:bbyyy/my_tools/my_cookie.dart'; import 'package:bbyyy/my_tools/my_tools.dart'; import 'package:bbyyy/my_tools/my_views.dart'; import 'package:bbyyy/paegs/home_page/recommended_today_page.dart'; import 'package:bbyyy/paegs/map_demo/map_demo_page.dart'; import 'package:bbyyy/paegs/root_page/root_page_view.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_swiper/flutter_swiper.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; class HomePage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State with AutomaticKeepAliveClientMixin { var data = []; var container = []; var puShop = []; var imgs = ['images/banner1.png', 'images/banner2.png', 'images/banner3.png']; var netImgs = []; int selectedIndex = 0; var tabs = ['全部']; var types = ['货帮', '货品']; List> sortItems = []; int typeIndex = 1; List shops = []; ScrollController _controller = ScrollController(); double maxH; double minH = 164; double H = 0; bool showInput = false; TextEditingController _description = TextEditingController(); FocusNode _descriptionFocus = FocusNode(); RefreshController _reController = RefreshController(initialRefresh: true); int page = 1; int pageIndex = 0; bool showS = false; String province; String city; Address _address; @override void initState() { super.initState(); EventBus().on('commodity_category', (arg) { setState(() {}); }); EventBus().on('uploadGoods', (arg) { _reController.requestRefresh(); }); EventBus().on('toTop', (arg) { _controller.animateTo(0.0, duration: Duration(milliseconds: 200), curve: Curves.easeIn); }); EventBus().on('homeCarousel', (arg) { if (arg is HomeCarouselBeanEntity) { arg.data.forEach((element) { netImgs.add(element.path); }); setState(() {}); } }); EventBus().on('商品变动', (arg) { _reController.requestRefresh(); }); EventBus().on('getLocation', (arg) { _reController.requestRefresh(); setState(() {}); }); _controller.addListener(() { setState(() { if (_controller.offset == 0) { RootPageView().toTop = false; EventBus().emit('ChangePage'); } else { RootPageView().toTop = true; EventBus().emit('ChangePage'); } H = maxH - _controller.offset; if (H < minH) { H = minH; } else if (H > maxH) { H = maxH; } }); }); types.forEach((element) { sortItems.add(DropdownMenuItem( child: Text( element, style: TextStyle(color: MyColors.c666666, fontSize: 14), ), value: element, )); }); _descriptionFocus.addListener(() { if (_descriptionFocus.hasFocus) { } else { if (_description.text.isEmpty) { showInput = false; } } }); homeCarousel(); } @override void dispose() { // TODO: implement dispose super.dispose(); EventBus().off('commodity_category'); EventBus().off('uploadGoods'); EventBus().off('toTop'); EventBus().off('homeCarousel'); EventBus().off('商品变动'); EventBus().off('getLocation'); } @override Widget build(BuildContext context) { maxH = MediaQuery.of(context).size.width * (520 / 750); minH = MediaQuery.of(context).padding.top + 64; if (H == 0) { H = maxH; } return GestureDetector( onTap: () { MyTools().hideKeyboard(context); }, behavior: HitTestBehavior.translucent, child: Scaffold( resizeToAvoidBottomInset: false, body: SmartRefresher( controller: _reController, onRefresh: onRefresh, onLoading: onLoading, enablePullDown: true, enablePullUp: true, child: CustomScrollView( slivers: [ carouselAndSearch(context), // recommendedToday(), storeCategory(), shopList() ], ), ), ), ); } Widget shopList() { return SliverList( delegate: SliverChildBuilderDelegate( (c, index) { return MyViews().pubShopItem(puShop[index], context); }, childCount: puShop.length, )); } Widget storeCategory() { return SliverPersistentHeader( pinned: true, //是否固定在顶部 floating: false, delegate: _SliverAppBarDelegate( minHeight: 54, maxHeight: 54, child: Column( children: [ Container( color: Colors.white, height: 53, child: ListView.builder( padding: EdgeInsets.only(left: 12, right: 12), itemBuilder: (c, index) { return GestureDetector( onTap: () { setState(() { selectedIndex = index; _reController.requestRefresh(); }); }, behavior: HitTestBehavior.translucent, child: Container( padding: EdgeInsets.only(right: 15, left: 15, bottom: 9), child: Column( children: [ Text( tabs[index], style: TextStyle( color: index == selectedIndex ? MyColors.cFF4233 : MyColors.c666666, fontSize: 14), ), Container( height: 10, child: Visibility( child: SvgPicture.asset('images/svg/tab.svg'), visible: index == selectedIndex, ), ) ], mainAxisAlignment: MainAxisAlignment.end, ), height: 53, ), ); }, itemCount: tabs.length, scrollDirection: Axis.horizontal, ), ), Container( height: 1, color: MyColors.cf2f2f2, ), ], ))); } Widget recommendedToday() { return SliverToBoxAdapter( child: Column( children: [ Container( padding: EdgeInsets.only(left: 16, right: 10), height: 54, child: Row( children: [ Text( '梆梆今日折扣', style: TextStyle(color: MyColors.c333333, fontSize: 14), ), GestureDetector( onTap: (){ MyTools().toPage(context, RecommendedTodayPage(), (then){}); }, behavior:HitTestBehavior.translucent, child: Row( children: [ Text( '查看更多', style: TextStyle(color: MyColors.c666666, fontSize: 12), ), Icon( Icons.chevron_right, color: MyColors.c666666, ) ], ), ) ], mainAxisAlignment: MainAxisAlignment.spaceBetween, ), ), Container( height: 1, color: MyColors.cf2f2f2, ), Container( height: 168, child: ListView.builder( padding: EdgeInsets.symmetric(horizontal: 16, vertical: 15), itemBuilder: (c, index) { return Container( margin: EdgeInsets.only(right: 10), height: 138, width: 100, padding: EdgeInsets.all(5), decoration: BoxDecoration( boxShadow: [ BoxShadow( color: MyColors.c7FE1E1E1, blurRadius: 5.0, ), ], color: Colors.white, borderRadius: BorderRadius.circular(4), ), child: Column( children: [ MyViews().netImg('', 90, 90, placeholder: 'images/svg/goodsDefImg.svg'), Text( '8.9元充10元话费', style: TextStyle(color: MyColors.c333333, fontSize: 11), maxLines: 1, overflow: TextOverflow.ellipsis, softWrap: true, ), Row( children: [ Text( '¥8.90', style: TextStyle( color: MyColors.cFF4233, fontSize: 13, fontWeight: FontWeight.bold), maxLines: 1, overflow: TextOverflow.ellipsis, softWrap: true, ), Container( decoration: BoxDecoration( border: Border.all(color: MyColors.cFF4233, width: 1), borderRadius: BorderRadius.circular(7), ), height: 14, width: 30, child: Text('详情',style: TextStyle(color: MyColors.cFF4233,fontSize: 9),), alignment: Alignment.center, ) ],mainAxisAlignment: MainAxisAlignment.spaceBetween, ) ],mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, ), ); }, itemCount: 10, scrollDirection: Axis.horizontal, ), ), ], ), ); } Widget carouselAndSearch(BuildContext context) { return SliverPersistentHeader( pinned: true, floating: false, delegate: _SliverAppBarDelegate( minHeight: minH, maxHeight: maxH, child: Stack( children: [ Swiper( itemBuilder: (BuildContext context, int index) { return netImgs.length == 0 ? GestureDetector( onTap: (){ // MyTools().toPage(context, MapDemoPage(), (then){}); }, child: Image.asset( "${imgs[index]}", fit: BoxFit.cover, ), ) : MyViews().netImg( imgURL(netImgs[index]), H, double.infinity, placeholder: 'images/svg/goodsDefImg.svg'); }, itemCount: netImgs.length == 0 ? imgs.length : netImgs.length, viewportFraction: 1, scale: 1, autoplay: true, ), SafeArea( bottom: false, child: Stack( children: [ Positioned( left: 0, child: Container( padding: EdgeInsets.only(left: 10, right: 10, top: 12), child: GestureDetector( onTap: () { addressSelection(); }, behavior: HitTestBehavior.translucent, child: Container( padding: EdgeInsets.only(left: 11, right: 14), decoration: BoxDecoration( boxShadow: [ BoxShadow( color: MyColors.c7FE1E1E1, blurRadius: 5.0, ), ], color: Colors.white, borderRadius: BorderRadius.circular(20)), child: Row( children: [ Icon( Icons.location_on_rounded, color: MyColors.c333333, size: 20, ), Text( province == null ? MyCookie().location != null ? MyCookie().location.city : '成都市' : city, style: TextStyle( color: MyColors.c333333, fontSize: 12, fontWeight: FontWeight.bold), ), ], ), height: 40, alignment: Alignment.center, ), ), alignment: Alignment.center, ), ), Positioned( top: 0, right: 0, child: Container( padding: EdgeInsets.only(left: 10, right: 10, top: 12), child: GestureDetector( onTap: () { showS = !showS; if (!showS) { _description.clear(); } setState(() {}); }, behavior: HitTestBehavior.translucent, child: AnimatedContainer( height: 40, width: !showS ? 40 : MediaQuery.of(context).size.width - 20, child: Row( children: [ SvgPicture.asset( showS ? 'images/svg/箭头.svg' : 'images/svg/搜索.svg', height: 15, width: 15, color: showS ? MyColors.cFF4233 : Colors.white, ), Visibility( visible: showS, child: Expanded( child: TextField( controller: _description, cursorColor: MyColors.cFF4233, cursorWidth: 1.0, onTap: () {}, decoration: InputDecoration( border: InputBorder.none, disabledBorder: InputBorder.none, enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, isDense: true, hintText: '请输入...', hintStyle: TextStyle( color: MyColors.c999999, fontSize: 16), contentPadding: const EdgeInsets.fromLTRB( 14, 4.5, 8, 4.5), ), maxLines: 1, style: TextStyle( color: MyColors.c333333, fontSize: 16, height: 1.3, letterSpacing: 0.2), keyboardType: TextInputType.text, onChanged: (t) { setState(() {}); }, ), ), ), Visibility( visible: showS && _description.text.isNotEmpty, child: GestureDetector( onTap: () { MyTools().hideKeyboard(context); _reController.requestRefresh(); }, behavior: HitTestBehavior.translucent, child: Container( child: MyViews() .myText('搜索', Colors.white, 13), decoration: BoxDecoration( color: MyColors.cFF4233, borderRadius: BorderRadius.circular(20), ), height: 40, width: 80, alignment: Alignment.center, ), ), ) ], mainAxisAlignment: MainAxisAlignment.center, ), alignment: !showS ? Alignment.center : Alignment.centerLeft, padding: EdgeInsets.only(left: !showS ? 0 : 12), decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(20)), color: showS ? Colors.white : MyColors.cFF4233, border: Border.all( width: 0.5, color: showS ? MyColors.cf2f2f2 : MyColors.cFF4233)), duration: Duration(milliseconds: 200), ), ), alignment: Alignment.centerRight, ), ), ], ), ), ], )), ); } @override // TODO: implement wantKeepAlive bool get wantKeepAlive => true; void getGoods(List shopUID) { var qData; if (shopUID.length == 0) { var conditions = ["public == true", "on_sale == true"]; if (selectedIndex != 0) { conditions.add("category == ${tabs[selectedIndex]}"); } if (_description.text.isNotEmpty) { conditions.add('title LIKE ${_description.text.toString()}'); } qData = { "key": "commodity", "filters": {"conditions": conditions}, "dims": commodityDims, "order_by": ["id,desc", "no,desc"], "paging": [page, 20] }; } else { var conditions = ["shop_uid in $shopUID", "on_sale == true"]; var conditions2 = ["public == true", "on_sale == true"]; if (selectedIndex != 0) { conditions.add("category == ${tabs[selectedIndex]}"); conditions2.add("category == ${tabs[selectedIndex]}"); } if (_description.text.isNotEmpty) { conditions.add('title LIKE ${_description.text.toString()}'); conditions2.add('title LIKE ${_description.text.toString()}'); } qData = { "key": "commodity", "filters": { "or": true, "conditions": conditions, "filters": [ {"conditions": conditions2} ] }, "order_by": ["id,desc", "no,desc"], "dims": commodityDims, "paging": [page, 20] }; } MyDio().query(qData, (response, hasError) { if (!hasError) { GoodsBeanEntity entity = GoodsBeanEntity().fromJson(json.decode(response.data.toString())); container.clear(); container.addAll(entity.data.data); } queryAd(); }, (error) { queryAd(); }); } void onRefresh() { page = 1; if (pageIndex == 1) { initTabs(); findAStore(); } else { storeType(); checkPublicStores(); } } void onLoading() { page++; if (pageIndex == 1) { findAStore(); } else { checkPublicStores(); } } Future initTabs() async { List commodityCategoryBeanData = []; MyDio().query({ "key": "commodity_category", "filters": {}, "dims": [ "name", ] }, (response, hasError) { if (!hasError) { try { CommodityCategoryBeanEntity entity = CommodityCategoryBeanEntity() .fromJson(json.decode(response.data.toString())); commodityCategoryBeanData = entity.data; tabs.clear(); tabs.add('全部'); commodityCategoryBeanData.forEach((element) { tabs.insert(1, element.name); }); if (selectedIndex > tabs.length - 1) { selectedIndex = 0; } setState(() {}); } catch (e) { tabs.clear(); tabs.add('全部'); if (selectedIndex > tabs.length - 1) { selectedIndex = 0; } } } else { return commodityCategoryBeanData; } }, (error) { return commodityCategoryBeanData; }); } findAStore() { MyDio().query({ "key": "shop_user", "filters": { "or": true, "conditions": [ "role!=$shopUserOwner", "user_uid==${MyCookie().getUID()}", "review_state==1" ], "filters": [ { "conditions": [ "role==$shopUserOwner", "user_uid==${MyCookie().getUID()}" ] } ] }, "dims": shopUserDims, "paging": [1, 20000] }, (response, hasError) { if (!hasError) { MyShopBeanEntity entity = MyShopBeanEntity().fromJson(json.decode(response.data.toString())); shops = entity.data.data; var shopUID = []; shops.forEach((element) { shopUID.add(element.shopUid); }); getGoods(shopUID); } }, (error) {}); } queryAd() { int count = 5; MyDio().query({ "key": "ad", "filters": { "conditions": ['on_show == true'] }, "dims": adDims, "order_by": ["id,desc", "no,desc"], "paging": [page, count] }, (response, hasError) { if (!hasError) { AdBeanEntity entity = AdBeanEntity().fromJson(json.decode(response.data.toString())); container.addAll(entity.data.data); container.shuffle(); } if (page == 1) { data.clear(); puShop.clear(); } if (pageIndex == 1) { data.addAll(container); } else { puShop.addAll(container); } setState(() {}); endRe(_reController); }, (error) { if (page == 1) { data.clear(); } data.addAll(container); setState(() {}); endRe(_reController); }); } void checkPublicStores() { var conditions = ['private==false', 'state == $shopStateNormal']; if (selectedIndex != 0) { conditions.add("category == ${tabs[selectedIndex]}"); } if (_description.text.isNotEmpty) { conditions.add('name LIKE ${_description.text.toString()}'); } if (MyCookie().location == null && province == null) { conditions.add('province == 四川省'); conditions.add('city == 成都市'); } else { if (province != null) { conditions.add('province == $province'); conditions.add('city == $city'); } else if (MyCookie().location != null) { conditions.add('province == ${MyCookie().location.province}'); conditions.add('city == ${MyCookie().location.city}'); } } MyDio().query({ "key": "shop", "filters": {"conditions": conditions}, "dims": shopDims, "order_by": ["id,desc", "no,desc"], "paging": [page, 20] }, (response, hasError) { if (!hasError) { StoreBeanEntity entity = StoreBeanEntity().fromJson(json.decode(response.data.toString())); container.clear(); container.addAll(entity.data.data); } queryAd(); }, (error) { queryAd(); }); } void storeType() { List commodityCategoryBeanData = []; MyDio().query({ "key": "shop_category", "filters": {}, "dims": [ "name", ] }, (response, hasError) { if (!hasError) { try { CommodityCategoryBeanEntity entity = CommodityCategoryBeanEntity() .fromJson(json.decode(response.data.toString())); commodityCategoryBeanData = entity.data; tabs.clear(); tabs.add('全部'); commodityCategoryBeanData.forEach((element) { tabs.insert(1, element.name); }); setState(() {}); } catch (e) { tabs.clear(); tabs.add('全部'); if (selectedIndex > tabs.length - 1) { selectedIndex = 0; } setState(() {}); } } }, (error) {}); } void addressSelection() { StateSetter ss; showModalBottomSheet( context: context, builder: (context) => BottomSheet( onClosing: () {}, builder: (context) => Container( height: 350, child: Column( children: [ StatefulBuilder( builder: (c, s) { ss = s; return Container( height: 40, color: Colors.white, padding: EdgeInsets.symmetric(horizontal: 15), child: Row( children: [ Row( children: [ Text( '定位到: ', style: TextStyle( color: MyColors.cFF4233, fontSize: 14), ), Text( _address == null ? '北京市 北京市' : '${_address.currentProvince.province} ${_address.currentCity.city}', style: TextStyle( color: MyColors.cFF4233, fontSize: 14), ), ], ), GestureDetector( child: Container( height: 40, width: 60, alignment: Alignment.center, child: Text( '确定', style: TextStyle( color: MyColors.cFF4233, fontSize: 16), ), ), onTap: () { if (_address == null) { province = '北京市'; city = '北京市'; setState(() {}); _reController.requestRefresh(); _address = null; Navigator.pop(context); } else { province = _address.currentProvince.province; city = _address.currentCity.city; setState(() {}); _reController.requestRefresh(); _address = null; Navigator.pop(context); } }, behavior: HitTestBehavior.translucent, ), ], mainAxisAlignment: MainAxisAlignment.spaceBetween, ), ); }, ), GestureDetector( onTap: () { if (MyCookie().location != null) { province = MyCookie().location.province; city = MyCookie().location.city; setState(() {}); _reController.requestRefresh(); _address = null; Navigator.pop(context); } }, behavior: HitTestBehavior.translucent, child: Container( height: 60, color: Colors.white, padding: EdgeInsets.symmetric(horizontal: 20), child: Row( children: [ Text( '当前定位:', style: TextStyle(color: MyColors.c333333, fontSize: 16), ), Text( MyCookie().location != null ? '${MyCookie().location.province} ${MyCookie().location.city}' : '请开启定位权限', style: TextStyle(color: MyColors.c333333, fontSize: 16), ) ], ), ), ), Container( height: 250.0, child: AddressPicker( style: TextStyle(color: Colors.black, fontSize: 17), mode: AddressPickerMode.provinceAndCity, onSelectedAddressChanged: (address) { _address = address; ss(() {}); }, ), ), ], ), ), ), ); } } class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { _SliverAppBarDelegate({ @required this.minHeight, @required this.maxHeight, @required this.child, }); final double minHeight; final double maxHeight; final Widget child; @override double get minExtent => minHeight; @override double get maxExtent => max(maxHeight, minHeight); @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent) { return new SizedBox.expand(child: child); } @override bool shouldRebuild(_SliverAppBarDelegate oldDelegate) { return maxHeight != oldDelegate.maxHeight || minHeight != oldDelegate.minHeight || child != oldDelegate.child; } }