import 'package:fis_common/logger/logger.dart'; import 'package:fis_i18n/i18n.dart'; import 'package:fis_measure/interfaces/process/items/item.dart'; import 'package:fis_measure/interfaces/process/items/item_metas.dart'; import 'package:fis_measure/interfaces/process/items/terms.dart'; import 'package:fis_measure/interfaces/process/player/play_controller.dart'; import 'package:fis_measure/interfaces/process/workspace/application.dart'; import 'package:fis_measure/process/language/measure_language.dart'; import 'package:fis_measure/process/workspace/measure_data_controller.dart'; import 'package:fis_measure/process/workspace/measure_handler.dart'; import 'package:fis_measure/view/measure/combo_widget.dart'; import 'package:fis_measure/view/measure/measure_view_controller.dart'; import 'package:fis_measure/view/player/controller.dart'; import 'package:fis_ui/index.dart'; import 'package:fis_ui/interface/interactive_container.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:vid/us/vid_us_image.dart'; /// 测量项页面 class LeftSiderSelectMeasure extends FStatefulWidget implements FInteractiveContainer { const LeftSiderSelectMeasure({Key? key}) : super(key: key); @override final String pageName = 'LeftSiderSelectMeasure'; @override FState createState() => LeftSiderSelectMeasureState(); } class LeftSiderSelectMeasureState extends FState { /// 数据 get application => Get.find(); get playerController => Get.find() as VidPlayerController; final measureHandler = Get.find(); final measureData = Get.find(); final measureMetaController = Get.find(); /// 测量语言包 final measureLanguage = MeasureLanguage(); /// 当前选中的测量项下标 int activeItemIndex = 0; /// 当前选中的子测量项下标 int activeChildItemIndex = 0; /// Styles late String fontFamily; static const Color buttonBackgroundColor = Color.fromRGBO(70, 70, 70, 1); static const Color buttonBorderColor = Color.fromRGBO(124, 124, 124, 1); static const Color buttonBorderHighlight = Color.fromRGBO(124, 124, 124, 1); static const Color buttonTextColor = Colors.white; static const Color childButtonHighlight = Color.fromRGBO(84, 144, 249, 1); static const Color childContainerBackground = Color.fromRGBO(60, 60, 60, 1); static const double buttonBorderHighlightWidth = 1.0; /// 触发测量项选中事件 void selectItem(int selectIndex) { if (selectIndex == activeItemIndex) return; final itemMeta = measureData.curItemMetaList[selectIndex]; changeItem(itemMeta); setState(() { activeItemIndex = selectIndex; activeChildItemIndex = 0; }); } /// 触发子测量项选中事件 void selectChildItem(int selectIndex) { if (selectIndex == activeChildItemIndex) return; final item = application.activeMeasureItem!; if (item is ITopMeasureItem) { item.switchChild(selectIndex); activeChildItemIndex = selectIndex; } setState(() {}); } /// 切换测量项 void changeItem(ItemMeta itemMeta) { try { application.switchItem(itemMeta); final item = application.activeMeasureItem!; if (item is ITopMeasureItem) { item.switchChild(0); item.workingChildChanged.addListener(_onWorkingChildChanged); } } catch (e) { logger.e("changeItem failed", e); } if (mounted) { setState(() {}); } } /// 子测量项变化事件监听 void _onWorkingChildChanged(sender, int e) { setState(() { activeChildItemIndex = e; }); } void _onItemMetaListChanged(Object s, dynamic e) { try { if (e != null) { setState(() {}); } } catch (e) { debugPrint("ItemMetaListChanged fail " + e.toString()); } } /// 首帧加载完成事件监听: 获取当前图像的测量项,从第一帧取 void _onFirstFrameLoaded(Object sender, VidUsImage e) async { if (!mounted) return; _getMeasureItemsList(e); _getAnnotationList(); } //初始化时尝试加载第一项测量项(如果有的话) void _loadFirstItem() { if (measureData.curItemMetaList.isNotEmpty) { final itemMeta = measureData.curItemMetaList.first; changeItem(itemMeta); setState(() { activeItemIndex = 0; activeChildItemIndex = 0; }); } } /// 注释获取 void _getAnnotationList() async { List annotationList = []; var measureCommentItemResult = await measureData.getCommentsByApplicationAsync( application.applicationName, application.categoryName, ); measureData.measureCommentItemResult = measureCommentItemResult?.commentItems ?? []; measureCommentItemResult?.commentItems?.forEach((element) { annotationList.add(element.text ?? ''); }); measureData.annotationList = annotationList; measureHandler.onAnnotationsLoaded(); } void _getMeasureItemsList(VidUsImage e) async { List getModes = []; for (var element in e.visuals[0].modes) { getModes.add(element.type.toString().split('.')[1]); } measureData.applicationModes = e.visuals[0].modes; measureData.currentMode = e.visuals[0].modes.first.type.name; var measureModeSelection = MeasureModeSelection( application.applicationName, application.categoryName, application.isThirdPart ? ['TPPTissue'] : getModes, ); measureHandler.measureModeChanged = measureModeSelection; var measureApplicationDTO = await measureData.getMeasureApplication.call(measureModeSelection); if (measureApplicationDTO != null) { measureData.measureApplicationVersion = measureApplicationDTO.version ?? ''; measureData.availableModes = measureApplicationDTO.availableModes ?? []; if (application.isThirdPart) { measureData.currentMode = 'TPPTissue'; } measureMetaController.setAvailableModes(measureData.currentMode); setState(() {}); } } /// 测量项列表变化事件监听 void _onCurItemMetaListChanged(sender, e) { if (measureData.curItemMetaList.isNotEmpty) { changeItem(measureData.curItemMetaList[0]); } setState(() {}); } @override void initState() { measureData.curItemMetaListChanged.addListener(_onCurItemMetaListChanged); measureData.itemMetaListChanged.addListener(_onItemMetaListChanged); WidgetsBinding.instance.addPostFrameCallback((call) { _loadFirstItem(); playerController.firstFrameLoaded.addListener(_onFirstFrameLoaded); }); super.initState(); } @override dispose() { super.dispose(); playerController.firstFrameLoaded.removeListener(_onFirstFrameLoaded); measureData.curItemMetaListChanged .removeListener(_onCurItemMetaListChanged); measureData.itemMetaListChanged.removeListener(_onItemMetaListChanged); final item = application.activeMeasureItem; if (item != null && item is ITopMeasureItem) { item.workingChildChanged.removeListener(_onWorkingChildChanged); } } @override FWidget build(BuildContext context) { fontFamily = Theme.of(context).textTheme.labelLarge!.fontFamily!; return buildItemsListView(measureData.curItemMetaList); } /// 构建测量项列表 FWidget buildItemsListView(List itemMetaList) { return FListView( shrinkWrap: true, controller: ScrollController(), children: List.generate(itemMetaList.length, (i) { return _buildItemContainer(i); })); } /// 构建测量项容器 FWidget _buildItemContainer(int itemMetaIndex) { final itemMeta = measureData.curItemMetaList[itemMetaIndex]; final isActived = itemMetaIndex == activeItemIndex; // 是否选中 final hasChildItem = itemMeta.childItems.isNotEmpty; //是否为组合测量项 return FContainer( decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), border: isActived && hasChildItem ? Border.all( color: buttonBorderHighlight, width: buttonBorderHighlightWidth) : null, ), margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 5), child: FColumn(children: [ if (isActived && hasChildItem) ...[ _buildItemTitle(itemMetaIndex), _buildChildItemContainer(itemMeta), ] else FContainer( width: double.infinity, child: _buildItemButton(itemMetaIndex), ), ]), ); } // 构建测量项按钮 FWidget _buildItemButton(int itemIndex) { final itemMeta = measureData.curItemMetaList[itemIndex]; final ifShowCN = i18nBook.isCurrentChinese && // 中文环境下显示中英文,否则只显示英文 measureLanguage.t('measure', itemMeta.description) != itemMeta.description; final isActived = itemIndex == activeItemIndex; return FElevatedButton( name: itemMeta.name, businessParent: widget, onPressed: () => selectItem(itemIndex), child: FColumn( mainAxisAlignment: MainAxisAlignment.center, children: [ if (ifShowCN) FText( measureLanguage.t('measure', itemMeta.description), maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( color: isActived ? null : buttonTextColor, fontFamily: fontFamily, fontSize: 12, ), ), FText( itemMeta.description, style: TextStyle( color: isActived ? null : buttonTextColor, ), ), ], ), style: ElevatedButton.styleFrom( backgroundColor: isActived ? null : buttonBackgroundColor, fixedSize: const Size.fromHeight( 50, ), side: BorderSide( color: isActived ? Colors.transparent : buttonBorderColor, ), ), ); } // 构建测量项标签【用于组合测量项顶部】 FWidget _buildItemTitle(int itemIndex) { final itemMeta = measureData.curItemMetaList[itemIndex]; final ifShowCN = i18nBook.isCurrentChinese && // 中文环境下显示中英文,否则只显示英文 measureLanguage.t('measure', itemMeta.description) != itemMeta.description; return FContainer( decoration: const BoxDecoration( border: Border( bottom: BorderSide( color: buttonBorderHighlight, width: buttonBorderHighlightWidth), ), ), child: FSizedBox( height: 50, width: double.infinity, child: FColumn( mainAxisAlignment: MainAxisAlignment.center, children: [ if (ifShowCN) FText( measureLanguage.t('measure', itemMeta.description), maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( color: buttonTextColor, fontFamily: fontFamily, fontSize: 12, ), ), FText( itemMeta.description, style: const TextStyle( color: buttonTextColor, ), ), ], ), ), ); } /// 子测量项容器 FWidget _buildChildItemContainer(ItemMeta itemMeta) { final activeName = itemMeta.description; final isSpecial = MeasurespecialsupportedTerms.items.contains(activeName); if (isSpecial) { //是否为特殊组合测量项 return const SpecialItemHR(); } else { return FContainer( decoration: const BoxDecoration( color: childContainerBackground, borderRadius: BorderRadius.only( bottomLeft: Radius.circular(5), bottomRight: Radius.circular(5)), ), padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 5), child: FColumn( children: (itemMeta.childItems) .asMap() .entries .map( (e) => _buildChildItemButton( e.value, e.key, ), ) .toList(), ), ); } } // 构建子测量项按钮 FWidget _buildChildItemButton(ItemMeta itemMeta, int childItemIndex) { final isActived = childItemIndex == activeChildItemIndex; return FContainer( width: double.infinity, margin: const EdgeInsetsDirectional.all(5), child: FElevatedButton( businessParent: widget, name: "selectChildItemIdnex:$childItemIndex", onPressed: () { selectChildItem(childItemIndex); }, child: FText( itemMeta.description, ), style: ElevatedButton.styleFrom( backgroundColor: isActived ? null : buttonBackgroundColor, side: BorderSide( color: isActived ? Colors.transparent : buttonBorderColor, ), ), )); } }