misc.dart 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. import 'dart:math';
  2. import 'package:cached_network_image/cached_network_image.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter_easyrefresh/easy_refresh.dart';
  5. import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
  6. import 'package:provider/provider.dart';
  7. import 'package:sport/bean/post_user.dart';
  8. import 'package:sport/bean/user.dart';
  9. import 'package:sport/constant/ui.dart';
  10. import 'package:sport/provider/user_model.dart';
  11. import 'package:sport/router/navigator_util.dart';
  12. import 'package:sport/widgets/dialog/popupmenu.dart' as menu;
  13. import 'package:sport/widgets/image.dart';
  14. import 'package:sport/widgets/refresh_header.dart' as header;
  15. import 'package:sport/widgets/refresh_footer.dart';
  16. import 'package:sport/widgets/space.dart';
  17. Widget buildSocialUserWidget(BuildContext context, PostUser user, int createTime, int avatarWidth) {
  18. return user == null
  19. ? Container()
  20. : GestureDetector(
  21. onTap: () => NavigatorUtil.goSocialUserDetail(context, user),
  22. child: Row(
  23. children: <Widget>[
  24. Space(
  25. width: 12,
  26. ),
  27. CircleAvatar(backgroundImage: userAvatarProvider(user?.avatar), radius: avatarWidth / 2),
  28. Space(
  29. width: 8,
  30. ),
  31. Text(
  32. user?.name,
  33. style: Theme.of(context).textTheme.subtitle1.copyWith(fontWeight: FontWeight.w600),
  34. ),
  35. ],
  36. ));
  37. }
  38. Widget buildLabelWidget(BuildContext context, String title) {
  39. return Container(
  40. padding: EdgeInsets.fromLTRB(ui_padding, 10.0, ui_padding, 10.0),
  41. child: Text(
  42. title,
  43. style: Theme.of(context).textTheme.headline1,
  44. ));
  45. }
  46. Widget gameTag(BuildContext context, String name) {
  47. return Container(
  48. decoration: BoxDecoration(
  49. borderRadius: BorderRadius.all(Radius.circular(50)),
  50. border: Border.all(
  51. color: Theme.of(context).accentColor,
  52. width: 1,
  53. ),
  54. ),
  55. padding: EdgeInsets.fromLTRB(8, 0, 8, 1),
  56. child: Text(
  57. name,
  58. style: Theme.of(context).textTheme.bodyText1.copyWith(color: Theme.of(context).accentColor),
  59. strutStyle: fixedLine,
  60. ),
  61. );
  62. }
  63. Widget achievementGroupWidget(List<Achievement> achievements) {
  64. return achievements == null || achievements.isEmpty
  65. ? Center(child: Container(child: Padding(padding: const EdgeInsets.all(24.0), child: Text("还未获得成就"))))
  66. : StaggeredGridView.countBuilder(
  67. padding: EdgeInsets.zero,
  68. shrinkWrap: true,
  69. physics: NeverScrollableScrollPhysics(),
  70. crossAxisCount: 4,
  71. itemCount: min(4, achievements.length),
  72. itemBuilder: (BuildContext context, int index) => achievementWidget(context, achievements[index]),
  73. crossAxisSpacing: 12.0,
  74. staggeredTileBuilder: (int index) => StaggeredTile.fit(1),
  75. );
  76. }
  77. Widget achievementWidget(BuildContext context, Achievement item, {double w = 70, bool replace = false, bool isRadius = false, bool jump = true}) => InkWell(
  78. onTap: () {
  79. if(item.userId != null && Provider.of<UserModel>(context, listen: false).user.id != item.userId)
  80. return;
  81. if (jump == true) NavigatorUtil.goAchievementDetails(context, id: item.id, userId: item.userId ?? 0, replace: replace);
  82. },
  83. child: Column(
  84. children: <Widget>[
  85. isRadius
  86. ? CircleAvatar(backgroundImage: CachedNetworkImageProvider(item.logo ?? ""), radius: w / 2)
  87. : item?.createdAt == ""
  88. ? ColorFiltered(
  89. colorFilter: ColorFilter.mode(Color(0xffF1F1F1), BlendMode.color),
  90. child: CachedNetworkImage(width: w, height: w, imageUrl: item.logo ?? ""),
  91. )
  92. : Container(
  93. width: w,
  94. height: w,
  95. child: CachedNetworkImage(imageUrl: item.logo ?? ""),
  96. ),
  97. Space(
  98. height: 5,
  99. ),
  100. Text(
  101. item.name,
  102. style: Theme.of(context).textTheme.subtitle1.copyWith(fontSize: w < 80 ? 12 : 14),
  103. )
  104. ],
  105. ));
  106. Widget sportBeEquivalentTo(BuildContext context, int consume, {bool highlight = false}) => Padding(
  107. padding: EdgeInsets.all(10.0),
  108. child: Text(
  109. "消耗了 ${(consume / 50).round()} 块小饼干",
  110. style: Theme.of(context).textTheme.subtitle1,
  111. ),
  112. );
  113. // Row(
  114. // mainAxisAlignment: MainAxisAlignment.spaceAround,
  115. // children: <Widget>[
  116. // Column(
  117. // children: <Widget>[
  118. // Image.asset("lib/assets/img/gamedetail_image_walk.png"),
  119. // Space(
  120. // height: 8,
  121. // ),
  122. // RichText(
  123. // text: TextSpan(children: <InlineSpan>[
  124. // TextSpan(text: '步行', style: Theme.of(context).textTheme.bodyText1),
  125. // TextSpan(
  126. // text: '${(consume / 3 * 90).floor()}',
  127. // style: highlight
  128. // ? Theme.of(context).textTheme.bodyText1.copyWith(color: Theme.of(context).accentColor)
  129. // : Theme.of(context).textTheme.bodyText1),
  130. // TextSpan(text: '步', style: Theme.of(context).textTheme.bodyText1),
  131. // ]),
  132. // )
  133. // ],
  134. // ),
  135. // Column(
  136. // children: <Widget>[
  137. // Image.asset("lib/assets/img/gamedetail_image_run.png"),
  138. // Space(
  139. // height: 8,
  140. // ),
  141. // RichText(
  142. // text: TextSpan(children: <InlineSpan>[
  143. // TextSpan(text: '跑步', style: Theme.of(context).textTheme.bodyText1),
  144. // TextSpan(
  145. // text: '${(consume / 60 / 1.036).toStringAsFixed(1)}',
  146. // style: highlight
  147. // ? Theme.of(context).textTheme.bodyText1.copyWith(color: Theme.of(context).accentColor)
  148. // : Theme.of(context).textTheme.bodyText1),
  149. // TextSpan(text: '公里', style: Theme.of(context).textTheme.bodyText1),
  150. // ]),
  151. // )
  152. // ],
  153. // ),
  154. // Column(
  155. // children: <Widget>[
  156. // Image.asset("lib/assets/img/gamedetail_image_riding.png"),
  157. // Space(
  158. // height: 8,
  159. // ),
  160. // RichText(
  161. // text: TextSpan(children: <InlineSpan>[
  162. // TextSpan(text: '单车', style: Theme.of(context).textTheme.bodyText1),
  163. // TextSpan(
  164. // text: '${(consume / 60 / 0.6142).toStringAsFixed(1)}',
  165. // style: highlight
  166. // ? Theme.of(context).textTheme.bodyText1.copyWith(color: Theme.of(context).accentColor)
  167. // : Theme.of(context).textTheme.bodyText1),
  168. // TextSpan(text: '公里', style: Theme.of(context).textTheme.bodyText1),
  169. // ]),
  170. // )
  171. // ],
  172. // ),
  173. // ],
  174. // );
  175. const REFRESH_INFO_COLOR = Color(0xff999999);
  176. header.ClassicalHeader buildClassicalHeader(
  177. {double extent = 80.0,
  178. double triggerDistance = 90.0,
  179. Color infoColor = REFRESH_INFO_COLOR,
  180. Color textColor =const Color(0xffFFC400),
  181. Color bgColor = Colors.transparent}) {
  182. return header.ClassicalHeader(
  183. extent: extent,
  184. triggerDistance: triggerDistance,
  185. showInfo: false,
  186. refreshText: '下拉刷新',
  187. refreshFailedText: '刷新失败',
  188. refreshedText: '刷新完成',
  189. refreshingText: '正在刷新...',
  190. refreshReadyText: '释放刷新',
  191. infoColor: Color(0xffFFC400),
  192. bgColor: bgColor,
  193. textColor: textColor,
  194. );
  195. }
  196. Footer buildClassicalFooter() {
  197. return CustomClassicalFooter(
  198. showInfo: false,
  199. loadedText: '加载完成',
  200. loadReadyText: '释放加载',
  201. loadFailedText: '加载失败',
  202. loadText: '拉动加载',
  203. loadingText: '正在加载...',
  204. noMoreText: "没有更多了~",
  205. infoColor: Color(0xff999999));
  206. }
  207. PopupMenuEntry menuDivider() => menu.PopupMenuItem(
  208. height: 1,
  209. child: Divider(
  210. height: 1,
  211. ),
  212. );
  213. PopupMenuEntry menuItem(String value, String icon, String text) => menu.PopupMenuItem(
  214. value: value,
  215. child: Row(
  216. mainAxisSize: MainAxisSize.min,
  217. children: <Widget>[
  218. Image.asset(
  219. "lib/assets/img/$icon",
  220. width: 24,
  221. ),
  222. SizedBox(
  223. width: 4,
  224. ),
  225. Text(
  226. text,
  227. )
  228. ],
  229. ),
  230. );
  231. PopupMenuEntry menuItemCenter(dynamic value, String text) => menu.PopupMenuItem(
  232. value: value,
  233. child: Center(
  234. child: Text(
  235. text,
  236. )),
  237. );
  238. PopupMenuEntry menuItemSelected(dynamic value, String text, bool select) => menu.PopupMenuItem(
  239. value: value,
  240. child: Row(
  241. mainAxisSize: MainAxisSize.min,
  242. children: <Widget>[
  243. Container(
  244. alignment: AlignmentDirectional.centerStart,
  245. constraints: BoxConstraints(minWidth: 60),
  246. padding: const EdgeInsets.symmetric(horizontal: 8.0),
  247. child: select
  248. ? Text(
  249. text,
  250. style: TextStyle(color: Color(0xffFFC400)),
  251. )
  252. : Text(
  253. text,
  254. ),
  255. ),
  256. if (select)
  257. Image.asset(
  258. "lib/assets/img/pop_icon_selected.png",
  259. width: 24,
  260. ),
  261. ],
  262. ));
  263. List<PopupMenuEntry> divideMenus(Iterable<PopupMenuEntry> tiles) {
  264. assert(tiles != null);
  265. final Iterator<PopupMenuEntry> iterator = tiles.iterator;
  266. final PopupMenuEntry divider = menuDivider();
  267. final List<PopupMenuEntry> list = [];
  268. while (iterator.moveNext()) {
  269. list.add(iterator.current);
  270. list.add(divider);
  271. }
  272. if (list.length > 1) list.removeAt(list.length - 1);
  273. return list;
  274. }
  275. final StrutStyle fixedLine = StrutStyle(forceStrutHeight: true);