bottom_bar.dart 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. import 'package:trackoffical_app/service/game/game_model.dart';
  4. import 'package:trackoffical_app/styles/theme.dart';
  5. import 'package:trackoffical_app/utils.dart';
  6. import 'package:trackoffical_app/view/ingame/utils.dart';
  7. import '../../model/m_control_point.dart';
  8. import 'in_game_controller.dart';
  9. class BottomBar extends GetView<InGameController> {
  10. BottomBar({super.key});
  11. final _model = Get.find<GameModel>();
  12. @override
  13. Widget build(BuildContext context) {
  14. return Obx(() {
  15. final duration = controller.beginDurationStr;
  16. final next = _model.nextPlanPoint;
  17. final hrp = _model.heartRatePercent.value.round();
  18. var color = hrp.toHRPColor();
  19. var cpChecked = _model.validCPCount;
  20. return SizedBox(
  21. height: InGameController.bottomBarHeight,
  22. width: context.width,
  23. child: PageView(
  24. scrollDirection: Axis.horizontal,
  25. children: [
  26. BottomBar1(
  27. color: color,
  28. duration: duration,
  29. myPositionHistoryLenKm: _model.myPositionHistoryLen.value.km,
  30. targetDistanceKm: controller.nextControlPointDistanceKm,
  31. paceSecond: _model.paceSecondKm.value,
  32. nextCp: next,
  33. cpAll: _model.validCPAllNum,
  34. cpChecked: cpChecked,
  35. distance: _model.widgetDistance(fontSize: 21, withTrip: !controller.isInGameUISimplifyMode),
  36. pace: _model.widgetPace(fontSize: 21, withTrip: !controller.isInGameUISimplifyMode)),
  37. BottomBar2(
  38. color: color,
  39. duration: duration,
  40. cpAll: _model.validCPAllNum,
  41. cpChecked: cpChecked,
  42. hr: _model.heartRate.value,
  43. hrp: hrp,
  44. stepCount: _model.stepCount.value,
  45. kCal: _model.kCal.value,
  46. ck: _model.ck.value,
  47. ei: _model.ei.value)
  48. ],
  49. )
  50. ) ;
  51. });
  52. }
  53. }
  54. Widget wDuration(String duration) {
  55. return Text(duration,
  56. style: const TextStyle(fontSize: 20, fontFamily: 'sa-digital-number'));
  57. }
  58. Widget elemCp(MControlPoint? nextCp) {
  59. Widget text;
  60. const style = TextStyle(fontSize: 26, fontWeight: FontWeight.w700);
  61. if (nextCp != null) {
  62. text = nextCp.display(textStyle: style);
  63. if (nextCp.areaId.isNotEmpty && nextCp.type == MControlPointType.nfc) {
  64. text = Row(
  65. mainAxisSize: MainAxisSize.min,
  66. children: [
  67. text,
  68. Text(
  69. ' (${nextCp.areaId})',
  70. style: style,
  71. )
  72. ],
  73. );
  74. }
  75. } else {
  76. text = const Text('--', style: style, maxLines: 1);
  77. }
  78. return text;
  79. }
  80. Widget wKm(double? km, double fontSize, {FontWeight? fontWeight}) {
  81. var unit = ' km';
  82. var value = '--';
  83. if(km != null){
  84. var i = km;
  85. if (km < 1) {
  86. unit = ' m';
  87. i *= 1000;
  88. }
  89. value = i.round().toString();
  90. }
  91. return RichText(
  92. text: TextSpan(
  93. text: value,
  94. style: TextStyle(fontSize: fontSize, fontWeight: fontWeight?? FontWeight.w500),
  95. children: [
  96. TextSpan(
  97. text: unit,
  98. style: TextStyle(fontSize: fontSize* 0.5, fontWeight: FontWeight.w500))
  99. ]
  100. ));
  101. }
  102. class BottomBar1 extends StatelessWidget {
  103. const BottomBar1({
  104. super.key,
  105. required this.color,
  106. required this.duration,
  107. required this.myPositionHistoryLenKm,
  108. required this.targetDistanceKm,
  109. required this.paceSecond,
  110. required this.nextCp,
  111. required this.cpAll,
  112. required this.cpChecked,
  113. required this.distance,
  114. required this.pace,
  115. });
  116. final Color color;
  117. final MControlPoint? nextCp;
  118. final String duration;
  119. final int cpAll;
  120. final int cpChecked;
  121. final double myPositionHistoryLenKm;
  122. final double? targetDistanceKm;
  123. final Duration paceSecond;
  124. final Widget distance;
  125. final Widget pace;
  126. @override
  127. Widget build(BuildContext context) {
  128. return Stack(children: [
  129. _BottomBarContainer(
  130. color: color,
  131. children: [
  132. elemCp(nextCp),
  133. wDuration(duration),
  134. getElemDistance(),
  135. wKm(targetDistanceKm, 26, fontWeight: FontWeight.w700),
  136. Text('$cpChecked/$cpAll', style: const TextStyle(fontSize: 32)),
  137. getElemPace()
  138. ],
  139. ),
  140. Positioned(
  141. left: 0,
  142. top: 0,
  143. child: getSmallTitle('目标')
  144. ),
  145. Positioned(
  146. right: 0,
  147. top: 0,
  148. child: getSmallTitle('里程')
  149. ),
  150. Positioned(
  151. left: 0,
  152. bottom: 0,
  153. child: getSmallTitle('点距')
  154. ),
  155. Positioned(
  156. right: 0,
  157. bottom: 0,
  158. child: getSmallTitle('配速')
  159. ),
  160. ],) ;
  161. }
  162. Widget getElemDistance(){
  163. return Padding(
  164. padding: const EdgeInsets.only(left: 16, right: 16),
  165. child: distance) ;
  166. }
  167. Widget getElemPace(){
  168. return Padding(
  169. padding: const EdgeInsets.only(left: 16, right: 16),
  170. child: pace) ;
  171. }
  172. }
  173. class BottomBar2 extends StatelessWidget {
  174. const BottomBar2({
  175. super.key,
  176. required this.color,
  177. required this.duration,
  178. required this.cpAll,
  179. required this.cpChecked,
  180. required this.hr,
  181. required this.hrp,
  182. required this.stepCount,
  183. required this.kCal,
  184. required this.ck,
  185. required this.ei,
  186. });
  187. final Color color;
  188. final int hr;
  189. final int hrp;
  190. final String duration;
  191. final int cpAll;
  192. final int cpChecked;
  193. final int stepCount;
  194. final double kCal;
  195. final double ck;
  196. final double ei;
  197. Widget wHrp() {
  198. return Row(
  199. mainAxisSize: MainAxisSize.min,
  200. crossAxisAlignment: CrossAxisAlignment.start,
  201. children: [
  202. Text('$hrp',
  203. style: const TextStyle(fontSize: 43, fontWeight: FontWeight.w700)),
  204. const Text('%',
  205. style: TextStyle(fontSize: 20, fontWeight: FontWeight.w700))
  206. ],
  207. );
  208. }
  209. Widget wHr() {
  210. return Row(
  211. mainAxisSize: MainAxisSize.min,
  212. crossAxisAlignment: CrossAxisAlignment.start,
  213. children: [
  214. Text('$hr',
  215. style: const TextStyle(fontSize: 43, fontWeight: FontWeight.w700)),
  216. Padding(
  217. padding: const EdgeInsets.only(top: 5),
  218. child: Image.asset('assets/images/ic_heart.png', height: 14.4))
  219. ],
  220. );
  221. }
  222. @override
  223. Widget build(BuildContext context) {
  224. return _BottomBarContainer(
  225. color: color,
  226. children: [
  227. wHrp(),
  228. wDuration(duration),
  229. wHr(),
  230. Row(
  231. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  232. children: [
  233. wSport('$stepCount', 'assets/images/ic_step_count.png'),
  234. const SizedBox(width: 12),
  235. wSport(kCal.toStringAsFixed(1), 'assets/images/ic_kcal.png'),
  236. ],
  237. ),
  238. Text('$cpChecked/$cpAll', style: const TextStyle(fontSize: 32)),
  239. Row(
  240. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  241. children: [
  242. wSport(ck.toStringAsFixed(1), 'assets/images/ic_ck.png'),
  243. const SizedBox(width: 12),
  244. wSport(ei.round().toString(), 'assets/images/ic_ei.png'),
  245. ],
  246. ),
  247. ],
  248. );
  249. }
  250. }
  251. class _BottomBarContainer extends StatelessWidget {
  252. const _BottomBarContainer({required this.children, required this.color});
  253. final List<Widget> children;
  254. final Color color;
  255. @override
  256. Widget build(BuildContext context) {
  257. return DefaultTextStyle(
  258. style: const TextStyle(color: Colors.white),
  259. child: Container(
  260. width: context.width,
  261. height: InGameController.bottomBarHeight,
  262. decoration: BoxDecoration(
  263. color: color,
  264. image: const DecorationImage(
  265. image: AssetImage('assets/images/bk_ingame_bottom_bar.png'))),
  266. child: Column(
  267. children: [
  268. Expanded(
  269. child: Row(
  270. children: [
  271. Expanded(flex: 4, child: Center(child: children[0])),
  272. Expanded(
  273. flex: 6,
  274. child: Center(child: children[1]),
  275. ),
  276. Expanded(flex: 4, child: Center(child: children[2])),
  277. ],
  278. )),
  279. Expanded(
  280. child: Row(
  281. children: [
  282. Expanded(flex: 4, child: Center(child: children[3])),
  283. Expanded(flex: 6, child: Center(child: children[4])),
  284. Expanded(flex: 4, child: Center(child: children[5])),
  285. ],
  286. )),
  287. ],
  288. ),
  289. ));
  290. }
  291. }
  292. void main() async {
  293. final b1 = BottomBar1(
  294. color: Colors.blue,
  295. nextCp: MControlPoint()
  296. ..isStart = true
  297. ..areaId = 'A51',
  298. targetDistanceKm: 1.234,
  299. duration: "00:00:00",
  300. cpAll: 18,
  301. cpChecked: 7,
  302. myPositionHistoryLenKm: 3.1,
  303. paceSecond: 380.seconds,
  304. distance: const SizedBox(),
  305. pace: const SizedBox(),
  306. );
  307. final b2 = const BottomBar2(
  308. color: Colors.blue,
  309. duration: '00:00:00',
  310. cpAll: 18,
  311. cpChecked: 7,
  312. hr: 123,
  313. hrp: 80,
  314. stepCount: 0,
  315. kCal: 11231,
  316. ck: 2344,
  317. ei: 1231);
  318. var bottom = b1;
  319. runApp(GetMaterialApp(
  320. theme: appThemeData(),
  321. home: Scaffold(
  322. body: Column(
  323. children: [
  324. Spacer(),
  325. bottom,
  326. ],
  327. ))));
  328. }