import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:trackoffical_app/screen.dart'; import 'package:trackoffical_app/utils.dart'; import 'package:vector_math/vector_math_64.dart' as vec; import '../../../widget/compass2.dart'; import '../game_std/utils.dart'; import '../widget_ruler2.dart'; import 'game_compass_top4_data.dart'; export 'game_compass_top4_data.dart'; export 'game_compass_button.dart'; export 'package:flutter/material.dart'; class GameCompassController{ final heartRatePercent = 0.0.obs; final isNoMapRulerScaleMode=false.obs; final duration = 0.seconds.obs; final compassRadians= 0.0.obs; final nextPointRadians= 0.0.obs; final heartRate = 0.obs; final stepCount=0.obs; final kCal= 0.0.obs; final ck= 0.0.obs; final ei= 0.0.obs; /// 地图比例尺 1:[userSetMapScale] final Rx userSetMapScale = Rx(null); } class GameCompassBase extends StatelessWidget{ const GameCompassBase({ super.key, required this.controller, required this.top4data, required this.topButtons, required this.process, this.compassDiameter=230, required this.isShowNextPointer, required this.isEnableRuler, required this.bottomCenterButton, }); static const _hPadding = 60.0; final GameCompassController controller; final List top4data; final List topButtons; final Widget? process; final double compassDiameter; final bool isShowNextPointer; final bool isEnableRuler; final Widget bottomCenterButton; @override Widget build(BuildContext context) { return Scaffold( body: DefaultTextStyle( style: const TextStyle(color: Colors.white), child: Stack( children: [ Obx(() => Container( decoration: BoxDecoration( color: controller.heartRatePercent.value.round().toHRPColor()), width: context.width, height: context.height, )), Obx(() => !controller.isNoMapRulerScaleMode.value ? const Ruler2(isScaleMode: false) : const SizedBox()), Container( padding: EdgeInsets.only( top: context.mediaQueryPadding.top, left: _hPadding, right: _hPadding), width: context.width, child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const SizedBox(height: 20), _topButtonBar(), _wDuration(), _process(), _topElemHub(), _compass(), _heartRate(), _sports(), _bottomBar(), ])), Obx(() => controller.isNoMapRulerScaleMode.value && isEnableRuler ? Ruler2( isScaleMode: true, onReturn: () => controller.isNoMapRulerScaleMode.value = false, mapScale: controller.userSetMapScale.value) : const SizedBox(height: 0)) ], ), )); } Widget _topButtonBar() { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: topButtons, ); } Widget _wDuration() { return Obx(() => Text(controller.duration.value.toAppString(), maxLines: 1, style: const TextStyle( fontSize: 29, fontFamily: 'sa-digital-number', ))); } Widget _process() { final w = process; return w!= null?DefaultTextStyle(style: const TextStyle( fontSize: 32, ), child: w): const SizedBox(); } Widget _topElemHub() { final rows = []; final titles = []; final divider = SizedBox(width: 2.78.wp); rows.add(Row( children: [ top4data[0], divider, top4data[1], ], )); titles.addAll([ Positioned( left: 0, top: 0, child: _getSmallTitle(top4data[0].title) ), Positioned( right: 0, top: 0, child: _getSmallTitle(top4data[1].title) ), ]); if(top4data.length==4){ rows.add(SizedBox(height: 2.78.wp)); rows.add(Row( children: [ top4data[2], divider, top4data[3], ], )); titles.addAll([ Positioned( left: 0, bottom: 0, child: _getSmallTitle(top4data[2].title) ), Positioned( right: 0, bottom: 0, child: _getSmallTitle(top4data[3].title) ), ]); } final stacks = [ Column( children: rows, ) ]; stacks.addAll(titles); return Stack( children: stacks, ) ; } Widget _getSmallTitle(String title){ return Container( alignment: Alignment.center, padding: const EdgeInsets.only(left: 3, right: 3), decoration: const BoxDecoration(color: Colors.black), child: Text(title, style: const TextStyle( fontSize:11, color: Colors.white, fontWeight: FontWeight.w700)) ); } Widget _compass() { return Obx(() { final radians = controller.compassRadians.value; return Compass2( compassRadians: radians, mapNorthRadians: radians, nextPointRadians: isShowNextPointer? controller.nextPointRadians.value: null, level: 1, showDegrees: vec.degrees(radians).compassDegrees, diameter: compassDiameter, nextPointImage: Image.asset('assets/images/im_compass_next_arrow2.png'), nextPointHeight: 100, degreeColor: Colors.white, plantSrc: 'assets/images/im_compass_no_map.png', ); } ); } Widget _heartRate() { return Obx(() => Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ wHrp(), Container( width: 1, height: 53, color: Colors.white.withAlpha((255 * 0.3).round())), wHr(), ], )); } Widget wHrp() { final hrp = controller.heartRatePercent.value.round(); return Row( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('$hrp', style: const TextStyle(fontSize: 43, fontWeight: FontWeight.w700)), const Text('%', style: TextStyle(fontSize: 20, fontWeight: FontWeight.w700)) ], ); } Widget wHr() { return Row( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('${controller.heartRate.value}', style: const TextStyle(fontSize: 43, fontWeight: FontWeight.w700)), Padding( padding: const EdgeInsets.only(top: 5), child: Image.asset('assets/images/ic_heart.png', height: 14.4)) ], ); } Widget _sports() { const style = TextStyle(fontSize: 15.24, fontWeight: FontWeight.w500); return Obx(() => Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ wSport( '${controller.stepCount.value}', 'assets/images/ic_step_count.png', textStyle: style), wSport(controller.kCal.value.toStringAsFixed(1), 'assets/images/ic_kcal.png', textStyle: style), wSport( controller.ck.value.toStringAsFixed(1), 'assets/images/ic_ck.png', textStyle: style), wSport(controller.ei.round().toString(), 'assets/images/ic_ei.png', textStyle: style), ], )); } Widget _bottomBar() { return Padding( padding: const EdgeInsets.only(bottom: 20, left: 20, right: 20), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.end, children: [ isEnableRuler? GestureDetector( onTap: _onSetMapScale, child: Image.asset('assets/images/btn_ruler_scale_no_map.png', width: 46, )): const SizedBox(), bottomCenterButton, isEnableRuler? GestureDetector( onTap: () => controller.isNoMapRulerScaleMode.value = true, child: Image.asset( 'assets/images/btn_ruler_no_map.png', width: 46, )): const SizedBox() ], )); } _onSetMapScale() { var value = controller.userSetMapScale.value?.toString() ?? ''; Get.dialog(AlertDialog( title: const Text('设置比例尺'), content: Row( children: [ const Text( '1 :', style: TextStyle(fontSize: 16), ), const SizedBox( width: 6, ), SizedBox( width: 120, child: TextField( onChanged: (v) { value = v; }, keyboardType: TextInputType.number, controller: TextEditingController.fromValue( TextEditingValue(text: value)))), ], ), actions: [ TextButton( onPressed: () { Get.back(); }, child: const Text('取消')), TextButton( onPressed: () { controller.userSetMapScale.value = double.tryParse(value)!; Get.back(); }, child: const Text('确定')), ], )); } }