import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:trackoffical_app/service/game/game_model.dart'; import 'package:trackoffical_app/styles/theme.dart'; import 'package:trackoffical_app/utils.dart'; import 'package:trackoffical_app/view/ingame/utils.dart'; import '../../model/m_control_point.dart'; import 'in_game_controller.dart'; class BottomBar extends GetView { BottomBar({super.key}); final _model = Get.find(); @override Widget build(BuildContext context) { return Obx(() { final duration = controller.beginDurationStr; final next = _model.nextPlanPoint; final hrp = _model.heartRatePercent.value.round(); var color = hrp.toHRPColor(); var cpChecked = _model.validCPCount; return SizedBox( height: InGameController.bottomBarHeight, width: context.width, child: PageView( scrollDirection: Axis.horizontal, children: [ BottomBar1( color: color, duration: duration, myPositionHistoryLenKm: _model.myPositionHistoryLen.value.km, targetDistanceKm: controller.nextControlPointDistanceKm, paceSecond: _model.paceSecondKm.value, nextCp: next, cpAll: _model.validCPAllNum, cpChecked: cpChecked, distance: _model.widgetDistance(fontSize: 21, withTrip: !controller.isInGameUISimplifyMode), pace: _model.widgetPace(fontSize: 21, withTrip: !controller.isInGameUISimplifyMode)), BottomBar2( color: color, duration: duration, cpAll: _model.validCPAllNum, cpChecked: cpChecked, hr: _model.heartRate.value, hrp: hrp, stepCount: _model.stepCount.value, kCal: _model.kCal.value, ck: _model.ck.value, ei: _model.ei.value) ], ) ) ; }); } } Widget wDuration(String duration) { return Text(duration, style: const TextStyle(fontSize: 20, fontFamily: 'sa-digital-number')); } Widget elemCp(MControlPoint? nextCp) { Widget text; const style = TextStyle(fontSize: 26, fontWeight: FontWeight.w700); if (nextCp != null) { text = nextCp.display(textStyle: style); if (nextCp.areaId.isNotEmpty && nextCp.type == MControlPointType.nfc) { text = Row( mainAxisSize: MainAxisSize.min, children: [ text, Text( ' (${nextCp.areaId})', style: style, ) ], ); } } else { text = const Text('--', style: style, maxLines: 1); } return text; } Widget wKm(double? km, double fontSize, {FontWeight? fontWeight}) { var unit = ' km'; var value = '--'; if(km != null){ var i = km; if (km < 1) { unit = ' m'; i *= 1000; } value = i.round().toString(); } return RichText( text: TextSpan( text: value, style: TextStyle(fontSize: fontSize, fontWeight: fontWeight?? FontWeight.w500), children: [ TextSpan( text: unit, style: TextStyle(fontSize: fontSize* 0.5, fontWeight: FontWeight.w500)) ] )); } class BottomBar1 extends StatelessWidget { const BottomBar1({ super.key, required this.color, required this.duration, required this.myPositionHistoryLenKm, required this.targetDistanceKm, required this.paceSecond, required this.nextCp, required this.cpAll, required this.cpChecked, required this.distance, required this.pace, }); final Color color; final MControlPoint? nextCp; final String duration; final int cpAll; final int cpChecked; final double myPositionHistoryLenKm; final double? targetDistanceKm; final Duration paceSecond; final Widget distance; final Widget pace; @override Widget build(BuildContext context) { return Stack(children: [ _BottomBarContainer( color: color, children: [ elemCp(nextCp), wDuration(duration), getElemDistance(), wKm(targetDistanceKm, 26, fontWeight: FontWeight.w700), Text('$cpChecked/$cpAll', style: const TextStyle(fontSize: 32)), getElemPace() ], ), Positioned( left: 0, top: 0, child: getSmallTitle('目标') ), Positioned( right: 0, top: 0, child: getSmallTitle('里程') ), Positioned( left: 0, bottom: 0, child: getSmallTitle('点距') ), Positioned( right: 0, bottom: 0, child: getSmallTitle('配速') ), ],) ; } Widget getElemDistance(){ return Padding( padding: const EdgeInsets.only(left: 16, right: 16), child: distance) ; } Widget getElemPace(){ return Padding( padding: const EdgeInsets.only(left: 16, right: 16), child: pace) ; } } class BottomBar2 extends StatelessWidget { const BottomBar2({ super.key, required this.color, required this.duration, required this.cpAll, required this.cpChecked, required this.hr, required this.hrp, required this.stepCount, required this.kCal, required this.ck, required this.ei, }); final Color color; final int hr; final int hrp; final String duration; final int cpAll; final int cpChecked; final int stepCount; final double kCal; final double ck; final double ei; Widget wHrp() { 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('$hr', 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)) ], ); } @override Widget build(BuildContext context) { return _BottomBarContainer( color: color, children: [ wHrp(), wDuration(duration), wHr(), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ wSport('$stepCount', 'assets/images/ic_step_count.png'), const SizedBox(width: 12), wSport(kCal.toStringAsFixed(1), 'assets/images/ic_kcal.png'), ], ), Text('$cpChecked/$cpAll', style: const TextStyle(fontSize: 32)), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ wSport(ck.toStringAsFixed(1), 'assets/images/ic_ck.png'), const SizedBox(width: 12), wSport(ei.round().toString(), 'assets/images/ic_ei.png'), ], ), ], ); } } class _BottomBarContainer extends StatelessWidget { const _BottomBarContainer({required this.children, required this.color}); final List children; final Color color; @override Widget build(BuildContext context) { return DefaultTextStyle( style: const TextStyle(color: Colors.white), child: Container( width: context.width, height: InGameController.bottomBarHeight, decoration: BoxDecoration( color: color, image: const DecorationImage( image: AssetImage('assets/images/bk_ingame_bottom_bar.png'))), child: Column( children: [ Expanded( child: Row( children: [ Expanded(flex: 4, child: Center(child: children[0])), Expanded( flex: 6, child: Center(child: children[1]), ), Expanded(flex: 4, child: Center(child: children[2])), ], )), Expanded( child: Row( children: [ Expanded(flex: 4, child: Center(child: children[3])), Expanded(flex: 6, child: Center(child: children[4])), Expanded(flex: 4, child: Center(child: children[5])), ], )), ], ), )); } } void main() async { final b1 = BottomBar1( color: Colors.blue, nextCp: MControlPoint() ..isStart = true ..areaId = 'A51', targetDistanceKm: 1.234, duration: "00:00:00", cpAll: 18, cpChecked: 7, myPositionHistoryLenKm: 3.1, paceSecond: 380.seconds, distance: const SizedBox(), pace: const SizedBox(), ); final b2 = const BottomBar2( color: Colors.blue, duration: '00:00:00', cpAll: 18, cpChecked: 7, hr: 123, hrp: 80, stepCount: 0, kCal: 11231, ck: 2344, ei: 1231); var bottom = b1; runApp(GetMaterialApp( theme: appThemeData(), home: Scaffold( body: Column( children: [ Spacer(), bottom, ], )))); }