level_page.dart 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. import 'dart:convert';
  2. import 'dart:math';
  3. import 'package:cached_network_image/cached_network_image.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:flutter_easyrefresh/easy_refresh.dart';
  6. import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
  7. import 'package:sport/bean/achievement_info.dart';
  8. import 'package:sport/provider/lib/provider_widget.dart';
  9. import 'package:sport/provider/lib/simple_model.dart';
  10. import 'package:sport/router/navigator_util.dart';
  11. import 'package:sport/router/routes.dart';
  12. import 'package:sport/pages/my/level_desc_page.dart';
  13. import 'package:sport/services/api/inject_api.dart';
  14. import 'package:sport/widgets/appbar.dart';
  15. import 'package:sport/widgets/box.dart';
  16. import 'package:sport/widgets/error.dart';
  17. import 'package:sport/widgets/image.dart';
  18. import 'package:sport/widgets/loading.dart';
  19. import 'package:sport/widgets/misc.dart';
  20. import 'package:sport/widgets/space.dart';
  21. class LevelPage extends StatefulWidget {
  22. @override
  23. State<StatefulWidget> createState() => _PageState();
  24. }
  25. class _PageState extends State<LevelPage> with InjectLoginApi {
  26. late SimpleModel _model;
  27. bool _max = false;
  28. int _brightness = 0;
  29. @override
  30. void initState() {
  31. super.initState();
  32. _model = SimpleModel((page) async {
  33. try {
  34. return [(await loginApi.getAchievementInfo()).data];
  35. } catch (e) {
  36. print(e);
  37. return [];
  38. }
  39. });
  40. // _controller = ScrollController()
  41. // ..addListener(() {
  42. //// print(
  43. //// "[_controller.position.pixels] -------------------------- ${_controller.position.pixels}");
  44. // print("[_brightness]--------------------------$_brightness");
  45. // if (_controller.position.pixels >= 70) {
  46. // if (_brightness == 0) {
  47. // setState(() {
  48. // _brightness = 1;
  49. // });
  50. // }
  51. // } else {
  52. // if (_brightness == 1) {
  53. // setState(() {
  54. // _brightness = 0;
  55. // });
  56. // }
  57. // }
  58. // });
  59. }
  60. @override
  61. Widget build(BuildContext context) {
  62. return Scaffold(
  63. backgroundColor: Color(0xff241D19),
  64. body: Stack(
  65. children: <Widget>[
  66. Positioned(
  67. top: -100,
  68. left: 0,
  69. child: Container(
  70. width: MediaQuery.of(context).size.width,
  71. height: 373.0,
  72. decoration: BoxDecoration(image: DecorationImage(image: AssetImage("lib/assets/img/mylevel_bg.png"), fit: BoxFit.contain)),
  73. )),
  74. ProviderWidget<SimpleModel>(
  75. model: _model,
  76. onModelReady: (model) => model.initData(),
  77. builder: (_, model, __) {
  78. AchievementInfoData? _data = model.list.isNotEmpty ? model.list.first : null;
  79. return EasyRefresh.builder(
  80. controller: model.refreshController,
  81. enableControlFinishRefresh: true,
  82. enableControlFinishLoad: true,
  83. onRefresh: () => model.refresh(),
  84. header: buildClassicalHeader(),
  85. builder: (context, physics, header, footer) {
  86. return CustomScrollView(
  87. physics: physics,
  88. slivers: <Widget>[
  89. buildSliverAppBar(context, "我的等级",
  90. backgroundColor: _brightness == 0 ? Color(0x00000000) : Color(0xffffffff),
  91. brightness: _brightness == 0 ? 1 : 0,
  92. textStyle: _brightness == 0
  93. ? TextStyle(fontWeight: FontWeight.w600, fontSize: 18.0, color: Color(0xffffffff))
  94. : TextStyle(fontWeight: FontWeight.w600, fontSize: 18.0, color: Color(0xff333333)),
  95. whiteBackButton: _brightness == 0 ? true : false,
  96. canBack: _brightness == 0 ? false : true,
  97. actions: [
  98. // InkWell(
  99. // child: Center(
  100. // child: Padding(
  101. // padding: const EdgeInsets.symmetric(horizontal: 12.0),
  102. // child:Text(
  103. // "奖励说明",
  104. // style: TextStyle(color: Colors.white, fontSize: 14.0),
  105. // ))),
  106. // onTap: () {
  107. //
  108. // NavigatorUtil.goPage(context, (context) => LevelDescPage());
  109. // })
  110. ]),
  111. // header,
  112. if (model.isBusy)
  113. SliverToBoxAdapter(
  114. child: RequestLoadingWidget(),
  115. ),
  116. if (model.isIdle && _data != null)
  117. SliverToBoxAdapter(
  118. child: BoxWidget(
  119. body: Column(
  120. children: <Widget>[
  121. Padding(
  122. padding: const EdgeInsets.only(bottom: 8.0),
  123. child: Row(
  124. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  125. children: <Widget>[
  126. Row(
  127. children: <Widget>[
  128. Text(
  129. "积分:",
  130. style: Theme.of(context).textTheme.subtitle1!,
  131. ),
  132. Space(
  133. width: 5.0,
  134. ),
  135. Text(
  136. '${_data.score}',
  137. style: TextStyle(fontSize: 14.0, color: Color(0xffFFC400)),
  138. )
  139. ],
  140. ),
  141. InkWell(
  142. child: Row(
  143. children: <Widget>[
  144. Padding(
  145. child: Text(
  146. "积分商城",
  147. style: Theme.of(context).textTheme.bodyText1!,
  148. ),
  149. padding: EdgeInsets.only(right: 5.0),
  150. ),
  151. arrowRight4()
  152. ],
  153. ),
  154. onTap: () {
  155. NavigatorUtil.go(context, Routes.scoreShopPage);
  156. },
  157. )
  158. ],
  159. ),
  160. ),
  161. Padding(
  162. padding: const EdgeInsets.only(top: 16.0, bottom: 8.0),
  163. child: Container(
  164. child: CachedNetworkImage(
  165. width: 130.0,
  166. height: 130.0,
  167. imageUrl: _data.level?.logo ?? "",
  168. fit: BoxFit.contain,
  169. ))),
  170. Text(
  171. "Lv.${_data.level?.level}",
  172. style: Theme.of(context).textTheme.headline3!.copyWith(fontSize: 20.0),
  173. ),
  174. Space(
  175. height: 24,
  176. ),
  177. Row(
  178. mainAxisAlignment: MainAxisAlignment.end,
  179. children: <Widget>[
  180. Row(
  181. children: <Widget>[
  182. Text(
  183. "${_data.exp}",
  184. style: TextStyle(fontSize: 11, color: Theme.of(context).accentColor),
  185. ),
  186. Text("/${_data.exp + _data.nextLevelExp}", style: TextStyle(fontSize: 11)),
  187. ],
  188. ),
  189. ],
  190. ),
  191. Space(
  192. height: 2,
  193. ),
  194. ClipRRect(
  195. borderRadius: BorderRadius.circular(10),
  196. child: Container(
  197. child: CustomPaint(
  198. painter: _ProgressBar(
  199. _data.nextLevelExp + _data.exp == 0 ? 0 : _data.exp / (_data.nextLevelExp + _data.exp),
  200. ),
  201. child: Container(
  202. height: 12,
  203. ),
  204. ),
  205. // height: 12,
  206. ),
  207. ),
  208. Space(
  209. height: 8,
  210. ),
  211. Row(
  212. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  213. children: <Widget>[
  214. Row(
  215. children: <Widget>[
  216. Text("累积运动:", style: Theme.of(context).textTheme.subtitle1!),
  217. Space(
  218. width: 2.0,
  219. ),
  220. Text(
  221. "${_data.exp}",
  222. style: Theme.of(context).textTheme.subtitle1!.copyWith(color: Theme.of(context).accentColor),
  223. ),
  224. Text("分钟", style: Theme.of(context).textTheme.subtitle1!),
  225. ],
  226. ),
  227. Text(
  228. "再运动 ${_data.nextLevelExp} 分钟可升级",
  229. style: Theme.of(context).textTheme.bodyText1!,
  230. ),
  231. ],
  232. ),
  233. Space(
  234. height: 10.0,
  235. ),
  236. ],
  237. ))),
  238. if (model.isIdle && _data != null)
  239. SliverToBoxAdapter(
  240. child: BoxWidget(
  241. body: Column(
  242. children: <Widget>[
  243. Row(
  244. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  245. children: <Widget>[
  246. Text(
  247. "我的成就",
  248. style: Theme.of(context).textTheme.headline3,
  249. ),
  250. InkWell(
  251. onTap: () {
  252. // setState(() {
  253. // _max = true;
  254. // });
  255. // NavigatorUtil.go(context, "achievement");
  256. NavigatorUtil.go(context, "${Routes.achievement}?data=${Uri.encodeComponent(json.encode(_data))}");
  257. },
  258. child: Row(
  259. children: <Widget>[
  260. Text(
  261. "查看全部 ",
  262. style: Theme.of(context).textTheme.bodyText1!,
  263. ),
  264. arrowRight4()
  265. ],
  266. ),
  267. ),
  268. ],
  269. ),
  270. Space(
  271. height: 10.0,
  272. ),
  273. if ((_data.getAchievementList?.length ?? 0) == 0)
  274. Padding(
  275. padding: const EdgeInsets.all(30.0),
  276. child: Column(
  277. children: <Widget>[
  278. Image.asset("lib/assets/img/${RequestErrorWidget.ASSETS_NO_RANK}"),
  279. Padding(
  280. padding: const EdgeInsets.fromLTRB(0, 12, 0, 12),
  281. child: Text(
  282. "还未获得任何成就",
  283. style: Theme.of(context).textTheme.bodyText2!,
  284. ),
  285. ),
  286. ],
  287. )),
  288. if ((_data.getAchievementList?.length ?? 0) > 0)
  289. Padding(
  290. padding: EdgeInsets.only(top: 16.0, bottom: 0.0),
  291. child: AlignedGridView.count(
  292. padding: EdgeInsets.zero,
  293. shrinkWrap: true,
  294. physics: NeverScrollableScrollPhysics(),
  295. crossAxisCount: 4,
  296. itemCount: _max ? _data.getAchievementList!.length : min(4, _data.getAchievementList!.length),
  297. itemBuilder: (BuildContext context, int index) => achievementWidget(
  298. context,
  299. _data.getAchievementList![index],
  300. isRadius: false,
  301. ),
  302. mainAxisSpacing: 12.0,
  303. crossAxisSpacing: 12.0,
  304. ),
  305. ),
  306. // Center(
  307. // child: Padding(
  308. // padding: const EdgeInsets.all(1.0),
  309. // child: Row(
  310. // children: <Widget>[
  311. // Expanded(
  312. // child: Divider(
  313. // endIndent: 20.0,
  314. // ),
  315. // ),
  316. // Text("未获得成就", style: Theme.of(context).textTheme.bodyText1!),
  317. // Expanded(
  318. // child: Divider(
  319. // indent: 20.0,
  320. // ),
  321. // ),
  322. // ],
  323. // ),
  324. // ),
  325. // ),
  326. // getList(_data)
  327. ],
  328. ),
  329. ),
  330. ),
  331. ],
  332. );
  333. });
  334. },
  335. )
  336. ],
  337. ));
  338. }
  339. }
  340. class _ProgressBar extends CustomPainter {
  341. final Paint _paint = Paint()
  342. ..color = Color(0xffeeeeee)
  343. ..isAntiAlias = true;
  344. final Paint _indicatorPaint = Paint()
  345. ..color = Color(0xffFFC400)
  346. ..isAntiAlias = true;
  347. double _paddingBar = 2;
  348. double percent;
  349. _ProgressBar(this.percent);
  350. @override
  351. void paint(Canvas canvas, Size size) {
  352. double indicator = size.width * min(1.0, this.percent);
  353. canvas.save();
  354. var rect = Rect.fromLTRB(0, size.height - 13, size.width, size.height);
  355. canvas.clipRRect(RRect.fromRectAndRadius(rect, Radius.circular(size.height / 2)), doAntiAlias: true);
  356. canvas.drawRect(rect, _paint);
  357. Paint _valuePaint = Paint()
  358. ..shader = LinearGradient(
  359. begin: Alignment.centerLeft,
  360. end: Alignment.centerRight,
  361. colors: <Color>[Color(0xffFFE600), Color(0xffFF9100)],
  362. ).createShader(rect);
  363. canvas.drawRect(Rect.fromLTRB(0, size.height - 13, size.width * this.percent, size.height), _valuePaint);
  364. canvas.restore();
  365. Path path = Path()
  366. ..moveTo(indicator, size.height - 13 - _paddingBar)
  367. ..lineTo(indicator - 5, 0)
  368. ..lineTo(indicator + 5, 0)
  369. ..close();
  370. canvas.drawPath(path, _indicatorPaint);
  371. }
  372. @override
  373. bool shouldRepaint(CustomPainter oldDelegate) {
  374. return false;
  375. }
  376. }