import 'dart:async'; import 'dart:math'; import 'package:fis_lib_basictest/hardware_detection/index.dart'; import 'package:fis_ui/index.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); // This widget is the root of your application. @override Widget build(BuildContext context) { return GetMaterialApp( theme: ThemeData( primarySwatch: Colors.blue, ), initialRoute: '/', getPages: [ GetPage( name: '/', page: () => HardwareDetectionPage(), binding: HardwareDetectionBinding(), ), GetPage(name: '/old', page: () => DrawWidgetStep2()), ], ); } } class DrawWidgetStep2 extends StatefulWidget { const DrawWidgetStep2({Key? key}) : super(key: key); @override State createState() => DrawWidgetStep2State(); } class DrawWidgetStep2State extends State with TickerProviderStateMixin { late Timer timer; AnimationController? controller; late Animation strokePercentAnimation; late Animation labelPercentAnimation; late Animation strokeColorAnimation; late double beginPercentValue; late double endPercentValue; late Color beginColor; late Color endColor; late double speechSliderValue = 0; late double microPhoneSliderValue = 0; late String speechSliderText = "0"; late String microphoneSliderText = "0"; @override void initState() { super.initState(); // 设置初始值结束值 beginPercentValue = 0; endPercentValue = 0; beginColor = Colors.black; endColor = ([...Colors.primaries]..shuffle()).first; // 动画控制器初始化 controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 1000)); // 添加监听 controller?.addListener(() => setState(() {})); // 开始执行动画 startAnimation(); // 设置定时器 timer = Timer.periodic(const Duration(milliseconds: 300), (timer) { startAnimation(); }); } void startAnimation() { // 进度条动画 strokePercentAnimation = Tween(begin: beginPercentValue, end: endPercentValue).animate( CurvedAnimation(parent: controller!, curve: Curves.elasticOut)); // text动画 labelPercentAnimation = Tween(begin: beginPercentValue, end: endPercentValue).animate( CurvedAnimation(parent: controller!, curve: Curves.easeInOutCubic)); // 进度条颜色动画 strokeColorAnimation = ColorTween(begin: beginColor, end: endColor).animate( CurvedAnimation(parent: controller!, curve: Curves.easeInOutCubic)); beginPercentValue = endPercentValue; endPercentValue = Random().nextDouble(); beginColor = endColor; endColor = ([...Colors.primaries]..shuffle()).first; controller?.forward(from: 1); } @override void dispose() { controller?.dispose(); timer.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: FPadding( padding: const EdgeInsets.symmetric(vertical: 10), child: FSingleChildScrollView( child: FColumn( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildNetworkTest(), _buildSpeechTest(), _buildMicroPhoneTest(), _buildCameraTest(), ], ), ), )); } _buildNetworkTest() { var title = _bildTestTitle("网络检测"); var testButton = _buildTestButton("网络检测"); var networkTestItems = _buildNetworkTestItems(); var divider = _buildDevider(); return FColumn( crossAxisAlignment: CrossAxisAlignment.start, children: [ title, testButton, ...networkTestItems, divider, ], ); } _buildSpeechTest() { var title = _bildTestTitle("扬声器检测"); var divider = _buildDevider(); var speechSelections = _buildSpeechSelections(); var speechResult = _buildTestItem( title: "扬声器状态", value: -1, valueUnit: "", testResult: "满足要求", isTestPass: true, ); var speechButton = _buildTestButton("扬声器检测"); var volumeSlider = _buildVolumSlider("扬声器音量", true); var mediaWave = _buildMediaWaves(false); var testResultActionButtonGroup = FContainer( padding: EdgeInsets.fromLTRB(0, 10, 10, 10), width: 250, child: FRow( children: [ FContainer( width: 100, child: _buildTestButton("听到了"), ), FContainer( width: 100, child: _buildTestButton("没听到"), ) ], ), ); return FColumn( crossAxisAlignment: CrossAxisAlignment.start, children: [ title, speechSelections, volumeSlider, speechButton, mediaWave, testResultActionButtonGroup, speechResult, divider, ], ); } FWidget _buildVolumSlider(String title, bool isSpeechSlider) { return FContainer( width: 500, padding: EdgeInsets.fromLTRB(10, 10, 10, 10), child: FRow( children: [ FContainer( width: 140, child: FText( title, style: TextStyle( fontWeight: FontWeight.bold, ), ), ), FContainer( width: 310, child: _buidSlider(isSpeechSlider), ), FText( isSpeechSlider ? speechSliderText : microphoneSliderText, ), ], ), ); } void updateSlider(value, text, isSpeech) { if (isSpeech) { speechSliderValue = value; speechSliderText = text; } else { microPhoneSliderValue = value; microphoneSliderText = text; } setState(() {}); } _buildMicroPhoneTest() { var title = _bildTestTitle("麦克风检测"); var divider = _buildDevider(); var mediaWave = _buildMediaWaves(true); var microPhoneResult = _buildTestItem( title: "麦克风状态", value: -1, valueUnit: "", testResult: "满足要求", isTestPass: true, ); var microphpneButton = _buildTestButton("麦克风测试"); var volumeSlider = _buildVolumSlider("麦克风音量", false); var microphoneSelection = _buildMicrophoneSelections(); return FColumn( crossAxisAlignment: CrossAxisAlignment.start, children: [ title, microphoneSelection, volumeSlider, microphpneButton, mediaWave, microPhoneResult, divider, ], ); } _buildMediaWaves(bool isMicrophone) { var mediaWave = FContainer( padding: EdgeInsets.fromLTRB(13, 10, 10, 10), child: FSizedBox( width: 100, height: 10, child: FCustomPaint( painter: DrawPainter( strokeBackgroundColor: Colors.grey.withOpacity(0.1), strokeColor: Colors.red, startAngle: -pi * 0.5, percent: 0, percentLabel: "0", strokeWidth: 1, fontSize: 2, ), ), ), ); return mediaWave; } _buildCameraTest() { var title = _bildTestTitle("摄像头检测"); var cameraSelection = _buildCameraSelections(); var devider = _buildDevider(); var cameraResult = _buildTestItem( title: "摄像头状态", value: -1, valueUnit: "", testResult: "满足要求", isTestPass: true, ); var testResultActionButtonGroup = FContainer( padding: EdgeInsets.fromLTRB(0, 10, 10, 10), width: 250, child: FRow( children: [ FContainer( width: 100, child: _buildTestButton("看到了"), ), FContainer( width: 100, child: _buildTestButton("没看到"), ) ], ), ); var image = FContainer( margin: EdgeInsets.fromLTRB(8, 10, 10, 10), width: 640, height: 480, color: Colors.black, ); var cameraStatement = FContainer( padding: EdgeInsets.fromLTRB(10, 10, 10, 0), child: FText("该摄像头用于会诊时采集本地画面,请确认是否成功看到画面。"), ); return FColumn( crossAxisAlignment: CrossAxisAlignment.start, children: [ title, cameraSelection, image, cameraStatement, testResultActionButtonGroup, cameraResult, devider, ], ); } FWidget _buidSlider(bool isSpeechSlider) { return FSlider( value: isSpeechSlider ? speechSliderValue : microPhoneSliderValue, max: 100, onChanged: (value) { var intValue = value.toInt(); updateSlider(value, "$intValue", isSpeechSlider); }, onChangeStart: (value) { var intValue = value.toInt(); updateSlider(value, "$intValue", isSpeechSlider); }, onChangeEnd: (value) { var intValue = value.toInt(); updateSlider(value, " $intValue", isSpeechSlider); }, ); } _bildTestTitle(String title) { return FContainer( padding: EdgeInsets.fromLTRB(10, 10, 10, 10), child: FText( title, style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), ); } FWidget _buildTestButton(String content) { return FContainer( padding: EdgeInsets.fromLTRB(10, 10, 10, 10), child: FInkWell( child: FText(content), onTap: () => {}, ), ); } List _buildNetworkTestItems() { var testItems = []; testItems.add(_buildTestItem( title: "网络延迟", value: 1, valueUnit: "ms", testResult: "满足要求", isTestPass: true, )); testItems.add(_buildTestItem( title: "上传速度", value: 342, valueUnit: "Mbps", testResult: "满足要求", isTestPass: true, )); testItems.add(_buildTestItem( title: "下载速度", value: 350, valueUnit: "Mbps", testResult: "满足要求", isTestPass: true, )); testItems.add(_buildTestItem( title: "视频服务质量", value: 20, valueUnit: "ms", testResult: "不满足要求", isTestPass: false, )); testItems.add(_buildTestItem( title: "网络质量", value: -1, valueUnit: "", testResult: "一般", isTestPass: false, )); return testItems; } FWidget _buildTestItem({ required String title, required int value, required String valueUnit, required String testResult, required bool isTestPass, }) { var color = isTestPass ? Colors.green : Colors.red; return FContainer( padding: EdgeInsets.fromLTRB(10, 10, 10, 10), width: 500, child: FRow( mainAxisAlignment: MainAxisAlignment.start, children: [ FContainer( width: 125, margin: EdgeInsets.fromLTRB(0, 0, 0, 0), child: FText( title, style: TextStyle( fontWeight: FontWeight.bold, ), ), ), FContainer( width: 125, child: FText(value == -1 ? "" : value.toString() + valueUnit), ), FContainer( width: 125, child: FText( testResult, style: TextStyle( color: color, ), ), ), FContainer( width: 60, child: isTestPass ? FIcon( Icons.check_circle_outline, color: color, ) : FIcon( Icons.highlight_off_rounded, color: color, ), ), ], ), ); } FWidget _buildDevider() { return FDivider( height: 15, thickness: 1, color: Colors.black, indent: 10, ); } FWidget _buildSpeechSelections() { var devices = []; devices.add(DeviceModel(name: "扬声器1", id: "1")); devices.add(DeviceModel(name: "扬声器2", id: "2")); devices.add(DeviceModel(name: "扬声器3", id: "3")); return _buildDeviceSelections(devices); } FWidget _buildMicrophoneSelections() { var devices = []; devices.add(DeviceModel(name: "麦克风1", id: "1")); devices.add(DeviceModel(name: "麦克风2", id: "2")); devices.add(DeviceModel(name: "麦克风3", id: "3")); return _buildDeviceSelections(devices); } FWidget _buildCameraSelections() { var devices = []; devices.add(DeviceModel(name: "摄像头1", id: "1")); devices.add(DeviceModel(name: "摄像头2", id: "2")); devices.add(DeviceModel(name: "摄像头3", id: "3")); return _buildDeviceSelections(devices); } FWidget _buildDeviceSelections(List source) { return FContainer( margin: EdgeInsets.fromLTRB(10, 10, 10, 10), child: FSelect( source: source, height: 33, width: 250, value: "1", optionValueExtractor: (value) { return value.id; }, optionLabelExtractor: (value) { return value.name; }, onSelectChanged: (value, index) { ; }, fontSize: 14, ), ); } } class DeviceModel { DeviceModel({ required this.name, required this.id, }); final String name; final String id; } class DrawPainter extends CustomPainter { final double strokeWidth; final Color strokeColor; final Color strokeBackgroundColor; final double startAngle; final double percent; final double fontSize; final Color textColor; final String? percentLabel; DrawPainter({ this.strokeWidth = 10, this.strokeColor = Colors.black, this.strokeBackgroundColor = Colors.grey, this.startAngle = 0, this.percent = 0, this.fontSize = 20, this.textColor = Colors.black, this.percentLabel, }); @override void paint(Canvas canvas, Size size) { //backgroud for (var i = 0; i < 15; i++) { var scolor = Colors.grey; var paint = Paint() ..style = PaintingStyle.stroke ..color = scolor ..strokeWidth = 3; var left = i * 10.0; var rect = Rect.fromLTWH(left, 2, 3, 20); canvas.drawRect(rect, paint); } var random = Random().nextInt(15); for (var i = 0; i < random; i++) { var scolor = Colors.blue; var paint = Paint() ..style = PaintingStyle.stroke ..color = scolor ..strokeWidth = 4; var left = i * 10.0; var rect = Rect.fromLTWH(left, 2, 3, 20); canvas.drawRect(rect, paint); } } @override bool shouldRepaint(CustomPainter oldDelegate) { return oldDelegate != this; } }