level_page.dart 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. import 'dart:convert';
  2. import 'dart:math';
  3. import 'package:cached_network_image/cached_network_image.dart';
  4. import 'package:flutter/cupertino.dart';
  5. import 'package:flutter/material.dart';
  6. import 'package:flutter_easyrefresh/easy_refresh.dart';
  7. import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
  8. import 'package:provider/provider.dart';
  9. import 'package:sport/bean/achievement_info.dart';
  10. import 'package:sport/bean/rank_game_info.dart';
  11. import 'package:sport/bean/user.dart';
  12. import 'package:sport/provider/lib/provider_widget.dart';
  13. import 'package:sport/provider/lib/simple_model.dart';
  14. import 'package:sport/provider/user_model.dart';
  15. import 'package:sport/router/navigator_util.dart';
  16. import 'package:sport/router/routes.dart';
  17. import 'package:sport/services/api/inject_api.dart';
  18. import 'package:sport/widgets/appbar.dart';
  19. import 'package:sport/widgets/box.dart';
  20. import 'package:sport/widgets/error.dart';
  21. import 'package:sport/widgets/image.dart';
  22. import 'package:sport/widgets/loading.dart';
  23. import 'package:sport/widgets/misc.dart';
  24. import 'package:sport/widgets/space.dart';
  25. import 'achievement_page.dart';
  26. class LevelPage extends StatefulWidget {
  27. @override
  28. State<StatefulWidget> createState() => _PageState();
  29. }
  30. class _PageState extends State<LevelPage> with InjectLoginApi {
  31. SimpleModel _model;
  32. bool _max = false;
  33. @override
  34. void initState() {
  35. super.initState();
  36. _model = SimpleModel((page) async => [(await loginApi.getAchievementInfo()).data]);
  37. }
  38. @override
  39. Widget build(BuildContext context) {
  40. return Scaffold(
  41. body: ProviderWidget<SimpleModel>(
  42. model: _model,
  43. onModelReady: (model) => model.initData(),
  44. builder: (_, model, __) {
  45. AchievementInfoData _data = model.list.isNotEmpty ? model.list.first : null;
  46. return EasyRefresh.builder(
  47. controller: model.refreshController,
  48. enableControlFinishRefresh: true,
  49. enableControlFinishLoad: true,
  50. onRefresh: () => model.refresh(),
  51. header: buildClassicalHeader(),
  52. builder: (context, physics, header, footer) {
  53. return CustomScrollView(
  54. physics: physics,
  55. slivers: <Widget>[
  56. buildSliverAppBar(context, "我的等级", backgroundColor: Theme.of(context).scaffoldBackgroundColor),
  57. header,
  58. if (model.isBusy)
  59. SliverToBoxAdapter(
  60. child: RequestLoadingWidget(),
  61. ),
  62. if (model.isIdle && _data != null)
  63. SliverToBoxAdapter(
  64. child: BoxWidget(
  65. body: Column(
  66. children: <Widget>[
  67. Padding(
  68. padding: const EdgeInsets.only(bottom: 8.0),
  69. child: Row(
  70. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  71. children: <Widget>[
  72. Row(
  73. children: <Widget>[
  74. Text(
  75. "积分:",
  76. style: Theme.of(context).textTheme.subtitle1,
  77. ),
  78. Space(
  79. width: 5.0,
  80. ),
  81. Text(
  82. '${_data.exp}',
  83. style: TextStyle(fontSize: 14.0, color: Color(0xffFFC400)),
  84. )
  85. ],
  86. ),
  87. InkWell(
  88. child: Row(
  89. children: <Widget>[
  90. Padding(
  91. child: Text(
  92. "积分商城",
  93. style: Theme.of(context).textTheme.bodyText1,
  94. ),
  95. padding: EdgeInsets.only(right: 5.0),
  96. ),
  97. arrowRight4()
  98. ],
  99. ),
  100. onTap: () {
  101. NavigatorUtil.go(context, Routes.scoreShopPage);
  102. },
  103. )
  104. ],
  105. ),
  106. ),
  107. Padding(
  108. padding: const EdgeInsets.only(top: 16.0, bottom: 8.0),
  109. child: Container(width: 90.0, height: 90.0, child: CachedNetworkImage(imageUrl: _data.level.logo ?? ""))),
  110. Text(
  111. "Lv.${_data.level.level}",
  112. style: Theme.of(context).textTheme.headline3,
  113. ),
  114. Space(
  115. height: 24,
  116. ),
  117. Row(
  118. mainAxisAlignment: MainAxisAlignment.end,
  119. children: <Widget>[
  120. Row(
  121. children: <Widget>[
  122. Text(
  123. "${_data.exp}",
  124. style: TextStyle(fontSize: 11, color: Theme.of(context).accentColor),
  125. ),
  126. Text("/${_data.exp + _data.nextLevelExp}", style: TextStyle(fontSize: 11)),
  127. ],
  128. ),
  129. ],
  130. ),
  131. Space(
  132. height: 2,
  133. ),
  134. ClipRRect(
  135. borderRadius: BorderRadius.circular(10),
  136. child: Container(
  137. child: CustomPaint(
  138. painter: _ProgressBar(
  139. _data.exp / (_data.nextLevelExp + _data.exp),
  140. ),
  141. child: Container(
  142. height: 12,
  143. ),
  144. ),
  145. // height: 12,
  146. ),
  147. ),
  148. Space(
  149. height: 8,
  150. ),
  151. Row(
  152. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  153. children: <Widget>[
  154. Row(
  155. children: <Widget>[
  156. Text("经验值:", style: Theme.of(context).textTheme.subtitle1),
  157. Space(
  158. width: 2.0,
  159. ),
  160. Text(
  161. "${_data.exp}",
  162. style: Theme.of(context).textTheme.subtitle1.copyWith(color: Theme.of(context).accentColor),
  163. ),
  164. ],
  165. ),
  166. Text(
  167. "再获得 ${_data.nextLevelExp} 经验可升到下一段",
  168. style: Theme.of(context).textTheme.bodyText1,
  169. ),
  170. ],
  171. ),
  172. ],
  173. ))),
  174. if (model.isIdle && _data != null)
  175. SliverToBoxAdapter(
  176. child: BoxWidget(
  177. body: Column(
  178. children: <Widget>[
  179. Row(
  180. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  181. children: <Widget>[
  182. Text(
  183. "我的成就",
  184. style: Theme.of(context).textTheme.headline3,
  185. ),
  186. if (_data.getAchievementList.length > -1 || _max)
  187. InkWell(
  188. onTap: () {
  189. // setState(() {
  190. // _max = true;
  191. // });
  192. // NavigatorUtil.go(context, "achievement");
  193. NavigatorUtil.go(context, "${Routes.achievement}?data=${Uri.encodeComponent(json.encode(_data))}");
  194. },
  195. child: Row(
  196. children: <Widget>[
  197. Text(
  198. "查看全部 ",
  199. style: Theme.of(context).textTheme.bodyText1,
  200. ),
  201. arrowRight4()
  202. ],
  203. ),
  204. ),
  205. ],
  206. ),
  207. if (_data.getAchievementList.length == 0)
  208. Padding(
  209. padding: const EdgeInsets.all(30.0),
  210. child: Column(
  211. children: <Widget>[
  212. Image.asset("lib/assets/img/${RequestErrorWidget.ASSETS_NO_RANK}"),
  213. Padding(
  214. padding: const EdgeInsets.fromLTRB(0, 12, 0, 12),
  215. child: Text(
  216. "还未获得任何成就",
  217. style: Theme.of(context).textTheme.bodyText2,
  218. ),
  219. ),
  220. ],
  221. )),
  222. if (_data.getAchievementList.length > 0)
  223. Padding(
  224. padding: EdgeInsets.symmetric(vertical: 16.0),
  225. child: StaggeredGridView.countBuilder(
  226. padding: EdgeInsets.zero,
  227. shrinkWrap: true,
  228. physics: NeverScrollableScrollPhysics(),
  229. crossAxisCount: 4,
  230. itemCount: _max ? _data.getAchievementList.length : min(4, _data.getAchievementList.length),
  231. itemBuilder: (BuildContext context, int index) =>
  232. achievementWidget(context, _data.getAchievementList[index], isRadius: false),
  233. mainAxisSpacing: 12.0,
  234. crossAxisSpacing: 12.0,
  235. staggeredTileBuilder: (int index) => StaggeredTile.fit(1),
  236. ),
  237. ),
  238. Center(
  239. child: Padding(
  240. padding: const EdgeInsets.all(1.0),
  241. child: Row(
  242. children: <Widget>[
  243. Expanded(
  244. child: Divider(
  245. endIndent: 20.0,
  246. ),
  247. ),
  248. Text("未获得成就", style: Theme.of(context).textTheme.bodyText1),
  249. Expanded(
  250. child: Divider(
  251. indent: 20.0,
  252. ),
  253. ),
  254. ],
  255. ),
  256. ),
  257. ),
  258. getList(_data)
  259. ],
  260. ),
  261. ),
  262. ),
  263. ],
  264. );
  265. });
  266. },
  267. ));
  268. }
  269. }
  270. class _ProgressBar extends CustomPainter {
  271. final Paint _paint = Paint()
  272. ..color = Color(0xffeeeeee)
  273. ..isAntiAlias = true;
  274. final Paint _indicatorPaint = Paint()
  275. ..color = Color(0xffFFC400)
  276. ..isAntiAlias = true;
  277. double _paddingBar = 2;
  278. double percent;
  279. _ProgressBar(this.percent);
  280. @override
  281. void paint(Canvas canvas, Size size) {
  282. double indicator = size.width * min(1.0, this.percent);
  283. canvas.save();
  284. var rect = Rect.fromLTRB(0, size.height - 13, size.width, size.height);
  285. canvas.clipRRect(RRect.fromRectAndRadius(rect, Radius.circular(size.height / 2)), doAntiAlias: true);
  286. canvas.drawRect(rect, _paint);
  287. Paint _valuePaint = Paint()
  288. ..shader = LinearGradient(
  289. begin: Alignment.centerLeft,
  290. end: Alignment.centerRight,
  291. colors: <Color>[Color(0xffFFE600), Color(0xffFF9100)],
  292. ).createShader(rect);
  293. canvas.drawRect(Rect.fromLTRB(0, size.height - 13, size.width * this.percent, size.height), _valuePaint);
  294. canvas.restore();
  295. Path path = Path()
  296. ..moveTo(indicator, size.height - 13 - _paddingBar)
  297. ..lineTo(indicator - 5, 0)
  298. ..lineTo(indicator + 5, 0)
  299. ..close();
  300. canvas.drawPath(path, _indicatorPaint);
  301. }
  302. @override
  303. bool shouldRepaint(CustomPainter oldDelegate) {
  304. return false;
  305. }
  306. }