target_modify.dart 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. import 'dart:math';
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:sport/bean/sport_target.dart';
  5. import 'package:sport/pages/social/notification.dart';
  6. import 'package:sport/services/api/inject_api.dart';
  7. import 'package:sport/widgets/box.dart';
  8. import 'package:sport/widgets/loading.dart';
  9. import 'package:sport/widgets/misc.dart';
  10. import 'package:sport/widgets/space.dart';
  11. class TargetModify extends StatefulWidget {
  12. final SportTarget target;
  13. final bool editCustom;
  14. final bool padding;
  15. TargetModify({this.target, this.editCustom = true, this.padding = true});
  16. @override
  17. createState() => _PageState();
  18. }
  19. class _PageState extends State<TargetModify> with InjectApi {
  20. Space space = Space(height: 5);
  21. List<SportTarget> _tags = [];
  22. ValueNotifier<String> _valueNotifierChoice = ValueNotifier("");
  23. double _customDuration = 150;
  24. TextEditingController _textEditingController;
  25. final String _customName = '自定义';
  26. @override
  27. void initState() {
  28. super.initState();
  29. _textEditingController = TextEditingController();
  30. api.getSportTargetAll().then((value) {
  31. _tags.addAll(value.results);
  32. if (_tags.isNotEmpty) {
  33. if (_tags.any((element) => element.name == _customName)) {
  34. var target = _tags.singleWhere((element) => element.name == _customName);
  35. _textEditingController.text = '${target.duration}';
  36. _customDuration = target.duration.toDouble();
  37. _valueNotifierChoice.value = target.name;
  38. TargetNotification(target: target).dispatch(context);
  39. } else {
  40. _tags.add(SportTarget(duration: 150, consume: kal(150), name: '自定义', intension: '自定义', id: -1));
  41. _textEditingController.text = '150';
  42. _valueNotifierChoice.value = _tags[0].name;
  43. TargetNotification(target: _tags[0]).dispatch(context);
  44. }
  45. }
  46. setState(() {});
  47. });
  48. }
  49. @override
  50. void dispose() {
  51. _textEditingController?.dispose();
  52. _valueNotifierChoice?.dispose();
  53. super.dispose();
  54. }
  55. int kal(double duration) {
  56. var realTime = duration / 60;
  57. var realWeight = 60 * 2 / 190;
  58. return ((realTime * realWeight) * 671.1).round();
  59. }
  60. @override
  61. Widget build(BuildContext context) {
  62. Widget body = Column(
  63. crossAxisAlignment: CrossAxisAlignment.start,
  64. children: <Widget>[
  65. ValueListenableBuilder(
  66. valueListenable: _valueNotifierChoice,
  67. builder: (_, _value, __) => Container(
  68. child: Center(
  69. child: Wrap(
  70. spacing: 6,
  71. children: _tags.map((e) {
  72. String name = e.name;
  73. bool _selected = name == _value;
  74. return FractionallySizedBox(
  75. widthFactor: .31,
  76. child: ChoiceChip(
  77. padding: EdgeInsets.zero,
  78. pressElevation: 0,
  79. selected: _selected,
  80. label: Center(
  81. child: Text(
  82. "$name",
  83. strutStyle: fixedLine,
  84. )),
  85. labelStyle: _selected ? TextStyle(color: Colors.white, fontSize: 13.0) : TextStyle(color: Color(0xff333333), fontSize: 13.0),
  86. //未选定的时候背景
  87. selectedColor: Theme.of(context).accentColor,
  88. //被禁用得时候背景
  89. backgroundColor: Colors.white,
  90. disabledColor: Colors.white,
  91. shape: StadiumBorder(
  92. side: BorderSide(color: _selected ? Theme.of(context).accentColor : Color(0xffcecece), width: 0.5),
  93. ),
  94. onSelected: (name == (widget.target == null ? "" : widget.target.name) && name != _customName)
  95. ? null
  96. : (value) {
  97. _valueNotifierChoice.value = name;
  98. TargetNotification(target: e).dispatch(context);
  99. },
  100. ));
  101. }).toList()),
  102. ),
  103. ),
  104. ),
  105. ValueListenableBuilder(
  106. valueListenable: _valueNotifierChoice,
  107. builder: (_, _value, __) => _tags.isEmpty
  108. ? RequestLoadingWidget()
  109. : _tags
  110. .where((element) => element.name == _value)
  111. .map((e) => Column(
  112. crossAxisAlignment: CrossAxisAlignment.start,
  113. children: <Widget>[
  114. SizedBox(
  115. height: 15,
  116. ),
  117. Row(
  118. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  119. children: <Widget>[
  120. Text(
  121. "目标强度:",
  122. style: Theme.of(context).textTheme.subtitle1,
  123. ),
  124. Text(e.intension, style: Theme.of(context).textTheme.subtitle1.copyWith(color: Theme.of(context).accentColor))
  125. ],
  126. ),
  127. space,
  128. Row(
  129. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  130. children: <Widget>[
  131. Text(
  132. "每日目标时长:",
  133. style: Theme.of(context).textTheme.subtitle1,
  134. ),
  135. e.name != _customName
  136. ? Text("${e.duration}分钟", style: Theme.of(context).textTheme.subtitle1.copyWith(color: Theme.of(context).accentColor))
  137. : !widget.editCustom
  138. ? Text("${e.duration}分钟", style: Theme.of(context).textTheme.subtitle1.copyWith(color: Theme.of(context).accentColor))
  139. : Container(
  140. width: 70,
  141. height: 35,
  142. child: Row(
  143. crossAxisAlignment: CrossAxisAlignment.end,
  144. children: <Widget>[
  145. Expanded(
  146. child: TextField(
  147. controller: _textEditingController,
  148. textAlign: TextAlign.right,
  149. maxLength: 3,
  150. maxLines: 1,
  151. style: Theme.of(context).textTheme.subtitle1.copyWith(color: Theme.of(context).accentColor),
  152. keyboardType: TextInputType.number,
  153. onTap: () {
  154. _textEditingController.clear();
  155. ScrollToBottomNotification().dispatch(context);
  156. },
  157. onChanged: (v) {
  158. if (v.length > 3) return;
  159. int inputValue = int.parse(v);
  160. int value = min(999, inputValue);
  161. // _textEditingController.text = "$value";
  162. e.duration = value;
  163. e.consume = kal(e.duration.toDouble());
  164. TargetNotification(target: e).dispatch(context);
  165. _customDuration = e.duration.toDouble();
  166. setState(() {});
  167. },
  168. decoration: InputDecoration(
  169. counterText: '',
  170. contentPadding: EdgeInsets.zero,
  171. floatingLabelBehavior: FloatingLabelBehavior.never,
  172. border: UnderlineInputBorder(
  173. borderSide: BorderSide(color: Theme.of(context).accentColor),
  174. ),
  175. enabledBorder: UnderlineInputBorder(
  176. borderSide: BorderSide(color: Theme.of(context).accentColor),
  177. ),
  178. focusedBorder: UnderlineInputBorder(
  179. borderSide: BorderSide(color: Theme.of(context).accentColor),
  180. ))),
  181. ),
  182. Padding(
  183. padding: const EdgeInsets.only(bottom: 2.0),
  184. child: Text("分钟", style: Theme.of(context).textTheme.subtitle1),
  185. ),
  186. ],
  187. ),
  188. )
  189. ],
  190. ),
  191. if (e.name == _customName)
  192. Stack(
  193. children: <Widget>[
  194. Padding(
  195. padding: const EdgeInsets.fromLTRB(18.0, 30.0, 14.0, 0),
  196. child: Row(
  197. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  198. children: <Widget>[
  199. Text(
  200. " 0 ",
  201. style: TextStyle(fontSize: 12),
  202. ),
  203. Text(
  204. " 100",
  205. style: TextStyle(fontSize: 12),
  206. ),
  207. Text(
  208. " 200",
  209. style: TextStyle(fontSize: 12),
  210. ),
  211. Text(
  212. "300",
  213. style: TextStyle(fontSize: 12),
  214. ),
  215. ],
  216. ),
  217. ),
  218. Slider(
  219. activeColor: Theme.of(context).accentColor,
  220. inactiveColor: Color(0xfff1f1f1),
  221. min: 0,
  222. max: 300,
  223. onChanged: (double value) {
  224. setState(() {
  225. e.duration = value.toInt();
  226. e.consume = kal(value);
  227. TargetNotification(target: e).dispatch(context);
  228. _customDuration = value;
  229. _textEditingController.text = '${e.duration}';
  230. });
  231. },
  232. value: min(_customDuration, 300),
  233. )
  234. ],
  235. ),
  236. space,
  237. Row(
  238. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  239. children: <Widget>[
  240. Text(
  241. "每日预计消耗:",
  242. style: Theme.of(context).textTheme.subtitle1,
  243. ),
  244. Text("${e.consume}kal", style: Theme.of(context).textTheme.subtitle1.copyWith(color: Theme.of(context).accentColor))
  245. ],
  246. ),
  247. space,
  248. if (e.fitPeople?.isNotEmpty == true)
  249. Row(
  250. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  251. children: <Widget>[
  252. Text(
  253. "适用人群:",
  254. style: Theme.of(context).textTheme.subtitle1,
  255. ),
  256. Text(e.fitPeople, style: Theme.of(context).textTheme.subtitle1.copyWith(color: Theme.of(context).accentColor))
  257. ],
  258. ),
  259. space,
  260. space,
  261. Row(
  262. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  263. children: <Widget>[
  264. Expanded(
  265. child: Divider(
  266. endIndent: 24.0,
  267. ),
  268. ),
  269. Text(
  270. "相当于",
  271. style: Theme.of(context).textTheme.bodyText1,
  272. ),
  273. Expanded(
  274. child: Divider(
  275. indent: 24.0,
  276. ),
  277. )
  278. ],
  279. ),
  280. Padding(
  281. padding: const EdgeInsets.fromLTRB(0, 10, 0, 5),
  282. child: Center(child: sportBeEquivalentTo(context, e.consume, highlight: true)),
  283. ),
  284. space,
  285. Center(
  286. child: Text(
  287. "提示:请依据个人情况选择最适合自己的运动强度",
  288. style: Theme.of(context).textTheme.subtitle2.copyWith(color: Color(0xffFF5B1D)),
  289. ),
  290. )
  291. ],
  292. ))
  293. .single),
  294. ],
  295. );
  296. return widget.padding
  297. ? BoxWidget(
  298. body: body,
  299. )
  300. : body;
  301. }
  302. }
  303. class TargetNotification extends Notification {
  304. TargetNotification({
  305. @required this.target,
  306. });
  307. final SportTarget target;
  308. }