基础组件库
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.
 
 
 
 
 

297 lines
9.0 KiB

  1. import 'dart:async';
  2. import 'package:event_bus/event_bus.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:pull_to_refresh/pull_to_refresh.dart';
  5. import 'package:provider/provider.dart';
  6. import 'package:flutter_bloc/flutter_bloc.dart';
  7. import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_notifier.dart';
  8. import 'package:zhiying_base_widget/widgets/custom/bottom_pic/bottom_pic.dart';
  9. import 'package:zhiying_base_widget/widgets/empty/empty_widget.dart';
  10. import 'package:zhiying_base_widget/widgets/home/home_auth/home_auth.dart';
  11. import 'package:zhiying_base_widget/widgets/refresh/refresh_header/refresh_gif_header.dart';
  12. import 'package:zhiying_comm/zhiying_comm.dart';
  13. import 'bloc/custom_item_page_bloc.dart';
  14. import 'bloc/custom_item_page_state.dart';
  15. import 'bloc/custom_item_page_event.dart';
  16. import 'bloc/custom_item_page_repository.dart';
  17. import 'package:zhiying_base_widget/pages/custom_page/event/reload_event.dart';
  18. ///
  19. /// 通用模块的分类导航下的子模块
  20. ///
  21. ///
  22. class CustomItemPage extends StatelessWidget {
  23. final Map<String, dynamic> data;
  24. final int tabIndex;
  25. final String modPid;
  26. final String modId;
  27. final bool needBuildStatus;
  28. Function(double) scroller;
  29. CustomItemPage(this.data, this.tabIndex, this.modId, this.modPid, this.needBuildStatus, {this.scroller});
  30. @override
  31. Widget build(BuildContext context) {
  32. return MultiProvider(
  33. providers: [
  34. ChangeNotifierProvider.value(value: MainPageNotifier()),
  35. ],
  36. child: BlocProvider<CustomItemPageBloc>(
  37. create: (_) => CustomItemPageBloc(CustomItemPageRepository(this.data, this.tabIndex, this.modId, this.modPid)),
  38. child: _CustomItemPageContainer(
  39. this.data,
  40. this.tabIndex,
  41. this.modId,
  42. this.modPid,
  43. this.needBuildStatus,
  44. scroller: this.scroller,
  45. ),
  46. ),
  47. );
  48. }
  49. }
  50. class _CustomItemPageContainer extends StatefulWidget {
  51. final Map<String, dynamic> data;
  52. final int tabIndex;
  53. final String modPid;
  54. final String modId;
  55. final bool needBuildStatus;
  56. final Function(double) scroller;
  57. const _CustomItemPageContainer(this.data, this.tabIndex, this.modId, this.modPid, this.needBuildStatus, {this.scroller, Key key}) : super(key: key);
  58. @override
  59. __CustomItemPageContainerState createState() => __CustomItemPageContainerState();
  60. }
  61. class __CustomItemPageContainerState extends State<_CustomItemPageContainer> with AutomaticKeepAliveClientMixin {
  62. @override
  63. bool get wantKeepAlive => true;
  64. ScrollController _controller;
  65. RefreshController _refreshController;
  66. EventBus _eventBus;
  67. /// 回到顶点
  68. void _scrollTop() {
  69. // _controller.jumpTo(0);
  70. _controller.animateTo(0, duration: Duration(milliseconds: 200), curve: Curves.linear);
  71. }
  72. /// 初始化
  73. void _initEvent() {
  74. BlocProvider.of<CustomItemPageBloc>(context).add(CustomItemPageInitEvent());
  75. }
  76. /// 刷新
  77. void _refreshEvent() {
  78. BlocProvider.of<CustomItemPageBloc>(context).add(CustomItemPageRefreshEvent());
  79. }
  80. /// 下拉更多
  81. void _loadEvent() {
  82. // BlocProvider.of<CustomItemPageBloc>(context).add(CustomItemPageLoadEvent());
  83. Provider.of<MainPageNotifier>(context, listen: false).loadMore();
  84. Future.delayed(Duration(milliseconds: 500), () => _refreshController?.loadComplete());
  85. }
  86. @override
  87. void initState() {
  88. _controller = ScrollController();
  89. _eventBus = EventBus();
  90. _refreshController = RefreshController(initialRefresh: false);
  91. _initEvent();
  92. _controller.addListener(() {
  93. if (widget.scroller != null) {
  94. widget?.scroller(_controller.offset);
  95. }
  96. });
  97. super.initState();
  98. }
  99. @override
  100. void dispose() {
  101. _controller?.dispose();
  102. _refreshController?.dispose();
  103. _eventBus?.destroy();
  104. super.dispose();
  105. }
  106. @override
  107. Widget build(BuildContext context) {
  108. return BlocConsumer<CustomItemPageBloc, CustomItemPageState>(
  109. listener: (context, state) {},
  110. buildWhen: (prev, current) {
  111. if (current is CustomItemPageRefreshSuccessState) {
  112. _refreshController?.refreshCompleted(resetFooterState: true);
  113. return false;
  114. }
  115. if (current is CustomItemPageRefreshErrorState) {
  116. _refreshController?.refreshFailed();
  117. return false;
  118. }
  119. if (current is CustomItemPageLoadSuccessState) {
  120. _refreshController?.loadComplete();
  121. return false;
  122. }
  123. if (current is CustomItemPageLoadErrorState) {
  124. _refreshController?.loadNoData();
  125. return false;
  126. }
  127. if (current is CustomItemPageErrorState) {
  128. return false;
  129. }
  130. if (current is CustomItemPageAppRestartState) {
  131. // 重启App
  132. Logger.log('开始重新启动App CustomItemPageAppRestartState');
  133. EventUtil.instance.fire(ReloadEvent());
  134. return false;
  135. }
  136. return true;
  137. },
  138. builder: (context, state) {
  139. Logger.log('Custom item page builder 刷新了');
  140. if (state is CustomItemPageLoadedState) {
  141. Logger.log('custom item page current state = ' + state?.toString());
  142. if (EmptyUtil.isEmpty(state.model))
  143. return _buildEmptyWidget();
  144. else
  145. return _buildMainWidget(state.model);
  146. }
  147. if (state is CustomItemPageInitErrorState) {
  148. return _buildEmptyWidget();
  149. }
  150. return _buildSkeletonWidget();
  151. },
  152. );
  153. }
  154. /// 有数据
  155. Widget _buildMainWidget(final List<Map<String, dynamic>> model) {
  156. return MediaQuery.removePadding(
  157. context: context,
  158. removeTop: false,
  159. child: Stack(
  160. children: <Widget>[
  161. SmartRefresher(
  162. controller: _refreshController,
  163. enablePullDown: true,
  164. enablePullUp: true,
  165. onRefresh: _refreshEvent,
  166. onLoading: _loadEvent,
  167. header: RefreshGifHeader(),
  168. // footer: RefreshFooter(),
  169. child: CustomScrollView(
  170. physics: BouncingScrollPhysics(),
  171. controller: _controller,
  172. slivers: _buildContentWidgets(model),
  173. ),
  174. ),
  175. Align(
  176. alignment: Alignment.bottomCenter,
  177. child: Container(
  178. margin: const EdgeInsets.only(bottom: 8),
  179. child: _buildAuthWidget(model),
  180. ), //_buildAuthWidget(model),
  181. ),
  182. Align(
  183. alignment: Alignment.bottomCenter,
  184. child: Container(
  185. margin: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom),
  186. child: _buildBottomPic(model),
  187. ), //_buildAuthWidget(model),
  188. )
  189. ],
  190. ),
  191. );
  192. }
  193. /// 根据widget的modName生成视图
  194. List<Widget> _buildContentWidgets(final List<Map<String, dynamic>> datas) {
  195. List<Widget> result = [];
  196. for (int i = 0; i < datas.length; i++) {
  197. WidgetModel item = WidgetModel.fromJson(Map<String, dynamic>.from(datas[i]));
  198. if (item.modName == 'audit_tip' || item.modName == "bottom_suspension") {
  199. Logger.debug('授权组件,跳过');
  200. continue;
  201. }
  202. if (item.modName == 'product') {
  203. datas[i]['eventBus'] = _eventBus;
  204. }
  205. result.addAll(WidgetFactory.create(
  206. item.modName,
  207. isSliver: true,
  208. model: datas[i],
  209. ));
  210. }
  211. // if (widget.needBuildStatus) {
  212. // double top = MediaQueryData.fromWindow(window).padding.top;
  213. // result.insert(
  214. // 0,
  215. // SliverPersistentHeader(
  216. // pinned: false,
  217. // floating: false,
  218. // delegate: CustomSliverPersistentHeaderDelegate(max: top, min: top, child: Container(
  219. // // color: Colors.yellow,
  220. // color: HexColor.fromHex('#FFFF4242'),
  221. // )),
  222. // ));
  223. //
  224. // }
  225. return result;
  226. }
  227. /// 空数据
  228. Widget _buildEmptyWidget() {
  229. return SmartRefresher(
  230. controller: _refreshController,
  231. onRefresh: _refreshEvent,
  232. enablePullDown: true,
  233. child: Container(
  234. child: EmptyWidget(),
  235. ),
  236. );
  237. }
  238. /// 骨架图
  239. Widget _buildSkeletonWidget() {
  240. return Container();
  241. }
  242. /// 特殊的授权组件
  243. Widget _buildAuthWidget(final List<Map<String, dynamic>> datas) {
  244. int length = datas?.length ?? 0;
  245. if (length == 0) return Container();
  246. Widget rlt;
  247. for (int i = 0; i < datas.length; i++) {
  248. WidgetModel item = WidgetModel.fromJson(Map<String, dynamic>.from(datas[i]));
  249. if (item.modName == 'audit_tip') {
  250. rlt = HomeAuth(datas[i]);
  251. break;
  252. }
  253. }
  254. return rlt ?? Container();
  255. }
  256. /// 特殊的底部图片跳转
  257. Widget _buildBottomPic(final List<Map<String, dynamic>> datas) {
  258. int length = datas?.length ?? 0;
  259. if (length == 0) return Container();
  260. Widget rlt;
  261. for (int i = 0; i < datas.length; i++) {
  262. WidgetModel item = WidgetModel.fromJson(Map<String, dynamic>.from(datas[i]));
  263. if (item.modName == 'bottom_suspension') {
  264. rlt = BottomPic(model: datas[i]);
  265. break;
  266. }
  267. }
  268. return rlt ?? Container();
  269. }
  270. }