123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- import 'dart:async';
- import 'package:fis_i18n/i18n.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/workspace/measure_3d_view_controller.dart';
- import 'package:fis_measure/utils/prompt_box.dart';
- import 'package:fis_measure/view/measure/carotid_measure_tool.dart';
- import 'package:fis_ui/index.dart';
- import 'package:flutter/material.dart' hide Image;
- import 'package:flutter/services.dart';
- import 'package:get/get.dart';
- import 'package:vid/us/vid_us_image.dart';
- import 'package:webviewx/webviewx.dart';
- import 'dart:convert';
- import 'package:fis_measure/utils/js_utils.dart'
- if (dart.library.io) 'package:fis_measure/utils/js_utils4native.dart'
- if (dart.library.html) 'package:fis_measure/utils/js_utils.dart';
- /// [Carotid] 🚧webview 下 initPage 方法需要 i18n 由 Flutter 触发
- /// [Carotid] ✅启用 3D 后的亮度对比度需要通知 Shell 计算
- /// [Carotid] ✅需要接入 webview 控制器
- /// [Carotid] ✅需要判断是否为壳子,浏览器环境无 3D 操作
- ///
- class Measure3DView extends StatefulWidget implements FWidget {
- const Measure3DView({
- Key? key,
- }) : super(key: key);
- @override
- _Measure3DViewState createState() => _Measure3DViewState();
- }
- class _Measure3DViewState extends State<Measure3DView> {
- late WebViewXController webviewController;
- final measure3DViewController = Get.find<Measure3DViewController>();
- final application = Get.find<IApplication>();
- Size get screenSize => MediaQuery.of(context).size;
- String documentFromAsset = "<h2> Hello webviewX ! <h2>";
- Future<String> _preloadHTML() async {
- documentFromAsset = await _loadHTMLFromAssets(
- 'assets/webview/3DMeasurePage.html',
- );
- return Future.value("");
- }
- Future<String> _loadHTMLFromAssets(String path) async {
- try {
- return await DefaultAssetBundle.of(context).loadString(path);
- } catch (e) {
- return Future.error(e);
- }
- }
- @override
- Widget build(BuildContext context) {
- return Column(
- children: <Widget>[
- Expanded(
- child: LayoutBuilder(
- builder: (BuildContext context, BoxConstraints constraints) {
- return _buildWebViewX(constraints);
- }),
- ),
- SizedBox(
- height: 30,
- child: Container(
- child: measure3DViewController.enable2DMeasure
- ? ElevatedButton(
- onPressed: () {
- _changeTo2DMeasure();
- },
- child: Text(i18nBook.measure.measureSpecifiedFace.t),
- )
- : Container(),
- ),
- ),
- ],
- );
- }
- @override
- void initState() {
- super.initState();
- measure3DViewController.onShellLoadedMdlFile.addListener(_mdlFileLoaded);
- measure3DViewController.adjustPlaneImage.addListener(_adjustedImage);
- }
- @override
- void dispose() {
- measure3DViewController.onShellLoadedMdlFile.removeListener(_mdlFileLoaded);
- measure3DViewController.adjustPlaneImage.removeListener(_adjustedImage);
- webviewController.dispose();
- super.dispose();
- }
- Widget _buildWebViewX(BoxConstraints constraints) {
- return FutureBuilder<String>(
- future: _preloadHTML(),
- builder: (context, AsyncSnapshot<String> snapshot) {
- if (snapshot.hasData) {
- return WebViewX(
- key: const ValueKey('webviewx'),
- initialContent: documentFromAsset,
- initialSourceType: SourceType.html,
- height: constraints.maxHeight,
- width: constraints.maxWidth,
- onWebViewCreated: (controller) => webviewController = controller,
- onPageStarted: (src) =>
- debugPrint('A new page has started loading'),
- onPageFinished: (src) {
- debugPrint('The page has finished loading');
- _setSurface().then((value) => _notifyShellToLoad());
- },
- jsContent: {
- EmbeddedJsContent(
- js: "var isCurrentChinese = ${i18nBook.isCurrentChinese}")
- },
- dartCallBacks: {
- DartCallback(
- name: 'Dart_getClipPlaneData',
- callBack: (msg) => callShellGetClipPlaneData(msg)),
- DartCallback(
- name: 'Dart_deleteClipImageData',
- callBack: (msg) => _deleteClipImageData(msg),
- ),
- DartCallback(
- name: "Dart_deleteAllClipImageData",
- callBack: (msg) => _deleteAllClipImageData(msg),
- ),
- DartCallback(
- name: "Dart_meshActiveStatusChanged",
- callBack: (boolValue) => _meshActiveStatusChanged(boolValue),
- ),
- DartCallback(
- name: "Dart_aiClipStateCallBack",
- callBack: (boolValue) => _aiClipStateCallBack(boolValue),
- ),
- DartCallback(
- name: "Dart_getVesselClipPlanePoints",
- callBack: (msg) => callShellGetVesselClipPlanePoints(msg),
- ),
- },
- webSpecificParams: const WebSpecificParams(
- printDebugInfo: true,
- ),
- mobileSpecificParams: const MobileSpecificParams(
- androidEnableHybridComposition: true,
- ),
- navigationDelegate: (navigation) {
- debugPrint(navigation.content.sourceType.toString());
- return NavigationDecision.navigate;
- },
- );
- } else {
- return const Center(child: CircularProgressIndicator());
- }
- });
- }
- void _deleteClipImageData(String msg) {
- // debugPrint("webview 触发 Dart_deleteClipImageData :$msg");
- callShellMethod('deleteClipImageData', [msg]);
- }
- void _deleteAllClipImageData(msg) {
- // debugPrint("webview 触发 Dart_deleteAllClipImageData :$msg");
- callShellMethod('deleteAllClipImageData', []);
- }
- /// [Carotid] ✅触发激活状态更新,来判断是否显示 [切换2D测量] 按钮
- void _meshActiveStatusChanged(bool res) {
- debugPrint("webview 触发 Dart_meshActiveStatusChanged :$res");
- callShellMethod('meshActiveStatusChanged', [res]);
- measure3DViewController.enable2DMeasure = res;
- setState(() {});
- }
- /// AI 切割成功的回调
- void _aiClipStateCallBack(bool success) async {
- if (success) {
- measure3DViewController.needAutoDetection = true;
- // callShellMethod('aiClipStateCallBack', [res]);
- measure3DViewController.resetTone();
- }
- }
- ///[Carotid] ✅初始化 mesh 长宽高可以由两张小图计算得到,设置标准宽度用于缩放切面
- Future<void> _setSurface() async {
- final faceImages = measure3DViewController.carotidResult.surfaceImageList;
- if (faceImages!.length == 6) {
- final first = await loadImageSize(faceImages[0]);
- final last = await loadImageSize(faceImages[5]);
- final width = (last.width - 1).toInt();
- final height = (last.height - 1).toInt();
- final depth = (first.height - 1).toInt();
- measure3DViewController.stdSize =
- Size(width.toDouble(), depth.toDouble());
- try {
- await webviewController.callJsMethod(
- 'changeSurface', [width, height, depth, ...faceImages]);
- } catch (e) {
- debugPrint("callmethod fail " + e.toString());
- }
- }
- }
- /// [Carotid] ✅获取到图像并进入 2D 测量页
- Future<void> _changeTo2DMeasure() async {
- try {
- String res =
- await webviewController.callJsMethod('getCurrentClipInformation', []);
- callShellSwitchMeasureMode(
- res, measure3DViewController.curImageAdjustPara)
- .callMethod("then", [
- (res) async {
- VidUsImage vidUsImage = VidUsImage.fromBytes(base64Decode(res));
- /// [Carotid] ✅写入单帧缓存
- final playerController = Get.find<IPlayerController>();
- playerController.pause();
- measure3DViewController.image4Measure = vidUsImage;
- measure3DViewController.changeModeTo2DMeasure();
- application.clearRecords();
- if (measure3DViewController.needAutoDetection) {
- Future.delayed(400.milliseconds, () {
- /// 内膜检测
- final intimaDetection = carotidMeasureApplicationList.last;
- application.switchItem(intimaDetection);
- PromptBox.snackbar(i18nBook.measure.autoRunIntimaDetection.t,
- duration: const Duration(milliseconds: 1500),
- title: i18nBook.common.tip.t,
- textColor: Colors.white,
- backgroundColor: Colors.black.withOpacity(0.7));
- Future.delayed(400.milliseconds, () {
- final firstItem = carotidMeasureApplicationList.first;
- application.switchItem(firstItem);
- });
- });
- measure3DViewController.needAutoDetection = false;
- }
- }
- ]);
- } catch (e) {
- debugPrint("callmethod fail " + e.toString());
- }
- }
- /// [Carotid] ✅_mdlFileLoaded 由壳子触发,通知 webview 模型已加载,显示操作按钮
- void _mdlFileLoaded(Object s, dynamic e) {
- try {
- webviewController.callJsMethod('mdlFileLoaded', ["Carotid", "True"]);
- } catch (e) {
- debugPrint("callmethod fail " + e.toString());
- }
- }
- /// [Carotid] ✅_adjustedImage 由 Flutter 触发,通知 webview 更新所有的面数据
- void _adjustedImage(Object s, ImageAdjustPara e) {
- try {
- webviewController.callJsMethod(
- 'adjustedImageByFlutter', [e.sharpness, e.brightness, e.contrast]);
- } catch (e) {
- debugPrint("callmethod fail " + e.toString());
- }
- }
- /// webview 初始化完成后通知壳子切换至对应模型文件
- Future<void> _notifyShellToLoad() async {
- measure3DViewController.notifyShellSetCurModel();
- }
- }
|