in_game_no_map_view.dart 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. import 'package:trackoffical_app/utils.dart';
  4. import 'package:trackoffical_app/view/game_settings.dart';
  5. import 'package:screen_brightness/screen_brightness.dart';
  6. import '../sport_wear_select_view.dart';
  7. import 'button_punch.dart';
  8. import 'info_view.dart';
  9. import 'widget_ruler2.dart';
  10. import '../../widget/compass2.dart';
  11. import 'utils.dart';
  12. import 'settings_view.dart';
  13. import '../../service/app.dart';
  14. import '../../service/game/game.dart';
  15. import '../../service/game/game_model.dart';
  16. import '../../service/mock.dart';
  17. import '../../styles/color_schemes.g.dart';
  18. import 'in_game_controller.dart';
  19. class InGameNoMapView extends GetView<InGameController> {
  20. InGameNoMapView({super.key});
  21. static const _hPadding = 60.0;
  22. final _model = Get.find<GameModel>();
  23. @override
  24. Widget build(BuildContext context) {
  25. return Scaffold(
  26. body: DefaultTextStyle(
  27. style: const TextStyle(color: Colors.white),
  28. child: Stack(
  29. children: [
  30. Obx(() => Container(
  31. decoration: BoxDecoration(
  32. color: _model.heartRatePercent.value.round().toHRPColor()),
  33. width: context.width,
  34. height: context.height,
  35. )),
  36. Obx(() => !controller.isNoMapRulerScaleMode.value
  37. ? const Ruler2(isScaleMode: false)
  38. : const SizedBox()),
  39. Container(
  40. padding: EdgeInsets.only(
  41. top: context.mediaQueryPadding.top,
  42. left: _hPadding,
  43. right: _hPadding),
  44. width: context.width,
  45. child: Column(
  46. crossAxisAlignment: CrossAxisAlignment.center,
  47. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  48. children: [
  49. const SizedBox(height: 20),
  50. _topButtonBar(),
  51. _wDuration(),
  52. _process(),
  53. _topElemHub(),
  54. _compass(),
  55. _heartRate(),
  56. _sports(),
  57. _bottomBar(),
  58. ])),
  59. Obx(() => controller.isNoMapRulerScaleMode.value
  60. ? Ruler2(
  61. isScaleMode: true,
  62. onReturn: () =>
  63. controller.isNoMapRulerScaleMode.value = false,
  64. mapScale: controller.mapScale.value)
  65. : const SizedBox(height: 0))
  66. ],
  67. ),
  68. ));
  69. }
  70. Widget _wDuration() {
  71. return Obx(() => Text(controller.beginDurationStr,
  72. maxLines: 1,
  73. style: const TextStyle(
  74. fontSize: 29,
  75. fontFamily: 'sa-digital-number',
  76. )));
  77. }
  78. Widget _process() {
  79. return Obx(() => Text('${_model.validCPCount}/${_model.validCPAllNum}',
  80. maxLines: 1,
  81. style: const TextStyle(
  82. fontSize: 32,
  83. )));
  84. }
  85. Widget _nextCPDistance() {
  86. var unit = ' km';
  87. var value = '--';
  88. final km = controller.nextControlPointDistanceKm;
  89. if (km != null) {
  90. var i = km;
  91. if (km < 1) {
  92. unit = ' m';
  93. i *= 1000;
  94. }
  95. value = i.round().toString();
  96. }
  97. return RichText(
  98. text: TextSpan(
  99. text: value,
  100. style:
  101. const TextStyle(fontSize: 28.31, fontWeight: FontWeight.w500),
  102. children: [
  103. TextSpan(
  104. text: unit,
  105. style:
  106. const TextStyle(fontSize: 13.07, fontWeight: FontWeight.w500))
  107. ]));
  108. }
  109. Widget _topElemHub() {
  110. const space = 6.5;
  111. return Obx(() => Stack(
  112. children: [
  113. Column(
  114. children: [
  115. Row(children: [
  116. _Elem(
  117. child: _model.nextPlanPoint.display(
  118. textStyle: const TextStyle(
  119. fontSize: 21.78, fontWeight: FontWeight.w500))),
  120. const SizedBox(width: space),
  121. _Elem(
  122. child: Padding(
  123. padding: const EdgeInsets.only(left: 16, right: 16),
  124. child: _model.widgetDistance(
  125. withTrip: !controller.isInGameUISimplifyMode))),
  126. ]),
  127. const SizedBox(height: space),
  128. Row(children: [
  129. _Elem(child: _nextCPDistance()),
  130. const SizedBox(width: space),
  131. _Elem(
  132. child: Padding(
  133. padding: const EdgeInsets.only(left: 16, right: 16),
  134. child: _model.widgetPace(
  135. withTrip: !controller.isInGameUISimplifyMode))),
  136. ])
  137. ],
  138. ),
  139. Positioned(
  140. left: 0,
  141. top: 0,
  142. child: getSmallTitle('目标')
  143. ),
  144. Positioned(
  145. right: 0,
  146. top: 0,
  147. child: getSmallTitle('里程')
  148. ),
  149. Positioned(
  150. left: 0,
  151. bottom: 0,
  152. child: getSmallTitle('点距')
  153. ),
  154. Positioned(
  155. right: 0,
  156. bottom: 0,
  157. child: getSmallTitle('配速')
  158. ),
  159. ],
  160. ));
  161. }
  162. Widget _compass() {
  163. return Obx(() => Compass2(
  164. compassRadians: _model.compassRadiansSrc.value,
  165. mapNorthRadians: _model.compassRadiansSrc.value,
  166. nextPointRadians: controller.nextCPRadians,
  167. level: 1,
  168. showDegrees: _model.compassShowDegrees,
  169. diameter: 230,
  170. nextPointImage: Image.asset('assets/images/im_compass_next_arrow2.png'),
  171. nextPointHeight: 100,
  172. degreeColor: Colors.white,
  173. plantSrc: 'assets/images/im_compass_no_map.png',
  174. ));
  175. }
  176. Widget _heartRate() {
  177. return Obx(() => Row(
  178. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  179. children: [
  180. wHrp(),
  181. Container(
  182. width: 1,
  183. height: 53,
  184. color: Colors.white.withAlpha((255 * 0.3).round())),
  185. wHr(),
  186. ],
  187. ));
  188. }
  189. Widget wHrp() {
  190. final hrp = _model.heartRatePercent.value.round();
  191. return Row(
  192. mainAxisSize: MainAxisSize.min,
  193. crossAxisAlignment: CrossAxisAlignment.start,
  194. children: [
  195. Text('$hrp',
  196. style: const TextStyle(fontSize: 43, fontWeight: FontWeight.w700)),
  197. const Text('%',
  198. style: TextStyle(fontSize: 20, fontWeight: FontWeight.w700))
  199. ],
  200. );
  201. }
  202. Widget wHr() {
  203. return Row(
  204. mainAxisSize: MainAxisSize.min,
  205. crossAxisAlignment: CrossAxisAlignment.start,
  206. children: [
  207. Text('${_model.heartRate.value}',
  208. style: const TextStyle(fontSize: 43, fontWeight: FontWeight.w700)),
  209. Padding(
  210. padding: const EdgeInsets.only(top: 5),
  211. child: Image.asset('assets/images/ic_heart.png', height: 14.4))
  212. ],
  213. );
  214. }
  215. Widget _sports() {
  216. const style = TextStyle(fontSize: 15.24, fontWeight: FontWeight.w500);
  217. return Obx(() => Row(
  218. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  219. children: [
  220. wSport(
  221. '${_model.stepCount.value}', 'assets/images/ic_step_count.png',
  222. textStyle: style),
  223. wSport(_model.kCal.value.toStringAsFixed(1),
  224. 'assets/images/ic_kcal.png',
  225. textStyle: style),
  226. wSport(
  227. _model.ck.value.toStringAsFixed(1), 'assets/images/ic_ck.png',
  228. textStyle: style),
  229. wSport(_model.ei.round().toString(), 'assets/images/ic_ei.png',
  230. textStyle: style),
  231. ],
  232. ));
  233. }
  234. Widget _bottomBar() {
  235. return Obx(() => Padding(
  236. padding: const EdgeInsets.only(bottom: 20, left: 20, right: 20),
  237. child: Row(
  238. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  239. crossAxisAlignment: CrossAxisAlignment.end,
  240. children: [
  241. GestureDetector(
  242. onTap: _onSetMapScale,
  243. child: Image.asset('assets/images/btn_ruler_scale_no_map.png',
  244. width: 46,
  245. )),
  246. SizedBox(
  247. width: 56,
  248. height: 56,
  249. child: ButtonPunch(
  250. onPressed: controller.isCheckCPButtonEnable
  251. ? controller.onCheckControlPoint
  252. : null,
  253. isWarn: controller.isCheckCPButtonWarn,
  254. )),
  255. GestureDetector(
  256. onTap: () => controller.isNoMapRulerScaleMode.value = true,
  257. child: Image.asset(
  258. 'assets/images/btn_ruler_no_map.png',
  259. width: 46,
  260. ))
  261. ],
  262. )));
  263. }
  264. Widget _topButton({required VoidCallback onPressed, required String src}){
  265. return GestureDetector(
  266. onTap: onPressed,
  267. child: Image.asset(
  268. src,
  269. width: 34,
  270. height: 34,
  271. )
  272. );
  273. }
  274. Widget _topButtonBar() {
  275. return Row(
  276. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  277. children: [
  278. _topButton(
  279. onPressed: () => Get.to(() => InfoView()),
  280. src: 'assets/images/btn_info_no_map.png'
  281. ),
  282. _topButton(
  283. onPressed: (){},
  284. // showCheckedPoints,
  285. src: 'assets/images/btn_past_cp_no_map.png'
  286. ),
  287. _topButton(
  288. onPressed: _onBrightness,
  289. src: 'assets/images/btn_brightness_no_map.png'
  290. ),
  291. _topButton(
  292. onPressed: controller.toSettings,
  293. src: 'assets/images/btn_settings_no_map.png'
  294. ),
  295. _topButton(
  296. onPressed: ()=>onButtonExit(controller),
  297. src: 'assets/images/btn_exit_no_map.png'
  298. ),
  299. ],
  300. );
  301. }
  302. void _onBrightness()async{
  303. await controller.setIsBrightnessMax(!controller.isBrightnessMax);
  304. }
  305. _onSetMapScale() {
  306. var value = controller.mapScale.value?.toString() ?? '';
  307. Get.dialog(AlertDialog(
  308. title: const Text('设置比例尺'),
  309. content: Row(
  310. children: [
  311. const Text(
  312. '1 :',
  313. style: TextStyle(fontSize: 16),
  314. ),
  315. const SizedBox(
  316. width: 6,
  317. ),
  318. SizedBox(
  319. width: 120,
  320. child: TextField(
  321. onChanged: (v) {
  322. value = v;
  323. },
  324. keyboardType: TextInputType.number,
  325. controller: TextEditingController.fromValue(
  326. TextEditingValue(text: value)))),
  327. ],
  328. ),
  329. actions: [
  330. TextButton(
  331. onPressed: () {
  332. Get.back();
  333. },
  334. child: const Text('取消')),
  335. TextButton(
  336. onPressed: () {
  337. controller.mapScale.value = double.tryParse(value);
  338. Get.back();
  339. },
  340. child: const Text('确定')),
  341. ],
  342. ));
  343. }
  344. }
  345. class _Elem extends StatelessWidget {
  346. const _Elem({required this.child});
  347. final Widget child;
  348. @override
  349. Widget build(BuildContext context) {
  350. return Expanded(
  351. child: Container(
  352. height: 55,
  353. alignment: Alignment.center,
  354. decoration: BoxDecoration(
  355. color: const Color(0x29ffffff),
  356. border: Border.all(color: const Color(0x43ffffff), width: 1.09),
  357. borderRadius: BorderRadius.circular(2.18)),
  358. child: child,
  359. ));
  360. }
  361. }
  362. class _Home extends StatelessWidget {
  363. @override
  364. Widget build(BuildContext context) {
  365. return InGameNoMapView();
  366. }
  367. }
  368. void main() async {
  369. Mock.initServices();
  370. await App.to.init();
  371. Get.put(GameModel());
  372. Get.put(GameService());
  373. await GameService.to.gameStart();
  374. // await GameService.to.gameLoad();
  375. var c = InGameControllerMock();
  376. Get.put<InGameController>(c);
  377. runApp(GetMaterialApp(
  378. theme: ThemeData(useMaterial3: true, colorScheme: lightColorScheme),
  379. home: _Home()));
  380. }