123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- 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/measure/operate_type_change_button.dart';
- import 'package:fis_measure/view/paint/ai_patint_controller.dart';
- import 'package:fis_measure/view/player/controller.dart';
- import 'package:fis_ui/base_define/page.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,
- required this.businessParent,
- }) : super(key: key);
- final FPage businessParent;
- @override
- FState<FMenuButtonGroup> createState() => _FMenuButtonGroupState();
- }
- class _FMenuButtonGroupState extends FState<FMenuButtonGroup> {
- // 单个按钮高度
- static const double buttonHeight = 30;
- // 按钮外边距
- static const double buttonMargin = 10;
- // 单个按钮总高度 = Content(42)+Margin(10)
- // static const double singleButtonHeight = buttonHeight + buttonMargin;
- // 按钮组宽度
- static const double buttonGroupWidth = 60;
- // 按钮组容器底部内边距 30 + 30
- static const double groupContainerPadding = buttonGroupWidth / 2;
- /// 获取当前组件最大高度
- get maxGroupHeight => Get.height - 200;
- final application = Get.find<IApplication>();
- /// 数据
- final measureData = Get.find<MeasureDataController>();
- final playerController = Get.find<IPlayerController>() as VidPlayerController;
- final measure3DViewController = Get.find<Measure3DViewController>();
- late final measureHandler = Get.find<MeasureHandler>();
- late final aiPatintController = Get.find<AiPatintController>();
- 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 = maxGroupHeight;
- 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 = maxGroupHeight;
- isExpanded = true;
- });
- break;
- case MeasureMode.carotid2DMode:
- setState(() {
- ifShowModeButton = true;
- ifShowVidModeButton = false;
- groupHeight = maxGroupHeight;
- isExpanded = true;
- });
- break;
- case MeasureMode.carotid3DMode:
- setState(() {
- ifShowModeButton = false;
- ifShowVidModeButton = false;
- });
- break;
- }
- }
- List<FWidget> buildTitleButtonList() {
- return [
- _buildTitleButton(
- FIcons.fis_quash,
- i18nBook.common.revoke.t,
- () => application.undoRecord(),
- ),
- _buildTitleButton(
- FIcons.fis_purge,
- i18nBook.measure.clear.t,
- () => application.clearRecords(),
- ),
- OperateTypeChangeButton(businessParent: widget.businessParent),
- _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(
- 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<IStandardLineCalibrationController>().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.antiAlias,
- width: buttonGroupWidth,
- // height: groupHeight,
- constraints: BoxConstraints(
- maxHeight: groupHeight,
- ),
- child: FListView(
- shrinkWrap: true,
- children: buildTitleButtonList(),
- ))),
- ),
- _buildDropDownButton(),
- const FSizedBox(height: 10),
- ],
- )
- ],
- );
- }
- FWidget _buildTitleButton(IconData icon, String title, Function onClick) {
- return FCustomLeftTooltip(
- textStyle: const TextStyle(fontSize: 16, color: Colors.white),
- height: 36,
- message: title,
- verticalOffset: 0,
- margin: const EdgeInsets.all(0),
- decoration: BoxDecoration(
- color: Colors.black.withOpacity(1.0),
- borderRadius: BorderRadius.circular(4),
- ),
- child: FContainer(
- height: buttonHeight,
- margin: const EdgeInsets.only(
- top: buttonMargin,
- ),
- child: FInkWell(
- onTap: () => onClick.call(),
- child: Icon(
- icon,
- color: Colors.white,
- ),
- ),
- ),
- );
- }
- FWidget _buildDropDownButton() {
- return FInkWell(
- onHover: (isHover) {
- if (isHover && !isExpanded) {
- setState(() {
- groupHeight = maxGroupHeight;
- isExpanded = true;
- });
- }
- },
- onTap: () {
- if (isExpanded) {
- setState(() {
- groupHeight = groupContainerPadding;
- isExpanded = false;
- });
- } else {
- setState(() {
- groupHeight = maxGroupHeight;
- 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)},
- ),
- ),
- ),
- ],
- );
- }
- }
- /// TODO:[Gavin] 定制组件,可与主项目的 FCustomRightTooltip 合并整合进 ui lib
- class FCustomLeftTooltip extends FStatefulWidget {
- const FCustomLeftTooltip({
- super.key,
- this.message,
- this.height,
- this.padding,
- this.margin,
- this.verticalOffset,
- this.decoration,
- this.textStyle,
- this.child,
- }) : super();
- final String? message;
- final double? height;
- final EdgeInsetsGeometry? padding;
- final EdgeInsetsGeometry? margin;
- final double? verticalOffset;
- final Decoration? decoration;
- final TextStyle? textStyle;
- final FWidget? child;
- @override
- FState<FCustomLeftTooltip> createState() => FCustomLeftTooltipState();
- }
- class FCustomLeftTooltipState extends FState<FCustomLeftTooltip> {
- OverlayEntry? _entry;
- void _showTooltip() {
- _createNewEntry();
- }
- void _hideTooltip() {
- _entry?.remove();
- _entry = null;
- }
- void _createNewEntry() {
- final OverlayState overlayState = Overlay.of(
- context,
- debugRequiredFor: widget,
- );
- final RenderBox box = context.findRenderObject()! as RenderBox;
- final RenderBox boxConatiner =
- overlayState.context.findRenderObject() as RenderBox;
- final Offset target = box.localToGlobal(
- box.size.center(Offset.zero),
- ancestor: overlayState.context.findRenderObject(),
- );
- final Offset leftSide = Offset(
- boxConatiner.size.width - (target.dx - box.size.width / 2),
- target.dy - (widget.height ?? 26) / 2,
- );
- final Widget overlay = Directionality(
- textDirection: Directionality.of(context),
- child: Positioned(
- right: leftSide.dx,
- top: leftSide.dy,
- child: Container(
- decoration: widget.decoration ??
- BoxDecoration(
- color: Colors.black.withOpacity(0.7),
- borderRadius: BorderRadius.circular(4),
- ),
- height: widget.height ?? 26,
- padding: widget.padding ?? const EdgeInsets.symmetric(horizontal: 8),
- margin: widget.margin ?? const EdgeInsets.only(left: 10),
- child: Center(
- child: Text(
- widget.message ?? '',
- style: widget.textStyle,
- ),
- ),
- ),
- ),
- );
- _entry = OverlayEntry(builder: (BuildContext context) => overlay);
- overlayState.insert(_entry!);
- }
- @override
- FWidget build(BuildContext context) {
- return FMouseRegion(
- onEnter: (event) {
- _showTooltip();
- },
- onExit: (event) {
- _hideTooltip();
- },
- child: FContainer(
- child: widget.child,
- ),
- );
- }
- @override
- void dispose() {
- super.dispose();
- if (_entry != null) {
- _entry?.remove();
- _entry = null;
- }
- }
- }
|