measure_configuation_page.dart 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. import 'dart:convert';
  2. import 'package:fis_i18n/i18n.dart';
  3. import 'package:fis_jsonrpc/rpc.dart';
  4. import 'package:fis_measure/define.dart';
  5. import 'package:fis_measure/interfaces/process/items/terms.dart';
  6. import 'package:fis_measure/interfaces/process/player/play_controller.dart';
  7. import 'package:fis_measure/interfaces/process/workspace/application.dart';
  8. import 'package:fis_measure/process/language/measure_language.dart';
  9. import 'package:fis_measure/process/workspace/measure_data_controller.dart';
  10. import 'package:fis_measure/process/workspace/measure_handler.dart';
  11. import 'package:fis_measure/view/measure/measure_config/widgets/has_selected_setting_dialog.dart';
  12. import 'package:fis_measure/view/measure/measure_config/widgets/measure_configuration_style.dart';
  13. import 'package:fis_measure/view/measure/measure_config/widgets/measure_configuration_unit.dart';
  14. import 'package:fis_measure/view/measure/measure_config/widgets/measurement_tool_selection.dart';
  15. import 'package:fis_measure/view/measure/measure_view_controller.dart';
  16. import 'package:fis_measure/view/player/controller.dart';
  17. import 'package:fis_theme/theme.dart';
  18. import 'package:fis_ui/index.dart';
  19. import 'package:fis_ui/interface/interactive_container.dart';
  20. import 'package:flutter/material.dart';
  21. import 'package:get/get.dart';
  22. import '../../gesture/positioned_cursor.dart';
  23. ///条目元数据组
  24. class ItemMetaGroup {
  25. ItemMetaGroup(
  26. this.itemMetaGroupTitle,
  27. this.itemMeta,
  28. this.isExpend,
  29. );
  30. /// 当前测量组的名称
  31. final String itemMetaGroupTitle;
  32. /// 当前测量组的测量数组
  33. final List<ItemMetaDTO> itemMeta;
  34. /// 是否展开
  35. bool? isExpend;
  36. }
  37. /// 测量工具配置
  38. class MeasureConfigurationPage extends StatefulWidget
  39. implements FWidget, FInteractiveContainer {
  40. @override
  41. final String pageName = 'MeasureConfigurationDialog';
  42. const MeasureConfigurationPage({
  43. Key? key,
  44. required this.ifHideConfig,
  45. }) : super(key: key);
  46. final bool ifHideConfig;
  47. @override
  48. State<MeasureConfigurationPage> createState() =>
  49. MeasureConfigurationPageState();
  50. }
  51. class MeasureConfigurationPageState extends State<MeasureConfigurationPage> {
  52. int measureToolsTab = 0;
  53. /// 切换标签栏
  54. void changeTab(int index) {
  55. measureToolsTab = index;
  56. setState(() {});
  57. }
  58. late final application = Get.find<IApplication>();
  59. late final measureHandler = Get.find<MeasureHandler>();
  60. final playerController = Get.find<IPlayerController>() as VidPlayerController;
  61. /// 数据
  62. final measureData = Get.find<MeasureDataController>();
  63. final mouseState = Get.find<IMouseState>();
  64. /// 测量项控制器
  65. final measureMetaController = Get.find<MeasureMetaController>();
  66. /// 之前保存的的测量项
  67. List<String> savedMeasureList = [];
  68. /// 选中的测量项
  69. List<String> chooseMeasureList = [];
  70. List<ItemMetaGroup> itemMetaListGroup = [];
  71. String activeName = '';
  72. List<MeasureModeDTO> measureMode = [];
  73. /// 缓存先前的设置
  74. String oldMeasureSystemSettingStr = '';
  75. Future<void> getName() async {
  76. List<String> getModes = [];
  77. for (var element in playerController.currentFrame?.visuals[0].modes ?? []) {
  78. getModes.add(element.type.toString().split('.')[1]);
  79. }
  80. var measureModeSelection = MeasureModeSelection(
  81. application.applicationName,
  82. application.categoryName,
  83. application.isThirdPart ? ['TPPTissue'] : getModes,
  84. );
  85. measureHandler.measureModeChanged = measureModeSelection;
  86. measureData.getMeasureApplicationList = [];
  87. var measureApplicationDTO =
  88. await measureData.getMeasureApplication.call(measureModeSelection);
  89. if (measureApplicationDTO != null) {
  90. /// 模式版本
  91. measureData.measureApplicationVersion =
  92. measureApplicationDTO.version ?? '';
  93. measureData.availableModes = measureApplicationDTO.availableModes ?? [];
  94. measureMetaController.setAvailableModes(measureData.currentMode);
  95. activeName = measureData.curItemMetaList[0].name;
  96. }
  97. }
  98. /// 保存测量项和测量设置
  99. void saveMeasureListAndMeasureSetting() async {
  100. /// 判断两个数组是否相同
  101. if (savedMeasureList.toString() != chooseMeasureList.toString() ||
  102. measureData.itemMetaListConfig.isNotEmpty) {
  103. var measureModeSubmitChanged = MeasureModeSubmit(
  104. measureData.measureApplicationVersion,
  105. application.applicationName,
  106. application.categoryName,
  107. UserDefinedMeasureModeDTO(
  108. modeName: measureData.currentMode,
  109. workingGroups: [
  110. UserDefinedMeasureGroupDTO(
  111. name: 'General',
  112. folders: [
  113. UserDefinedMeasureFolderDTO(
  114. name: 'General',
  115. workingItemNames: chooseMeasureList,
  116. itemMetas: measureData.itemMetaListConfig,
  117. ),
  118. ],
  119. ),
  120. ],
  121. ),
  122. );
  123. measureHandler.measureModeSubmitChanged = measureModeSubmitChanged;
  124. await measureData.saveUserDefinedMeasureApplicationAsync
  125. .call(measureModeSubmitChanged);
  126. getName();
  127. measureMetaController.setAvailableModes(measureData.currentMode);
  128. }
  129. saveMeasureSystemSettingAsync();
  130. }
  131. /// 还原测量项
  132. void resetMeasureList() {
  133. chooseMeasureList = measureData.getMeasureApplicationList;
  134. measureData.availableModes = measureMode;
  135. measureMetaController.setMeasureConfigItemMetaList();
  136. }
  137. /// 还原测量配置
  138. void resetMeasureSetting() {
  139. measureData.measureSystemSetting = MeasureSystemSettingDTO.fromJson(
  140. jsonDecode(oldMeasureSystemSettingStr));
  141. }
  142. /// 还原并退出
  143. void onCancel() async {
  144. String kMeasureSystemSettingStr =
  145. jsonEncode(measureData.measureSystemSetting.toJson());
  146. final bool conifgChanged =
  147. !isTheSameConfig(oldMeasureSystemSettingStr, kMeasureSystemSettingStr);
  148. final bool measureItemChanged =
  149. savedMeasureList.toString() != chooseMeasureList.toString();
  150. if (conifgChanged || measureItemChanged) {
  151. FConfirmAlert.show(
  152. context: Get.context!,
  153. title: i18nBook.common.tip.t,
  154. subTitle: "设置发生变更,是否需要保存?",
  155. confrimLabel: "保存并退出",
  156. cancelLabel: "不保存",
  157. // confrimLabel: i18nBook.common.confirm.t,
  158. // cancelLabel: i18nBook.common.cancel.t,
  159. businessParent: widget,
  160. onConfirm: () async {
  161. _saveAndExit();
  162. setState(() {});
  163. },
  164. onCancel: () async {
  165. _resetAndExit();
  166. setState(() {});
  167. },
  168. );
  169. } else {
  170. _saveAndExit();
  171. setState(() {});
  172. }
  173. }
  174. bool isTheSameConfig(String config1, String config2) {
  175. MeasureSystemSettingDTO measureSystemSetting1 =
  176. MeasureSystemSettingDTO.fromJson(jsonDecode(config1));
  177. MeasureSystemSettingDTO measureSystemSetting2 =
  178. MeasureSystemSettingDTO.fromJson(jsonDecode(config2));
  179. return jsonEncode(measureSystemSetting1.toJson()) ==
  180. jsonEncode(measureSystemSetting2.toJson());
  181. }
  182. /// 保存并退出
  183. void _saveAndExit() async {
  184. saveMeasureListAndMeasureSetting();
  185. Get.back();
  186. }
  187. /// 还原并退出
  188. void _resetAndExit() {
  189. resetMeasureSetting();
  190. resetMeasureList();
  191. saveMeasureSystemSettingAsync();
  192. Get.back();
  193. }
  194. // 保存修改测量样式
  195. Future<void> saveMeasureSystemSettingAsync() async {
  196. measureData.measureSystemSettingChanged
  197. .emit(this, measureData.measureSystemSetting);
  198. await measureData
  199. .saveMeasureSystemSettingAsync(measureData.measureSystemSetting);
  200. mouseState.cursorType = getMeasureSystemSettingCursorType(
  201. measureData.measureSystemSetting.cursorType);
  202. mouseState.cursorSize =
  203. measureData.measureSystemSetting.cursorSize as double;
  204. }
  205. @override
  206. void initState() {
  207. super.initState();
  208. List<String> chooseMeasure = [];
  209. if (widget.ifHideConfig) {
  210. measureToolsTab = 2;
  211. }
  212. measureMetaController.measureConfig();
  213. itemMetaListGroup = measureData.itemMetaListGroup;
  214. chooseMeasure = measureData.getMeasureApplicationList
  215. .where((element) => !MeasureUnsupportedTerms.items.contains(element))
  216. .toList();
  217. // 将原始列表转换为JSON字符串
  218. String jsonString = jsonEncode(measureData.availableModes);
  219. // 将JSON字符串转换回对象列表
  220. List<dynamic> jsonList = jsonDecode(jsonString);
  221. measureMode =
  222. jsonList.map((json) => MeasureModeDTO.fromJson(json)).toList();
  223. savedMeasureList = chooseMeasure.toSet().toList();
  224. chooseMeasureList = chooseMeasure.toSet().toList();
  225. oldMeasureSystemSettingStr =
  226. jsonEncode(measureData.measureSystemSetting.toJson());
  227. }
  228. @override
  229. void dispose() {
  230. super.dispose();
  231. }
  232. @override
  233. FWidget build(BuildContext context) {
  234. return FStack(
  235. children: [
  236. QuickFWidget(
  237. ModalBarrier(
  238. color: Colors.black.withOpacity(0.5),
  239. onDismiss: () {
  240. onCancel();
  241. },
  242. ),
  243. ),
  244. FSimpleDialog(
  245. title: FText(
  246. i18nBook.user.setting.t,
  247. style: const TextStyle(
  248. color: Colors.white,
  249. fontSize: 18,
  250. ),
  251. ),
  252. cancelString: i18nBook.common.cancel.t,
  253. okString: i18nBook.common.confirm.t,
  254. isDefault: true,
  255. onOk: () {
  256. _saveAndExit();
  257. },
  258. onCancel: () {
  259. onCancel();
  260. },
  261. children: [
  262. FContainer(
  263. width: 830,
  264. height: 500,
  265. child: _buildMeasureconfiguration(),
  266. ),
  267. ],
  268. ),
  269. ],
  270. );
  271. }
  272. FWidget _buildMeasureconfiguration() {
  273. return FContainer(
  274. padding: const EdgeInsets.symmetric(horizontal: 15),
  275. child: FRow(
  276. crossAxisAlignment: CrossAxisAlignment.start,
  277. children: [
  278. FContainer(
  279. width: 170,
  280. decoration: const BoxDecoration(
  281. border: Border(
  282. right: BorderSide(
  283. color: Color.fromRGBO(235, 235, 235, 1),
  284. width: 1,
  285. ),
  286. ),
  287. ),
  288. child: FColumn(
  289. crossAxisAlignment: CrossAxisAlignment.end,
  290. children: [
  291. const FSizedBox(
  292. height: 10,
  293. ),
  294. if (!widget.ifHideConfig)
  295. _buildTabButton(0, i18nBook.measure.measureToolSelect.t),
  296. if (!widget.ifHideConfig)
  297. _buildTabButton(1, i18nBook.measure.selectedMeasureTool.t),
  298. _buildTabButton(2, i18nBook.measure.measureStyleConfig.t),
  299. _buildTabButton(3, i18nBook.measure.measureUnitConfig.t),
  300. ],
  301. ),
  302. ),
  303. FExpanded(
  304. child: FStack(
  305. fit: StackFit.passthrough,
  306. children: [
  307. FOffstage(
  308. offstage: measureToolsTab != 0,
  309. child: FSingleChildScrollView(
  310. child: SelectModulePage(
  311. itemMetaListGroup: itemMetaListGroup,
  312. chooseMeasureList: chooseMeasureList,
  313. ),
  314. ),
  315. ),
  316. FOffstage(
  317. offstage: measureToolsTab != 1,
  318. child: _HasSelectedModulePage(
  319. chooseMeasureList: chooseMeasureList,
  320. ),
  321. ),
  322. FOffstage(
  323. offstage: measureToolsTab != 2,
  324. child: StyleConfigPage(
  325. businessParent: widget,
  326. ),
  327. ),
  328. FOffstage(
  329. offstage: measureToolsTab != 3,
  330. child: UnitConfigPage(
  331. businessParent: widget,
  332. ),
  333. ),
  334. ],
  335. )),
  336. ],
  337. ),
  338. );
  339. }
  340. FWidget _buildTabButton(int index, String title) {
  341. return FContainer(
  342. width: 160,
  343. child: FInkWell(
  344. onTap: () {
  345. changeTab(index);
  346. },
  347. child: FContainer(
  348. padding: const EdgeInsets.symmetric(
  349. vertical: 10,
  350. horizontal: 5,
  351. ),
  352. child: FText(
  353. title,
  354. style: measureToolsTab == index
  355. ? TextStyle(
  356. color: FTheme.ins.colorScheme.primary,
  357. )
  358. : const TextStyle(),
  359. textAlign: TextAlign.end,
  360. ),
  361. ),
  362. ),
  363. );
  364. }
  365. }
  366. class _HasSelectedModulePage extends StatelessWidget implements FWidget {
  367. final List<String> chooseMeasureList;
  368. /// 数据
  369. final measureData = Get.find<MeasureDataController>();
  370. /// 测量项控制器
  371. final measureMetaController = Get.find<MeasureMetaController>();
  372. /// 测量语言包
  373. final measureLanguage = MeasureLanguage();
  374. _HasSelectedModulePage({
  375. required this.chooseMeasureList,
  376. });
  377. /// 打开已选测量工具设置
  378. ///
  379. /// [itemMeta] 测量的对象
  380. void openHasSelectedSettingDialog(ItemMetaDTO itemMeta) {
  381. Get.dialog(HasSelectedSettingDialog(itemMeta: itemMeta));
  382. }
  383. @override
  384. FWidget build(BuildContext context) {
  385. return FListView(
  386. shrinkWrap: true,
  387. children: [
  388. FColumn(
  389. crossAxisAlignment: CrossAxisAlignment.start,
  390. children: [
  391. FContainer(
  392. padding: const EdgeInsets.only(left: 15, top: 15, bottom: 15),
  393. child: FWrap(
  394. spacing: 16.0, // 主轴(水平)方向间距
  395. runSpacing: 8.0, // 纵轴(垂直)方向间距
  396. direction: Axis.horizontal,
  397. crossAlignment: WrapCrossAlignment.center,
  398. alignment: WrapAlignment.start,
  399. children: List<FWidget>.generate(
  400. chooseMeasureList.length,
  401. (index) {
  402. return FInkWell(
  403. onTap: () {
  404. var item = measureMetaController
  405. .setMeasureConfigItemMetaList()
  406. .firstWhere((element) =>
  407. element.description ==
  408. chooseMeasureList[index]);
  409. openHasSelectedSettingDialog(item);
  410. },
  411. child: FContainer(
  412. width: 180,
  413. height: 60,
  414. decoration: BoxDecoration(
  415. border: Border.all(
  416. width: 0.5,
  417. color: FTheme.ins.colorScheme.primary,
  418. ),
  419. ),
  420. child: FColumn(
  421. mainAxisAlignment: MainAxisAlignment.center,
  422. children: [
  423. if (!i18nBook.isCurrentEnglish)
  424. FText(
  425. measureLanguage.t(
  426. 'measure',
  427. chooseMeasureList[index].toString(),
  428. ),
  429. style: const TextStyle(
  430. color: Colors.black,
  431. ),
  432. ),
  433. FText(
  434. chooseMeasureList[index].toString(),
  435. style: const TextStyle(
  436. color: Colors.black,
  437. ),
  438. ),
  439. ],
  440. ),
  441. // ),
  442. ),
  443. );
  444. },
  445. ),
  446. ),
  447. ),
  448. ],
  449. ),
  450. ],
  451. );
  452. }
  453. }