import 'package:fis_i18n/i18n.dart'; import 'package:fis_jsonrpc/rpc.dart'; import 'package:fis_lib_qrcode/qr_flutter.dart'; import 'package:fis_measure/interfaces/process/player/play_controller.dart'; import 'package:fis_measure/interfaces/process/standard_line/calibration.dart'; import 'package:fis_measure/interfaces/process/workspace/application.dart'; import 'package:fis_measure/interfaces/process/workspace/measure_3d_view_controller.dart'; import 'package:fis_measure/process/workspace/measure_3d_view_controller.dart'; import 'package:fis_measure/process/workspace/measure_data_controller.dart'; import 'package:fis_measure/process/workspace/measure_handler.dart'; import 'package:fis_measure/utils/prompt_box.dart'; import 'package:fis_measure/view/loadding/loadding.dart'; import 'package:fis_measure/view/paint/ai_patint_controller.dart'; import 'package:fis_measure/view/player/controller.dart'; import 'package:fis_ui/index.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; // import 'package:url_launcher/url_launcher.dart'; class FMenuButtonGroup extends FStatefulWidget { final VoidCallback capturePng; const FMenuButtonGroup({ Key? key, required this.capturePng, }) : super(key: key); @override FState createState() => _FMenuButtonGroupState(); } class _FMenuButtonGroupState extends FState { // 单个按钮高度 static const double buttonHeight = 42; // 按钮外边距 static const double buttonMargin = 10; // 单个按钮总高度 = Content(42)+Margin(10) static const double singleButtonHeight = 52; // 按钮组宽度 static const double buttonGroupWidth = 60; // 按钮组容器底部内边距 30 + 30 static const double groupContainerPadding = buttonGroupWidth / 2; // 按钮组容器展开的高度 get countGroupHeight => buildTitleButtonList().length * singleButtonHeight + groupContainerPadding * 2; final application = Get.find(); /// 数据 final measureData = Get.find(); final playerController = Get.find() as VidPlayerController; final measure3DViewController = Get.find(); late final measureHandler = Get.find(); late final aiPatintController = Get.find(); late bool canShowAI = [ DiagnosisConclusionEnum.Benign, DiagnosisConclusionEnum.Malignant, DiagnosisConclusionEnum.BenignAndMalignant ].contains(measureData.diagnosisConclusion); double groupHeight = 0; bool isExpanded = true; bool ifShowModeButton = false; bool ifShowVidModeButton = true; get isShell => measure3DViewController.isShell; get exist3DData => measure3DViewController.exist3DData; @override void initState() { super.initState(); groupHeight = countGroupHeight; measure3DViewController.updatePlayerMode.addListener(_onModeChanged); } @override void dispose() { measure3DViewController.updatePlayerMode.removeListener(_onModeChanged); super.dispose(); } /// 模式改变触发更新 void _onModeChanged(Object s, MeasureMode mode) { switch (mode) { case MeasureMode.vidMode: setState(() { ifShowModeButton = false; ifShowVidModeButton = true; groupHeight = countGroupHeight; isExpanded = true; }); break; case MeasureMode.carotid2DMode: setState(() { ifShowModeButton = true; ifShowVidModeButton = false; groupHeight = countGroupHeight; isExpanded = true; }); break; case MeasureMode.carotid3DMode: setState(() { ifShowModeButton = false; ifShowVidModeButton = false; }); break; } } List buildTitleButtonList() { return [ _buildTitleButton( FIcons.fis_quash, i18nBook.common.revoke.t, () => application.undoRecord(), ), _buildTitleButton( FIcons.fis_purge, i18nBook.measure.clear.t, () => application.clearRecords(), ), _buildTitleButton( measureHandler.fullScreenState ? FIcons.fis_full_screen_reduction : FIcons.fis_full_screen, measureHandler.fullScreenState ? i18nBook.common.cancel.t + i18nBook.measure.fullScreen.t : i18nBook.measure.fullScreen.t, () { measureHandler.fullScreenState = !measureHandler.fullScreenState; setState(() {}); }, ), _buildTitleButton( measureHandler.toolPanelState ? Icons.cancel_presentation : Icons.present_to_all, measureHandler.toolPanelState ? "关闭测量" : "打开测量", () { measureHandler.toolPanelState = !measureHandler.toolPanelState; setState(() {}); }, ), _buildTitleButton( FIcons.fis_save, i18nBook.common.save.t, widget.capturePng, ), _buildTitleButton( FIcons.fis_share, i18nBook.remedical.share.t, () async { var itemCurrentImage = await measureData.shareImage.call( measureData.itemCurrentImage, ); Get.dialog(_buildShareQRCode(itemCurrentImage)); }, ), //第三方图像需要校准线 if (application.isThirdPart) ...[ _buildTitleButton( FIcons.device, i18nBook.remedical.calibrationLine.t, () { Get.find().enterEditMode(); }, ), ], //AI结果隐藏按钮 if (canShowAI) ...[ _buildTitleButton( !aiPatintController.state.ifShowAi ? FIcons.fis_eye_display : FIcons.fis_eye_hidden, !aiPatintController.state.ifShowAi ? i18nBook.measure.showAi.t : i18nBook.measure.hideAi.t, () { aiPatintController.state.ifShowAi = !aiPatintController.state.ifShowAi; setState(() {}); }, ), ], //进入颈动脉3D模式 if (isShell && exist3DData && ifShowVidModeButton) ...[ _buildTitleButton( FIcons.three_dimensional, i18nBook.measure.carotid3DMode.t, () { measure3DViewController.changeModeTo3DMode(); }, ), ], //从颈动脉2D返回到【测量】或【3D】 if (isShell && exist3DData && ifShowModeButton) ...[ _buildTitleButton( FIcons.three_dimensional, i18nBook.measure.carotid3DMode.t, () { measure3DViewController.backTo3DMode(); }, ), _buildTitleButton( Icons.play_circle_outline_rounded, i18nBook.measure.vidMode.t, () { measure3DViewController.backToVidMode(); playerController.resetCurrentFrame(); }, ), ] ]; } @override FWidget build(BuildContext context) { return FRow( children: [ FExpanded(child: FContainer()), FColumn( verticalDirection: VerticalDirection.up, mainAxisAlignment: MainAxisAlignment.end, children: [ QuickFWidget(Transform.translate( offset: const Offset(0, -buttonGroupWidth / 2), child: FAnimatedContainer( duration: const Duration(milliseconds: 300), padding: const EdgeInsets.only( top: groupContainerPadding, bottom: groupContainerPadding / 2, ), decoration: BoxDecoration( borderRadius: const BorderRadius.only( bottomLeft: Radius.circular(buttonGroupWidth / 2), bottomRight: Radius.circular(buttonGroupWidth / 2), ), color: Colors.grey.withOpacity(0.6), ), clipBehavior: Clip.hardEdge, width: buttonGroupWidth, height: groupHeight, child: FColumn( children: buildTitleButtonList(), )))), _buildDropDownButton(), const FSizedBox(height: 10), ], ) ], ); } FWidget _buildTitleButton(IconData icon, String title, Function onClick) { return FContainer( height: buttonHeight, margin: const EdgeInsets.only( top: buttonMargin, ), child: FInkWell( onTap: () => onClick.call(), child: Column( children: [ Icon( icon, color: Colors.white, ), Text( title, style: const TextStyle( color: Colors.white, fontSize: 14, ), ) ], ), ), ); } FWidget _buildDropDownButton() { return FInkWell( onHover: (isHover) { if (isHover && !isExpanded) { setState(() { groupHeight = countGroupHeight; isExpanded = true; }); } }, onTap: () { if (isExpanded) { setState(() { groupHeight = groupContainerPadding; isExpanded = false; }); } else { setState(() { groupHeight = countGroupHeight; isExpanded = true; }); } }, child: FContainer( decoration: const BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(buttonGroupWidth / 2)), color: Colors.white, ), padding: const EdgeInsets.only(top: 15), height: buttonGroupWidth, width: buttonGroupWidth, child: FColumn( children: [ if (isExpanded) ...[ FText(i18nBook.measure.collapseGroup.t), const FIcon(Icons.arrow_drop_up) ] else ...[ FText(i18nBook.measure.expandGroup.t), const FIcon(Icons.arrow_drop_down) ] ], ), )); } FWidget _buildShareQRCode(String itemCurrentImage) { return FSimpleDialog( title: FText( i18nBook.remedical.share.t, style: const TextStyle( color: Colors.white, fontSize: 18, ), ), isDefault: false, children: [ FContainer( width: 360, child: FContainer( padding: const EdgeInsets.only(top: 20, bottom: 20), child: QRCodeWithLogo( itemCurrentImage, codeStatement: i18nBook.remedical.scanQrCodeToShareImage.t, operationStatement: i18nBook.remedical.copyLink.t, operationSuccessCallback: () => {PromptBox.toast(i18nBook.remedical.copySuccess.t)}, ), ), ), ], ); } }