menu_button_group.dart 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. import 'package:fis_i18n/i18n.dart';
  2. import 'package:fis_jsonrpc/rpc.dart';
  3. import 'package:fis_lib_qrcode/qr_flutter.dart';
  4. import 'package:fis_measure/interfaces/process/player/play_controller.dart';
  5. import 'package:fis_measure/interfaces/process/standard_line/calibration.dart';
  6. import 'package:fis_measure/interfaces/process/workspace/application.dart';
  7. import 'package:fis_measure/interfaces/process/workspace/measure_3d_view_controller.dart';
  8. import 'package:fis_measure/process/workspace/measure_3d_view_controller.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/utils/prompt_box.dart';
  12. import 'package:fis_measure/view/loadding/loadding.dart';
  13. import 'package:fis_measure/view/paint/ai_patint_controller.dart';
  14. import 'package:fis_measure/view/player/controller.dart';
  15. import 'package:fis_ui/index.dart';
  16. import 'package:flutter/material.dart';
  17. import 'package:get/get.dart';
  18. // import 'package:url_launcher/url_launcher.dart';
  19. class FMenuButtonGroup extends FStatefulWidget {
  20. final VoidCallback capturePng;
  21. const FMenuButtonGroup({
  22. Key? key,
  23. required this.capturePng,
  24. }) : super(key: key);
  25. @override
  26. FState<FMenuButtonGroup> createState() => _FMenuButtonGroupState();
  27. }
  28. class _FMenuButtonGroupState extends FState<FMenuButtonGroup> {
  29. // 单个按钮高度
  30. static const double buttonHeight = 42;
  31. // 按钮外边距
  32. static const double buttonMargin = 10;
  33. // 单个按钮总高度 = Content(42)+Margin(10)
  34. static const double singleButtonHeight = 52;
  35. // 按钮组宽度
  36. static const double buttonGroupWidth = 60;
  37. // 按钮组容器底部内边距 30 + 30
  38. static const double groupContainerPadding = buttonGroupWidth / 2;
  39. // 按钮组容器展开的高度
  40. get countGroupHeight =>
  41. buildTitleButtonList().length * singleButtonHeight +
  42. groupContainerPadding * 2;
  43. final application = Get.find<IApplication>();
  44. /// 数据
  45. final measureData = Get.find<MeasureDataController>();
  46. final playerController = Get.find<IPlayerController>() as VidPlayerController;
  47. final measure3DViewController = Get.find<Measure3DViewController>();
  48. late final measureHandler = Get.find<MeasureHandler>();
  49. late final aiPatintController = Get.find<AiPatintController>();
  50. late bool canShowAI = [
  51. DiagnosisConclusionEnum.Benign,
  52. DiagnosisConclusionEnum.Malignant,
  53. DiagnosisConclusionEnum.BenignAndMalignant
  54. ].contains(measureData.diagnosisConclusion);
  55. double groupHeight = 0;
  56. bool isExpanded = true;
  57. bool ifShowModeButton = false;
  58. bool ifShowVidModeButton = true;
  59. get isShell => measure3DViewController.isShell;
  60. get exist3DData => measure3DViewController.exist3DData;
  61. @override
  62. void initState() {
  63. super.initState();
  64. groupHeight = countGroupHeight;
  65. measure3DViewController.updatePlayerMode.addListener(_onModeChanged);
  66. }
  67. @override
  68. void dispose() {
  69. measure3DViewController.updatePlayerMode.removeListener(_onModeChanged);
  70. super.dispose();
  71. }
  72. /// 模式改变触发更新
  73. void _onModeChanged(Object s, MeasureMode mode) {
  74. switch (mode) {
  75. case MeasureMode.vidMode:
  76. setState(() {
  77. ifShowModeButton = false;
  78. ifShowVidModeButton = true;
  79. groupHeight = countGroupHeight;
  80. isExpanded = true;
  81. });
  82. break;
  83. case MeasureMode.carotid2DMode:
  84. setState(() {
  85. ifShowModeButton = true;
  86. ifShowVidModeButton = false;
  87. groupHeight = countGroupHeight;
  88. isExpanded = true;
  89. });
  90. break;
  91. case MeasureMode.carotid3DMode:
  92. setState(() {
  93. ifShowModeButton = false;
  94. ifShowVidModeButton = false;
  95. });
  96. break;
  97. }
  98. }
  99. List<FWidget> buildTitleButtonList() {
  100. return [
  101. _buildTitleButton(
  102. FIcons.fis_quash,
  103. i18nBook.common.revoke.t,
  104. () => application.undoRecord(),
  105. ),
  106. _buildTitleButton(
  107. FIcons.fis_purge,
  108. i18nBook.measure.clear.t,
  109. () => application.clearRecords(),
  110. ),
  111. _buildTitleButton(
  112. measureHandler.fullScreenState
  113. ? FIcons.fis_full_screen_reduction
  114. : FIcons.fis_full_screen,
  115. measureHandler.fullScreenState
  116. ? i18nBook.common.cancel.t + i18nBook.measure.fullScreen.t
  117. : i18nBook.measure.fullScreen.t,
  118. () {
  119. measureHandler.fullScreenState = !measureHandler.fullScreenState;
  120. setState(() {});
  121. },
  122. ),
  123. _buildTitleButton(
  124. measureHandler.toolPanelState
  125. ? Icons.cancel_presentation
  126. : Icons.present_to_all,
  127. measureHandler.toolPanelState ? "关闭测量" : "打开测量",
  128. () {
  129. measureHandler.toolPanelState = !measureHandler.toolPanelState;
  130. setState(() {});
  131. },
  132. ),
  133. _buildTitleButton(
  134. FIcons.fis_save,
  135. i18nBook.common.save.t,
  136. widget.capturePng,
  137. ),
  138. _buildTitleButton(
  139. FIcons.fis_share,
  140. i18nBook.remedical.share.t,
  141. () async {
  142. var itemCurrentImage = await measureData.shareImage.call(
  143. measureData.itemCurrentImage,
  144. );
  145. Get.dialog(_buildShareQRCode(itemCurrentImage));
  146. },
  147. ),
  148. //第三方图像需要校准线
  149. if (application.isThirdPart) ...[
  150. _buildTitleButton(
  151. FIcons.device,
  152. i18nBook.remedical.calibrationLine.t,
  153. () {
  154. Get.find<IStandardLineCalibrationController>().enterEditMode();
  155. },
  156. ),
  157. ],
  158. //AI结果隐藏按钮
  159. if (canShowAI) ...[
  160. _buildTitleButton(
  161. !aiPatintController.state.ifShowAi
  162. ? FIcons.fis_eye_display
  163. : FIcons.fis_eye_hidden,
  164. !aiPatintController.state.ifShowAi
  165. ? i18nBook.measure.showAi.t
  166. : i18nBook.measure.hideAi.t,
  167. () {
  168. aiPatintController.state.ifShowAi =
  169. !aiPatintController.state.ifShowAi;
  170. setState(() {});
  171. },
  172. ),
  173. ],
  174. //进入颈动脉3D模式
  175. if (isShell && exist3DData && ifShowVidModeButton) ...[
  176. _buildTitleButton(
  177. FIcons.three_dimensional,
  178. i18nBook.measure.carotid3DMode.t,
  179. () {
  180. measure3DViewController.changeModeTo3DMode();
  181. },
  182. ),
  183. ],
  184. //从颈动脉2D返回到【测量】或【3D】
  185. if (isShell && exist3DData && ifShowModeButton) ...[
  186. _buildTitleButton(
  187. FIcons.three_dimensional,
  188. i18nBook.measure.carotid3DMode.t,
  189. () {
  190. measure3DViewController.backTo3DMode();
  191. },
  192. ),
  193. _buildTitleButton(
  194. Icons.play_circle_outline_rounded,
  195. i18nBook.measure.vidMode.t,
  196. () {
  197. measure3DViewController.backToVidMode();
  198. playerController.resetCurrentFrame();
  199. },
  200. ),
  201. ]
  202. ];
  203. }
  204. @override
  205. FWidget build(BuildContext context) {
  206. return FRow(
  207. children: [
  208. FExpanded(child: FContainer()),
  209. FColumn(
  210. verticalDirection: VerticalDirection.up,
  211. mainAxisAlignment: MainAxisAlignment.end,
  212. children: [
  213. QuickFWidget(Transform.translate(
  214. offset: const Offset(0, -buttonGroupWidth / 2),
  215. child: FAnimatedContainer(
  216. duration: const Duration(milliseconds: 300),
  217. padding: const EdgeInsets.only(
  218. top: groupContainerPadding,
  219. bottom: groupContainerPadding / 2,
  220. ),
  221. decoration: BoxDecoration(
  222. borderRadius: const BorderRadius.only(
  223. bottomLeft: Radius.circular(buttonGroupWidth / 2),
  224. bottomRight: Radius.circular(buttonGroupWidth / 2),
  225. ),
  226. color: Colors.grey.withOpacity(0.6),
  227. ),
  228. clipBehavior: Clip.hardEdge,
  229. width: buttonGroupWidth,
  230. height: groupHeight,
  231. child: FColumn(
  232. children: buildTitleButtonList(),
  233. )))),
  234. _buildDropDownButton(),
  235. const FSizedBox(height: 10),
  236. ],
  237. )
  238. ],
  239. );
  240. }
  241. FWidget _buildTitleButton(IconData icon, String title, Function onClick) {
  242. return FContainer(
  243. height: buttonHeight,
  244. margin: const EdgeInsets.only(
  245. top: buttonMargin,
  246. ),
  247. child: FInkWell(
  248. onTap: () => onClick.call(),
  249. child: Column(
  250. children: [
  251. Icon(
  252. icon,
  253. color: Colors.white,
  254. ),
  255. Text(
  256. title,
  257. style: const TextStyle(
  258. color: Colors.white,
  259. fontSize: 14,
  260. ),
  261. )
  262. ],
  263. ),
  264. ),
  265. );
  266. }
  267. FWidget _buildDropDownButton() {
  268. return FInkWell(
  269. onHover: (isHover) {
  270. if (isHover && !isExpanded) {
  271. setState(() {
  272. groupHeight = countGroupHeight;
  273. isExpanded = true;
  274. });
  275. }
  276. },
  277. onTap: () {
  278. if (isExpanded) {
  279. setState(() {
  280. groupHeight = groupContainerPadding;
  281. isExpanded = false;
  282. });
  283. } else {
  284. setState(() {
  285. groupHeight = countGroupHeight;
  286. isExpanded = true;
  287. });
  288. }
  289. },
  290. child: FContainer(
  291. decoration: const BoxDecoration(
  292. borderRadius:
  293. BorderRadius.all(Radius.circular(buttonGroupWidth / 2)),
  294. color: Colors.white,
  295. ),
  296. padding: const EdgeInsets.only(top: 15),
  297. height: buttonGroupWidth,
  298. width: buttonGroupWidth,
  299. child: FColumn(
  300. children: [
  301. if (isExpanded) ...[
  302. FText(i18nBook.measure.collapseGroup.t),
  303. const FIcon(Icons.arrow_drop_up)
  304. ] else ...[
  305. FText(i18nBook.measure.expandGroup.t),
  306. const FIcon(Icons.arrow_drop_down)
  307. ]
  308. ],
  309. ),
  310. ));
  311. }
  312. FWidget _buildShareQRCode(String itemCurrentImage) {
  313. return FSimpleDialog(
  314. title: FText(
  315. i18nBook.remedical.share.t,
  316. style: const TextStyle(
  317. color: Colors.white,
  318. fontSize: 18,
  319. ),
  320. ),
  321. isDefault: false,
  322. children: [
  323. FContainer(
  324. width: 360,
  325. child: FContainer(
  326. padding: const EdgeInsets.only(top: 20, bottom: 20),
  327. child: QRCodeWithLogo(
  328. itemCurrentImage,
  329. codeStatement: i18nBook.remedical.scanQrCodeToShareImage.t,
  330. operationStatement: i18nBook.remedical.copyLink.t,
  331. operationSuccessCallback: () =>
  332. {PromptBox.toast(i18nBook.remedical.copySuccess.t)},
  333. ),
  334. ),
  335. ),
  336. ],
  337. );
  338. }
  339. }