game_settings.dart 5.6 KB

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