import 'dart:async'; import 'dart:convert'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart' show ByteData, Uint8List, rootBundle; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:star_lock/app_settings/app_colors.dart'; import 'package:star_lock/app_settings/app_settings.dart'; import 'package:star_lock/talk/call/callTalk.dart'; import 'package:star_lock/talk/starChart/constant/talk_status.dart'; import 'package:star_lock/talk/starChart/handle/other/talk_data_repository.dart'; import 'package:star_lock/talk/starChart/proto/talk_data.pbserver.dart'; import 'package:star_lock/talk/starChart/star_chart_manage.dart'; import 'package:star_lock/talk/starChart/webView/h264_web_logic.dart'; import 'package:star_lock/talk/starChart/webView/h264_web_view_state.dart'; import 'package:star_lock/tools/titleAppBar.dart'; import 'package:webview_flutter/webview_flutter.dart'; class H264WebView extends StatefulWidget { @override _H264WebViewState createState() => _H264WebViewState(); } class _H264WebViewState extends State with TickerProviderStateMixin { final H264WebViewLogic logic = Get.put(H264WebViewLogic()); final H264WebViewState state = Get.find().state; final startChartManage = StartChartManage(); @override void initState() { // TODO: implement initState super.initState(); state.animationController = AnimationController( vsync: this, // 确保使用的TickerProvider是当前Widget duration: const Duration(seconds: 1), ); state.animationController.repeat(); //动画开始、结束、向前移动或向后移动时会调用StatusListener state.animationController.addStatusListener((AnimationStatus status) { if (status == AnimationStatus.completed) { state.animationController.reset(); state.animationController.forward(); } else if (status == AnimationStatus.dismissed) { state.animationController.reset(); state.animationController.forward(); } }); } @override Widget build(BuildContext context) { return WillPopScope( onWillPop: () async { // 返回 false 表示禁止退出 return false; }, child: SizedBox( width: 1.sw, height: 1.sh, child: Stack( alignment: Alignment.center, children: [ Obx(() { final double screenWidth = MediaQuery.of(context).size.width; final double screenHeight = MediaQuery.of(context).size.height; return state.isShowLoading.value ? Image.asset( 'images/main/monitorBg.png', width: screenWidth, height: screenHeight, fit: BoxFit.cover, ) : SizedBox.expand( child: RotatedBox( quarterTurns: startChartManage.rotateAngle ~/ 90, child: WebViewWidget( controller: state.webViewController, ), ), ); }), Obx( () => state.isShowLoading.value ? Positioned( bottom: 310.h, child: Text( '正在创建安全连接...'.tr, style: TextStyle(color: Colors.black, fontSize: 26.sp), ), ) : Container(), ), Obx( () => state.isShowLoading.isFalse ? Positioned( top: ScreenUtil().statusBarHeight + 75.h, width: 1.sw, child: Obx( () { final String sec = (state.oneMinuteTime.value % 60) .toString() .padLeft(2, '0'); final String min = (state.oneMinuteTime.value ~/ 60) .toString() .padLeft(2, '0'); return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( '$min:$sec', style: TextStyle( fontSize: 26.sp, color: Colors.white), ), ], ); }, ), ) : Container(), ), Positioned( bottom: 10.w, child: Container( width: 1.sw - 30.w * 2, // height: 300.h, margin: EdgeInsets.all(30.w), decoration: BoxDecoration( color: Colors.black.withOpacity(0.2), borderRadius: BorderRadius.circular(20.h)), child: Column( children: [ SizedBox(height: 20.h), bottomTopBtnWidget(), SizedBox(height: 20.h), bottomBottomBtnWidget(), SizedBox(height: 20.h), ], ), ), ), Obx(() => state.isShowLoading.isTrue ? buildRotationTransition() : Container()), Obx(() => state.isLongPressing.value ? Positioned( top: 80.h, left: 0, right: 0, child: Center( child: Container( padding: EdgeInsets.all(10.w), decoration: BoxDecoration( color: Colors.black.withOpacity(0.7), borderRadius: BorderRadius.circular(10.w), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.mic, color: Colors.white, size: 24.w), SizedBox(width: 10.w), Text( '正在说话...'.tr, style: TextStyle( fontSize: 20.sp, color: Colors.white), ), ], ), ), ), ) : Container()), ], ), ), ); } Widget bottomTopBtnWidget() { return Row(mainAxisAlignment: MainAxisAlignment.center, children: [ // 打开关闭声音 GestureDetector( onTap: () { if (state.talkStatus.value == TalkStatus.answeredSuccessfully) { // 打开关闭声音 logic.updateTalkExpect(); } }, child: Container( width: 50.w, height: 50.w, padding: EdgeInsets.all(5.w), child: Obx(() => Image( width: 40.w, height: 40.w, image: state.isOpenVoice.value ? const AssetImage( 'images/main/icon_lockDetail_monitoringOpenVoice.png') : const AssetImage( 'images/main/icon_lockDetail_monitoringCloseVoice.png'))), ), ), SizedBox(width: 50.w), // 截图 GestureDetector( onTap: () async { if (state.talkStatus.value == TalkStatus.answeredSuccessfully) { await logic.captureAndSavePng(); } }, child: Container( width: 50.w, height: 50.w, padding: EdgeInsets.all(5.w), child: Image( width: 40.w, height: 40.w, image: const AssetImage( 'images/main/icon_lockDetail_monitoringScreenshot.png')), ), ), SizedBox(width: 50.w), // 录制 GestureDetector( onTap: () async { logic.showToast('功能暂未开放'.tr); // if ( // state.talkStatus.value == TalkStatus.answeredSuccessfully) { // if (state.isRecordingScreen.value) { // await logic.stopRecording(); // } else { // await logic.startRecording(); // } // } }, child: Container( width: 50.w, height: 50.w, padding: EdgeInsets.all(5.w), child: Image( width: 40.w, height: 40.w, fit: BoxFit.fill, image: const AssetImage( 'images/main/icon_lockDetail_monitoringScreenRecording.png'), ), ), ), SizedBox(width: 50.w), GestureDetector( onTap: () { logic.showToast('功能暂未开放'.tr); }, child: Image( width: 28.w, height: 28.w, fit: BoxFit.fill, image: const AssetImage('images/main/icon_lockDetail_rectangle.png'), ), ), ]); } Widget bottomBottomBtnWidget() { return Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ // 接听 Obx( () => bottomBtnItemWidget( getAnswerBtnImg(), getAnswerBtnName(), Colors.white, longPress: () async { if (state.talkStatus.value == TalkStatus.answeredSuccessfully) { // 启动录音 logic.startProcessingAudio(); state.isLongPressing.value = true; } }, longPressUp: () async { // 停止录音 logic.stopProcessingAudio(); state.isLongPressing.value = false; }, onClick: () async { if (state.talkStatus.value == TalkStatus.passiveCallWaitingAnswer) { // 接听 logic.initiateAnswerCommand(); } }, ), ), bottomBtnItemWidget( 'images/main/icon_lockDetail_hangUp.png', '挂断'.tr, Colors.red, onClick: () { // 挂断 logic.udpHangUpAction(); }), bottomBtnItemWidget( 'images/main/icon_lockDetail_monitoringUnlock.png', '开锁'.tr, AppColors.mainColor, onClick: () { // if (state.talkStatus.value == TalkStatus.answeredSuccessfully && // state.listData.value.length > 0) { // logic.udpOpenDoorAction(); logic.remoteOpenLock(); // } // if (UDPManage().remoteUnlock == 1) { // logic.udpOpenDoorAction(); // showDeletPasswordAlertDialog(context); // } else { // logic.showToast('请在锁设置中开启远程开锁'.tr); // } }, ) ]); } String getAnswerBtnImg() { switch (state.talkStatus.value) { case TalkStatus.passiveCallWaitingAnswer: return 'images/main/icon_lockDetail_monitoringAnswerCalls.png'; case TalkStatus.answeredSuccessfully: case TalkStatus.proactivelyCallWaitingAnswer: return 'images/main/icon_lockDetail_monitoringUnTalkback.png'; default: return 'images/main/icon_lockDetail_monitoringAnswerCalls.png'; } } String getAnswerBtnName() { switch (state.talkStatus.value) { case TalkStatus.passiveCallWaitingAnswer: return '接听'.tr; case TalkStatus.proactivelyCallWaitingAnswer: case TalkStatus.answeredSuccessfully: return '长按说话'.tr; default: return '接听'.tr; } } Widget bottomBtnItemWidget( String iconUrl, String name, Color backgroundColor, { required Function() onClick, Function()? longPress, Function()? longPressUp, }) { double wh = 80.w; return GestureDetector( onTap: onClick, onLongPress: longPress, onLongPressUp: longPressUp, child: SizedBox( height: 160.w, width: 140.w, child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( width: wh, height: wh, constraints: BoxConstraints( minWidth: wh, ), decoration: BoxDecoration( color: backgroundColor, borderRadius: BorderRadius.circular((wh + 10.w * 2) / 2), ), padding: EdgeInsets.all(20.w), child: Image.asset(iconUrl, fit: BoxFit.fitWidth), ), SizedBox(height: 20.w), Text( name, style: TextStyle(fontSize: 20.sp, color: Colors.white), textAlign: TextAlign.center, // 当文本超出指定行数时,使用省略号表示 maxLines: 2, // 设置最大行数为1 ) ], ), ), ); } //旋转动画 Widget buildRotationTransition() { return Positioned( left: ScreenUtil().screenWidth / 2 - 220.w / 2, top: ScreenUtil().screenHeight / 2 - 220.w / 2 - 150.h, child: GestureDetector( child: RotationTransition( //设置动画的旋转中心 alignment: Alignment.center, //动画控制器 turns: state.animationController, //将要执行动画的子view child: AnimatedOpacity( opacity: 0.5, duration: const Duration(seconds: 2), child: Image.asset( 'images/main/realTime_connecting.png', width: 220.w, height: 220.w, ), ), ), onTap: () { state.animationController.forward(); }, ), ); } @override void dispose() { state.animationController.dispose(); CallTalk().finishAVData(); // UdpTalkDataHandler().resetDataRates(); super.dispose(); } }