game_settings.dart 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import 'package:flutter/material.dart';
  2. import 'package:trackoffical_app/generated/assets.dart';
  3. import 'package:trackoffical_app/screen.dart';
  4. import 'package:trackoffical_app/service/app.dart';
  5. import 'package:trackoffical_app/service/mock.dart';
  6. import 'package:trackoffical_app/service/user_profile.dart';
  7. import 'package:trackoffical_app/view/sport_wear_select_view.dart';
  8. import '../service/sport_wear.dart';
  9. import '../widget/app_top_bar.dart';
  10. import 'package:get/get.dart';
  11. class GameSettingsView extends StatefulWidget {
  12. const GameSettingsView({super.key, this.isInGame = false});
  13. final bool isInGame;
  14. @override
  15. State<StatefulWidget> createState() {
  16. return _GameSettingsState();
  17. }
  18. }
  19. class _GameSettingsState extends State<GameSettingsView> {
  20. @override
  21. void initState() {
  22. super.initState();
  23. if(!widget.isInGame){
  24. profile.cleanGameSettingsLock();
  25. setState(() {});
  26. }
  27. }
  28. final SportWearService _sp = Get.find();
  29. final profile = App.to.userProfile;
  30. Widget listView(String title, GameSettingsValue value, Widget trailing, {bool show=true}) {
  31. if(!show){
  32. return const SizedBox();
  33. }
  34. return ListTile(
  35. title: Row(
  36. mainAxisSize: MainAxisSize.min,
  37. children: [
  38. Text(
  39. title,
  40. style: TextStyle(fontSize: 4.44.wp),
  41. ),
  42. SizedBox(width: 3.0.wp),
  43. widget.isInGame
  44. ? Image.asset(
  45. value.isLocked ? Assets.imagesIcLock : Assets.imagesIcLockOpen,
  46. height: 3.69.wp,
  47. )
  48. : const SizedBox()
  49. ],
  50. ),
  51. trailing: trailing);
  52. }
  53. Widget listViewSwitch<S>(String title, GameSettingsValue<bool, S> value, {bool show=true}) {
  54. return listView(
  55. title,
  56. value,
  57. Switch(
  58. activeColor: Colors.blue,
  59. value: value.value,
  60. onChanged: value.isLocked
  61. ? null
  62. : (v) {
  63. setState(() {
  64. value.value = v;
  65. });
  66. }),
  67. show: show
  68. );
  69. }
  70. Widget listViewMenu<T, S>(String title, GameSettingsValue<T, S> value, List<T> menu,
  71. String Function(T) fmt) {
  72. final menuList = menu
  73. .map((e) => MenuItemButton(
  74. onPressed: () => setState(() {
  75. value.value = e;
  76. }),
  77. child: MenuAcceleratorLabel(fmt(e)),
  78. ))
  79. .toList();
  80. return listView(
  81. title,
  82. value,
  83. SizedBox(
  84. height: 46,
  85. width: 94,
  86. child: value.isLocked
  87. ? Text(fmt(value.value))
  88. : SubmenuButton(
  89. menuChildren: menuList,
  90. trailingIcon: const Icon(Icons.arrow_drop_down, size: 20),
  91. child: Text(fmt(value.value)),
  92. ),
  93. ));
  94. }
  95. Widget listViewSP(){
  96. return ListTile(
  97. title: Text('心率带', style: TextStyle(fontSize: 4.44.wp),),
  98. trailing: Row(
  99. mainAxisSize: MainAxisSize.min,
  100. children: [
  101. Obx(() {
  102. final wear = _sp.connectedSportWear.value;
  103. return wear != null ? Text(wear.name) : const Text('未连接');
  104. }),
  105. const Icon(Icons.keyboard_arrow_right)
  106. ],
  107. ),
  108. onTap: showSportWearSelectDialog,
  109. );
  110. }
  111. @override
  112. Widget build(BuildContext context) {
  113. final children = <Widget>[];
  114. final isInGame = widget.isInGame;
  115. if (isInGame) {
  116. children.add(listViewMenu('地图模式', profile.gameSettingsUIMode,
  117. GameUIMode.values, (m){
  118. var text = '';
  119. switch(m){
  120. case GameUIMode.electronicMap:
  121. text = '电子';
  122. break;
  123. case GameUIMode.noMap:
  124. text = '无图';
  125. break;
  126. case GameUIMode.paperMap:
  127. text = '纸质';
  128. break;
  129. }
  130. return text;
  131. }));
  132. }
  133. if (isInGame) {
  134. children.add(listViewSP());
  135. }
  136. children.addAll([
  137. listViewSwitch('简单显示面板', profile.gameSettingsSimpleDashboard),
  138. listViewSwitch('边界报警', profile.gameSettingsBoundaryWarn, show: isInGame),
  139. listViewMenu('轨迹长度', profile.gameSettingsTrackLengthSeconds,
  140. [60, 90, 120], (v) => '$v秒'),
  141. listViewSwitch('显示我的位置', profile.gameSettingsShowMyLocation),
  142. listViewSwitch('开始提示', profile.gameSettingsStartRemind),
  143. listViewSwitch('声音提示', profile.gameSettingsSoundPrompt),
  144. listViewSwitch('震动提示', profile.gameSettingsVibrationPrompt),
  145. listViewSwitch('打点文创', profile.gameSettingsShowOriginality, show: isInGame),
  146. listViewSwitch('指北针真北', profile.gameSettingsRealNorth),
  147. listViewSwitch('允许GPS场控', profile.gameSettingsGpsTrack),
  148. listViewMenu('打点半径', profile.gameSettingsPunchRadiusMeter,
  149. [2, 3, 5], (v) => '$v米'),
  150. listViewSwitch('路线预览', profile.gameSettingsRoutePreview),
  151. listViewSwitch('打点错误提示', profile.gameSettingsPunchErrorPrompt),
  152. listViewSwitch('热区提醒', profile.gameSettingsHotZonePrompt),
  153. // listViewSwitch('虚拟点打点方式', profile.gameSettingsRoutePreview),
  154. ]);
  155. return Scaffold(
  156. appBar:
  157. AppTopBar(title: const Text('设置'), automaticallyImplyLeading: true),
  158. body: ListView(
  159. children: children,
  160. ),
  161. );
  162. }
  163. }
  164. void main() {
  165. Mock.initServices();
  166. runPreview(const GameSettingsView());
  167. }