home.dart 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. import 'package:bot_toast/bot_toast.dart';
  2. import 'package:cached_network_image/cached_network_image.dart';
  3. import 'package:color_thief_flutter/color_thief_flutter.dart';
  4. import 'package:flutter/cupertino.dart';
  5. import 'package:flutter/material.dart';
  6. import 'package:flutter_app_upgrade/flutter_app_upgrade.dart';
  7. import 'package:flutter_easyrefresh/easy_refresh.dart';
  8. import 'package:flutter_swiper/flutter_swiper.dart';
  9. import 'package:package_info/package_info.dart';
  10. import 'package:provider/provider.dart';
  11. import 'package:twong/api/index.dart';
  12. import 'package:twong/providers/home_model.dart';
  13. import 'package:twong/router/index.dart';
  14. import 'package:twong/config/style.dart';
  15. import 'package:twong/models/index.dart';
  16. import 'package:twong/utils/image_utils.dart';
  17. import 'package:twong/utils/index.dart';
  18. import 'package:twong/widgets/future_widget.dart';
  19. import 'package:twong/widgets/search_bar.dart';
  20. import 'package:twong/widgets/sliver_bar.dart';
  21. import 'package:twong/widgets/product_item.dart';
  22. class HomePage extends StatefulWidget {
  23. @override
  24. State<StatefulWidget> createState() {
  25. return _HomePageState();
  26. }
  27. }
  28. class _HomePageState extends State<HomePage> {
  29. Home _data;
  30. bool _checkColor = true;
  31. Color headerColor = Colors.red;
  32. ScrollController _controller = ScrollController();
  33. @override
  34. initState() {
  35. super.initState();
  36. initData();
  37. _controller.addListener(_onScroll);
  38. }
  39. initData() async {
  40. _data = Cache.get(SaveKey.home);
  41. Network.inst.getIndex().then((data) {
  42. if(!mounted) return;
  43. setState(() {
  44. _data = data;
  45. });
  46. Cache.set(SaveKey.home, _data);
  47. }).catchError((err) {
  48. print(err);
  49. });
  50. }
  51. _onSwipeChange(int index) async {
  52. if (!_checkColor) return;
  53. // todo 测试数据
  54. var colors = <Color>[ Colors.red, Colors.green ];
  55. getColorFromUrl(_data.banner[index].pic).then((color) {
  56. setState(() {
  57. headerColor = colors[index];
  58. });
  59. });
  60. }
  61. Widget _buildSlider (BuildContext context, int index) {
  62. var banner = _data.banner[index];
  63. return CachedNetworkImage(
  64. fit: BoxFit.cover,
  65. imageUrl: banner.pic,
  66. imageBuilder: (BuildContext context, ImageProvider<dynamic> provider) {
  67. return GestureDetector(
  68. onTap: () {
  69. var id = banner.url.split("/")[2];
  70. Navigator.pushNamed(context, RouteNames.productDetails, arguments: id);
  71. },
  72. child: Container(
  73. decoration: BoxDecoration(
  74. borderRadius: BorderRadius.circular(4.px),
  75. image: DecorationImage(
  76. image: provider,
  77. fit: BoxFit.cover
  78. ),
  79. ),
  80. ),
  81. );
  82. },
  83. placeholder: (BuildContext context, String str) {
  84. return Center(child: CircularProgressIndicator());
  85. },
  86. );
  87. }
  88. Widget _buildCate () {
  89. var buildBox = (String uri) {
  90. if (uri == null) {
  91. return Container(
  92. margin: EdgeInsets.all(4),
  93. decoration: BoxDecoration(
  94. color: Colors.white,
  95. borderRadius: BorderRadius.circular(3),
  96. ),
  97. );
  98. }
  99. return InkWell(
  100. onTap: () {},
  101. child: Container(
  102. margin: EdgeInsets.all(4),
  103. decoration: BoxDecoration(
  104. borderRadius: BorderRadius.circular(3),
  105. image: DecorationImage(image: CachedNetworkImageProvider(uri), fit: BoxFit.cover),
  106. ),
  107. ),
  108. );
  109. };
  110. return Row(
  111. children: <Widget>[
  112. Expanded(flex: 4, child: buildBox(null)),
  113. Expanded(flex: 6, child: Column(
  114. children: <Widget>[
  115. Expanded( child: buildBox(null)),
  116. Expanded( child: buildBox(null))
  117. ],
  118. ))
  119. ],
  120. );
  121. }
  122. Widget _buildNews () {
  123. return Container(
  124. alignment: Alignment.center,
  125. child: Text("新闻资讯"),
  126. );
  127. }
  128. Widget _buildProducts () {
  129. if (_data.info.firstList.length > 0) {
  130. return SliverList(
  131. delegate: SliverChildBuilderDelegate((context, index) =>
  132. ProductItem(index, _data?.info?.firstList),
  133. childCount: _data.info.firstList.length),
  134. );
  135. } else {
  136. return SliverToBoxAdapter(
  137. child: Container(
  138. alignment: Alignment.center,
  139. child: Text("暂时没有数据"),
  140. ),
  141. );
  142. }
  143. }
  144. Widget _buildMenu() {
  145. var widgets = List<Widget>();
  146. for(var item in _data.menus) {
  147. widgets.add(Expanded(
  148. child: GestureDetector(
  149. onTap: () { Navigator.pushNamed(context, item.url); },
  150. child: Container(
  151. alignment: Alignment.center,
  152. margin: EdgeInsets.all(10.px),
  153. child: Column(
  154. mainAxisAlignment: MainAxisAlignment.center,
  155. children: [
  156. Expanded(child: Container(
  157. width: 40.px,
  158. margin: EdgeInsets.only(bottom: 4.px),
  159. decoration: BoxDecoration(
  160. image: DecorationImage(image: CachedNetworkImageProvider(item.pic), fit: BoxFit.cover),
  161. borderRadius: BorderRadius.circular(10.px),
  162. ),
  163. )),
  164. Text(item.name, style: TextStyle(fontSize: 11.px),)
  165. ],
  166. ),
  167. ))
  168. ));
  169. }
  170. var isVip = Cache.user != null && Cache.user.vip_level > 1;
  171. widgets.add(Expanded(
  172. child: GestureDetector(
  173. onTap: () { Navigator.pushNamed(context, "user"); },
  174. child: Container(
  175. alignment: Alignment.center,
  176. margin: EdgeInsets.all(10.px),
  177. child: Column(
  178. mainAxisAlignment: MainAxisAlignment.center,
  179. children: [
  180. Expanded(child: Container(
  181. width: 40.px,
  182. margin: EdgeInsets.only(bottom: 4.px),
  183. decoration: BoxDecoration(
  184. // image: DecorationImage(image: CachedNetworkImageProvider(""), fit: BoxFit.cover),
  185. borderRadius: BorderRadius.circular(10.px),
  186. ),
  187. )),
  188. Text(isVip ? "会员中心" : "用户中心", style: TextStyle(fontSize: 11.px),)
  189. ],
  190. ),
  191. ))
  192. ));
  193. return SliverToBoxAdapter(
  194. child: Container(
  195. height: 80.px,
  196. color: Colors.white,
  197. margin: EdgeInsets.all(6.px),
  198. child: Row(
  199. children: widgets,
  200. ),
  201. )
  202. );
  203. }
  204. List<Widget> _buildDataList() {
  205. return <Widget>[
  206. SliverToBoxAdapter(
  207. child: Container(
  208. height: 150.px,
  209. decoration: BoxDecoration(
  210. gradient: LinearGradient(
  211. begin: Alignment.topCenter,
  212. end: Alignment.bottomCenter,
  213. colors: [headerColor, DColors.back],
  214. ),
  215. ),
  216. padding: EdgeInsets.only(left: 6.px, right: 6.px),
  217. child: Swiper(
  218. scale: 0.9,
  219. autoplay: true,
  220. itemBuilder: _buildSlider,
  221. itemCount: _data.banner.length,
  222. onIndexChanged: _onSwipeChange,
  223. pagination: SwiperPagination(),
  224. autoplayDisableOnInteraction: true,
  225. )
  226. )
  227. ),
  228. _buildMenu(),
  229. SliverToBoxAdapter(
  230. child: Container(
  231. height: 150.px,
  232. child: _buildCate()
  233. ),
  234. ),
  235. SliverToBoxAdapter(
  236. child: Container(
  237. height: 40.px,
  238. color: Colors.white,
  239. margin: EdgeInsets.all(6.px),
  240. child: _buildNews()
  241. ),
  242. ),
  243. SliverBar(),
  244. SliverPadding(
  245. padding: EdgeInsets.all(6.px),
  246. sliver: _buildProducts()
  247. )
  248. ];
  249. }
  250. _buildNoData() {
  251. return <Widget>[
  252. SliverToBoxAdapter(
  253. child: Container(
  254. height: 300.px,
  255. child: Center(child: CircularProgressIndicator())
  256. ))
  257. ];
  258. }
  259. _buildBody() {
  260. // var headerColor = Provider.of<HomeModel>(context, listen: false).headerColor;
  261. return EasyRefresh.custom(
  262. onRefresh: _onRefresh,
  263. onLoad: _onLoad,
  264. bottomBouncing: true,
  265. scrollController: _controller,
  266. footer: BallPulseFooter(color: DColors.Main),
  267. header: BallPulseHeader(backgroundColor: headerColor, color: Colors.white),
  268. slivers: _data == null ? _buildNoData() : _buildDataList(),
  269. );
  270. }
  271. Future _onLoad() async {
  272. Log.i("home list load more...");
  273. return await Network.inst.getIndex().then((data){
  274. if(!mounted) return;
  275. _data = data;
  276. setState(() {
  277. _data.info.firstList.addAll(data.info.firstList.toList());
  278. });
  279. }).catchError((err) {});
  280. }
  281. Future _onRefresh() async {
  282. Log.i("refresh home");
  283. return await Network.inst.getIndex().then((data){
  284. if(!mounted) return;
  285. setState(() {
  286. _data = data;
  287. });
  288. }).catchError((err) {});
  289. }
  290. @override
  291. Widget build(BuildContext context) {
  292. return Scaffold(
  293. backgroundColor: DColors.back,
  294. appBar: SearchBar(null, color: headerColor, elevation: 0, actions: [
  295. GestureDetector(onTap: () {
  296. Navigator.pushNamed(context, RouteNames.message);
  297. },
  298. child: Container(
  299. margin: EdgeInsets.only(right: 12.px),
  300. child: Icon(IconFonts.message),
  301. ))
  302. ]),
  303. body: _buildBody(),
  304. floatingActionButton: _checkColor ? null : InkWell(
  305. onTap: () => _controller.animateTo(0,
  306. duration: Duration(milliseconds: 600), curve: Curves.ease),
  307. child: Container(
  308. width: 32.px,
  309. height: 32.px,
  310. child: Icon(Icons.keyboard_arrow_up_sharp, color: Colors.white),
  311. decoration: BoxDecoration(
  312. color: Color.fromARGB(128, 243, 0, 0),
  313. borderRadius: BorderRadius.circular(10.px)
  314. ),
  315. ),
  316. ),
  317. );
  318. }
  319. void _onScroll() {
  320. if (_checkColor && _controller.offset > 300) {
  321. setState(() {
  322. _checkColor = false;
  323. });
  324. }
  325. if (!_checkColor && _controller.offset < 300) {
  326. setState(() {
  327. _checkColor = true;
  328. });
  329. }
  330. }
  331. }