Browse Source

1、新增安卓定位权限

guanxinyi 1 year ago
parent
commit
615f6dabe4

+ 1 - 0
android/app/src/main/AndroidManifest.xml

@@ -39,6 +39,7 @@
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
     <uses-permission android:name="android.permission.FLASHLIGHT" />
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+
     <!-- 蓝牙权限 Start -->
     <uses-permission android:name="android.permission.BLUETOOTH"/>
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

BIN
assets/images/avatar.png


BIN
assets/images/avatar_women.png


+ 5 - 2
lib/managers/index.dart

@@ -2,9 +2,9 @@
  * @Descripttion: 
  * @version: 
  * @Author: guanxiaoxin
- * @Date: 2023-09-11 20:46:24
+ * @Date: 2023-10-16 13:36:49
  * @LastEditors: guanxiaoxin
- * @LastEditTime: 2023-09-20 15:03:06
+ * @LastEditTime: 2023-10-16 20:24:55
  * @FilePath: \VNoteApp\lib\managers\index.dart
  */
 import 'package:get/get.dart';
@@ -23,10 +23,12 @@ import 'package:vnoteapp/managers/interfaces/follow_up.dart';
 import 'package:vnoteapp/managers/interfaces/health_check_record.dart';
 import 'package:vnoteapp/managers/interfaces/label.dart';
 import 'package:vnoteapp/managers/interfaces/patient.dart';
+import 'package:vnoteapp/managers/interfaces/permission.dart';
 import 'package:vnoteapp/managers/interfaces/service_pack.dart';
 import 'package:vnoteapp/managers/interfaces/template.dart';
 import 'package:vnoteapp/managers/label.dart';
 import 'package:vnoteapp/managers/patient.dart';
+import 'package:vnoteapp/managers/permission.dart';
 import 'package:vnoteapp/managers/service_pack.dart';
 import 'package:vnoteapp/managers/template.dart';
 import 'interfaces/base.dart';
@@ -45,6 +47,7 @@ abstract class ManagerCenter {
     Get.put<IFollowUpManager>(FollowUpManager());
     Get.put<ITemplateManager>(TemplateManager());
     Get.put<IHealthCehckRecordManager>(HealthCheckRecordManager());
+    Get.put<IPermissionManager>(PermissionManager());
   }
 
   static T find<T extends IManager>() {

+ 4 - 0
lib/managers/interfaces/permission.dart

@@ -0,0 +1,4 @@
+abstract class IPermissionManager {
+  ///检查精准定位
+  Future<void> requestLocationPermission();
+}

+ 39 - 0
lib/managers/permission.dart

@@ -0,0 +1,39 @@
+import 'package:permission_handler/permission_handler.dart';
+
+import 'interfaces/permission.dart';
+
+class PermissionManager implements IPermissionManager {
+  PermissionManager();
+
+  @override
+  Future<void> requestLocationPermission() async {
+    PermissionStatus status = await Permission.location.request();
+    if (status.isGranted) {
+      // 权限已授予,可以进行相关操作
+      // 在这里添加你的逻辑代码
+      return;
+    } else {
+      // 权限被拒绝
+      if (status.isPermanentlyDenied) {
+        // 用户永久拒绝了权限,你可以引导用户前往设置页面手动授予权限
+        openAppSettings();
+      } else {
+        // 用户暂时拒绝了权限
+        // 在这里可以给用户一些解释,然后再次请求权限
+        requestLocationPermission();
+      }
+      return;
+    }
+  }
+}
+
+enum PermissionEnum {
+  //音视频相关
+  VideoAndVoiceRelevant,
+
+  //IO相关
+  IORelevant,
+
+  //App 需要的所有权限
+  All,
+}

+ 16 - 14
lib/pages/check/examination/controller.dart

@@ -4,10 +4,11 @@
  * @Author: guanxiaoxin
  * @Date: 2023-09-22 14:09:39
  * @LastEditors: guanxiaoxin
- * @LastEditTime: 2023-10-13 15:37:57
+ * @LastEditTime: 2023-10-16 17:08:10
  * @FilePath: \VNoteApp\lib\pages\check\examination\controller.dart
  */
 
+import 'package:fis_jsonrpc/rpc.dart';
 import 'package:get/get.dart';
 import 'package:vnoteapp/architecture/storage/text_storage.dart';
 import 'package:vnoteapp/architecture/utils/prompt_box.dart';
@@ -43,20 +44,21 @@ class ExaminationController extends GetxController {
       fileName: key,
       directory: "patient/$patientCode/exam/2023",
     );
-    // final result = await _examManager.createExam(CreateExamRequest(
-    //   key: key,
-    //   patientCode: patientCode,
-    //   templateCode: templateCode,
-    //   examData: data,
-    // ));
-    // if (result?.isNotEmpty ?? false) {
-    try {
-      template.save(data);
-    } catch (err) {
-      print('🥟');
+    final result = await _examManager.createExam(CreateExamRequest(
+      key: key,
+      patientCode: patientCode,
+      templateCode: templateCode,
+      examData: data,
+    ));
+    if (result?.isNotEmpty ?? false) {
+      try {
+        template.save(data);
+        PromptBox.toast('保存成功');
+      } catch (err) {
+        print('🥟');
+        PromptBox.toast('保存失败');
+      }
     }
-    PromptBox.toast('保存成功');
-    // }
   }
 
   // @override

+ 39 - 13
lib/pages/check/widgets/configurable_card.dart

@@ -11,7 +11,9 @@ import 'package:vnoteapp/components/dynamic_drawer.dart';
 import 'package:vnoteapp/managers/interfaces/template.dart';
 import 'package:vnoteapp/pages/check/models/form.dart';
 import 'package:vnoteapp/pages/check/widgets/exam_configurable/exam_blood_pressure.dart';
+import 'package:vnoteapp/pages/check/widgets/exam_configurable/exam_blood_sugar.dart';
 import 'package:vnoteapp/pages/check/widgets/exam_configurable/exam_body_temperature.dart';
+import 'package:vnoteapp/pages/check/widgets/exam_configurable/exam_body_weight.dart';
 import 'package:vnoteapp/pages/check/widgets/exam_configurable/exam_check_box.dart';
 import 'package:vnoteapp/pages/check/widgets/exam_configurable/exam_input.dart';
 import 'package:vnoteapp/pages/check/widgets/exam_configurable/exam_number_input.dart';
@@ -261,6 +263,8 @@ class _ConfigurableFormState extends State<ConfigurableCard> {
       'radioScore': _buildRadioScore,
       'bloodPressure': _buildBloodPressure,
       'bodyTemperature': _buildBodyTemperature,
+      'weight': _buildBodyWeight,
+      'sugar': _buildBodySugar,
     };
     Widget Function(FormObject) builder =
         widgetMap[currentFormObject?.type] ?? _buildInput;
@@ -563,20 +567,9 @@ class _ConfigurableFormState extends State<ConfigurableCard> {
     );
   }
 
-  /// 数字输入框组件
+  /// 体温组件
   Widget _buildBodyTemperature(FormObject currentFormObject) {
     String currentInputValue = formValue[currentFormObject.key!] ?? '';
-    Future<void> commonInput() async {
-      String? result = await VDialogNumber(
-        title: currentFormObject.label,
-        initialValue: formValue[currentFormObject.key],
-      ).show();
-      if (result?.isNotEmpty ?? false) {
-        formValue[currentFormObject.key!] = result;
-        currentInputValue = formValue[currentFormObject.key!];
-        setState(() {});
-      }
-    }
 
     void specialInput(String value) {
       formValue[currentFormObject.key!] = value;
@@ -586,7 +579,40 @@ class _ConfigurableFormState extends State<ConfigurableCard> {
 
     return ExamBodyTemperature(
       currentInputValue: currentInputValue,
-      commonInput: commonInput,
+      specialInput: specialInput,
+      currentFormObject: currentFormObject,
+    );
+  }
+
+  /// 体重
+  Widget _buildBodyWeight(FormObject currentFormObject) {
+    String currentInputValue = formValue[currentFormObject.key!] ?? '';
+
+    void specialInput(String value) {
+      formValue[currentFormObject.key!] = value;
+      currentInputValue = formValue[currentFormObject.key!];
+      setState(() {});
+    }
+
+    return ExamBodyWeight(
+      currentInputValue: currentInputValue,
+      specialInput: specialInput,
+      currentFormObject: currentFormObject,
+    );
+  }
+
+  /// 血糖
+  Widget _buildBodySugar(FormObject currentFormObject) {
+    String currentInputValue = formValue[currentFormObject.key!] ?? '';
+
+    void specialInput(String value) {
+      formValue[currentFormObject.key!] = value;
+      currentInputValue = formValue[currentFormObject.key!];
+      setState(() {});
+    }
+
+    return ExamBloodSugar(
+      currentInputValue: currentInputValue,
       specialInput: specialInput,
       currentFormObject: currentFormObject,
     );

+ 316 - 0
lib/pages/check/widgets/exam_configurable/exam_blood_sugar.dart

@@ -0,0 +1,316 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:vnote_device_plugin/devices/sugar.dart';
+import 'package:vnote_device_plugin/models/exams/sugar.dart';
+import 'package:vnoteapp/components/alert_dialog.dart';
+import 'package:vnoteapp/components/button.dart';
+import 'package:vnoteapp/managers/interfaces/permission.dart';
+import 'package:vnoteapp/pages/check/models/form.dart';
+import 'package:vnoteapp/pages/check/widgets/exam_configurable/exam_card.dart';
+
+class ExamBloodSugar extends StatefulWidget {
+  const ExamBloodSugar({
+    super.key,
+    required this.currentFormObject,
+    required this.currentInputValue,
+    this.specialInput,
+  });
+  final FormObject currentFormObject;
+  final String currentInputValue;
+  final Function(String value)? specialInput;
+
+  @override
+  State<ExamBloodSugar> createState() => _ExamBloodSugarState();
+}
+
+class _ExamBloodSugarState extends State<ExamBloodSugar> {
+  var permissionManager = Get.find<IPermissionManager>();
+  @override
+  void initState() {
+    permissionManager.requestLocationPermission();
+    super.initState();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return ExamCard(
+      title: widget.currentFormObject.label ?? '',
+      clickCard: () {
+        _buildTempertureInput(widget.currentFormObject);
+      },
+      content: Container(
+        alignment: Alignment.bottomRight,
+        padding: const EdgeInsets.only(
+          bottom: 20,
+          right: 30,
+          left: 40,
+        ),
+        constraints: const BoxConstraints(minHeight: 150),
+        child: FittedBox(
+          child: Row(
+            mainAxisAlignment: MainAxisAlignment.end,
+            crossAxisAlignment: CrossAxisAlignment.end,
+            children: [
+              RichText(
+                text: TextSpan(
+                  text: widget.currentInputValue,
+                  style: const TextStyle(
+                    fontSize: 80,
+                    color: Colors.black,
+                  ),
+                  children: [
+                    TextSpan(
+                      text: widget.currentFormObject.append ?? '',
+                      style: const TextStyle(fontSize: 25),
+                    )
+                  ],
+                ),
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+
+  Future<void> _buildTempertureInput(FormObject currentFormObject) async {
+    // Future.delayed(const Duration(milliseconds: 3000), () {
+    //   specialInputController.text = generateRandomNumber().toString();
+    //   widget.specialInput?.call(specialInputController.text);
+    //   setState(() {});
+    // });
+
+    final result = await Get.dialog(
+      BloodSugar(
+        currentFormObject: widget.currentFormObject,
+        bloodSugar: widget.currentInputValue,
+      ),
+      barrierDismissible: false,
+    );
+    widget.specialInput?.call(result);
+    print(result);
+  }
+}
+
+class BloodSugar extends StatefulWidget {
+  const BloodSugar({
+    super.key,
+    required this.currentFormObject,
+    this.bloodSugar,
+  });
+  final FormObject currentFormObject;
+  final String? bloodSugar;
+
+  @override
+  State<BloodSugar> createState() => _BloodSugarState();
+}
+
+class _BloodSugarState extends State<BloodSugar> {
+  late final SugarDeviceWorker worker = SugarDeviceWorker(
+    mac: '60:98:66:C4:0E:51',
+    model: 'i-sens630',
+  );
+  late TextEditingController specialInputController =
+      TextEditingController(text: widget.bloodSugar ?? '00.0');
+  bool connectFailState = false;
+  bool connectSuccessState = false;
+  bool isConnect = false;
+  @override
+  void initState() {
+    connect();
+
+    worker.successEvent.addListener(_onSuccess);
+    worker.connectErrorEvent.addListener(_onConnectFail);
+    worker.connectedEvent.addListener(_onConnectSuccess);
+
+    super.initState();
+  }
+
+  Future<void> connect() async {
+    connectFailState = false;
+    isConnect = true;
+    connectSuccessState = false;
+    setState(() {});
+    await worker.connect();
+  }
+
+  Future<void> disconnect() async {
+    worker.connectErrorEvent.removeListener(_onConnectFail);
+    worker.connectedEvent.removeListener(_onConnectSuccess);
+    await worker.disconnect();
+  }
+
+  @override
+  void dispose() {
+    super.dispose();
+  }
+
+  void _onSuccess(_, SugarExamData e) {
+    setState(() {
+      specialInputController.text = e.sugar.toString();
+      // connectFailState = false;
+      // connectSuccessState = false;
+      isConnect = false;
+      // disconnect();
+    });
+  }
+
+  void _onConnectFail(sender, e) {
+    print('连接设备失败');
+    connectFailState = true;
+    connectSuccessState = false;
+    isConnect = false;
+    disconnect();
+    setState(() {});
+  }
+
+  void _onConnectSuccess(sender, e) {
+    connectSuccessState = true;
+    connectFailState = false;
+    isConnect = false;
+    setState(() {});
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return VAlertDialog(
+      title: widget.currentFormObject.label ?? '',
+      width: 600,
+      contentPadding: const EdgeInsets.symmetric(vertical: 12, horizontal: 24),
+      content: buildMainWidget(),
+      showCancel: true,
+      onConfirm: () {
+        disconnect();
+        Get.back(result: specialInputController.text);
+      },
+      onCanceled: () {
+        disconnect();
+      },
+    );
+  }
+
+  Widget buildInputField() {
+    return Container(
+      width: 350,
+      padding: const EdgeInsets.only(left: 15),
+      child: TextFormField(
+        keyboardType: TextInputType.number,
+        style: const TextStyle(
+          fontSize: 100,
+        ),
+        showCursor: false,
+        controller: specialInputController,
+        decoration: const InputDecoration(
+          labelStyle: TextStyle(
+            fontSize: 100,
+          ),
+        ),
+      ),
+    );
+  }
+
+  Widget buildConnectFailText() {
+    return const Text(
+      '设备连接失败',
+      style: TextStyle(
+        color: Colors.red,
+        fontSize: 25,
+      ),
+      textAlign: TextAlign.left,
+    );
+  }
+
+  Widget buildConnectSuccessText() {
+    return const Text(
+      '设备连接成功',
+      style: TextStyle(
+        color: Colors.green,
+        fontSize: 25,
+      ),
+      textAlign: TextAlign.left,
+    );
+  }
+
+  Widget buildConnectingText() {
+    return const Row(
+      children: [
+        Expanded(
+          child: Text(
+            '设备连接中',
+            style: TextStyle(
+              fontSize: 40,
+              color: Colors.blue,
+            ),
+          ),
+        ),
+        CircularProgressIndicator(
+          valueColor: AlwaysStoppedAnimation(
+            Colors.blue,
+          ),
+        ),
+        SizedBox(
+          width: 20,
+        ),
+      ],
+    );
+  }
+
+  Widget buildReconnectButton() {
+    return Container(
+      margin: const EdgeInsets.only(top: 4),
+      width: 134,
+      child: VButton(
+        onTap: () async {
+          /// TODO
+          await connect();
+          worker.connectErrorEvent.addListener(_onConnectFail);
+          worker.connectedEvent.addListener(_onConnectSuccess);
+
+          /// TODO 后面需要改,这边暂时演示用
+          Future.delayed(const Duration(milliseconds: 8000), () {
+            if (!connectSuccessState) {
+              connectFailState = true;
+            }
+          });
+        },
+        child: const Row(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: [
+            Icon(Icons.connected_tv_rounded, size: 24),
+            SizedBox(
+              width: 8,
+            ),
+            Text("重连", style: TextStyle(fontSize: 20)),
+          ],
+        ),
+      ),
+    );
+  }
+
+  Widget buildConnectStateWidgets() {
+    return Column(
+      children: [
+        if (connectFailState) buildConnectFailText(),
+        if (connectSuccessState) buildConnectSuccessText(),
+        if (isConnect)
+          buildConnectingText()
+        else if (connectFailState)
+          buildReconnectButton(),
+      ],
+    );
+  }
+
+  Widget buildMainWidget() {
+    return SizedBox(
+      height: 100,
+      child: Row(
+        children: [
+          buildInputField(),
+          Expanded(
+            child: buildConnectStateWidgets(),
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 317 - 0
lib/pages/check/widgets/exam_configurable/exam_body_weight.dart

@@ -0,0 +1,317 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:vnote_device_plugin/devices/weight.dart';
+import 'package:vnoteapp/components/alert_dialog.dart';
+import 'package:vnoteapp/components/button.dart';
+import 'package:vnoteapp/managers/interfaces/permission.dart';
+import 'package:vnoteapp/pages/check/models/form.dart';
+import 'package:vnoteapp/pages/check/widgets/exam_configurable/exam_card.dart';
+
+class ExamBodyWeight extends StatefulWidget {
+  const ExamBodyWeight({
+    super.key,
+    required this.currentFormObject,
+    required this.currentInputValue,
+    this.specialInput,
+  });
+  final FormObject currentFormObject;
+  final String currentInputValue;
+  final Function(String value)? specialInput;
+
+  @override
+  State<ExamBodyWeight> createState() => _ExamBodyWeightState();
+}
+
+class _ExamBodyWeightState extends State<ExamBodyWeight> {
+  var permissionManager = Get.find<IPermissionManager>();
+  @override
+  void initState() {
+    permissionManager.requestLocationPermission();
+    super.initState();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return ExamCard(
+      title: widget.currentFormObject.label ?? '',
+      clickCard: () {
+        _buildTempertureInput(widget.currentFormObject);
+      },
+      content: Container(
+        alignment: Alignment.bottomRight,
+        padding: const EdgeInsets.only(
+          bottom: 20,
+          right: 30,
+          left: 40,
+        ),
+        constraints: const BoxConstraints(minHeight: 150),
+        child: FittedBox(
+          child: Row(
+            mainAxisAlignment: MainAxisAlignment.end,
+            crossAxisAlignment: CrossAxisAlignment.end,
+            children: [
+              RichText(
+                text: TextSpan(
+                  text: widget.currentInputValue,
+                  style: const TextStyle(
+                    fontSize: 80,
+                    color: Colors.black,
+                  ),
+                  children: [
+                    TextSpan(
+                      text: widget.currentFormObject.append ?? '',
+                      style: const TextStyle(fontSize: 25),
+                    )
+                  ],
+                ),
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+
+  Future<void> _buildTempertureInput(FormObject currentFormObject) async {
+    // Future.delayed(const Duration(milliseconds: 3000), () {
+    //   specialInputController.text = generateRandomNumber().toString();
+    //   widget.specialInput?.call(specialInputController.text);
+    //   setState(() {});
+    // });
+
+    final result = await Get.dialog(
+      Weight(
+        currentFormObject: widget.currentFormObject,
+        weight: widget.currentInputValue,
+      ),
+      barrierDismissible: false,
+    );
+    widget.specialInput?.call(result);
+    print('object');
+    print(result);
+    print('object');
+  }
+}
+
+class Weight extends StatefulWidget {
+  const Weight({
+    super.key,
+    required this.currentFormObject,
+    this.weight,
+  });
+  final FormObject currentFormObject;
+  final String? weight;
+
+  @override
+  State<Weight> createState() => _WeightState();
+}
+
+class _WeightState extends State<Weight> {
+  late final WeightDeviceWorker worker = WeightDeviceWorker(
+    mac: 'CF:E4:2C:22:01:39',
+    model: 'CF398BLE',
+  );
+  late TextEditingController specialInputController =
+      TextEditingController(text: widget.weight ?? '00.0');
+  bool connectFailState = false;
+  bool connectSuccessState = false;
+  bool isConnect = false;
+  @override
+  void initState() {
+    connect();
+
+    worker.successEvent.addListener(_onSuccess);
+    worker.connectErrorEvent.addListener(_onConnectFail);
+    worker.connectedEvent.addListener(_onConnectSuccess);
+
+    super.initState();
+  }
+
+  Future<void> connect() async {
+    connectFailState = false;
+    isConnect = true;
+    connectSuccessState = false;
+    setState(() {});
+    await worker.connect();
+  }
+
+  Future<void> disconnect() async {
+    worker.connectErrorEvent.removeListener(_onConnectFail);
+    worker.connectedEvent.removeListener(_onConnectSuccess);
+    await worker.disconnect();
+  }
+
+  @override
+  void dispose() {
+    super.dispose();
+  }
+
+  void _onSuccess(_, double e) {
+    setState(() {
+      specialInputController.text = e.toString();
+      // connectFailState = false;
+      // connectSuccessState = false;
+      isConnect = false;
+      // disconnect();
+    });
+  }
+
+  void _onConnectFail(sender, e) {
+    print('连接设备失败');
+    connectFailState = true;
+    connectSuccessState = false;
+    isConnect = false;
+    disconnect();
+    setState(() {});
+  }
+
+  void _onConnectSuccess(sender, e) {
+    connectSuccessState = true;
+    connectFailState = false;
+    isConnect = false;
+    setState(() {});
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return VAlertDialog(
+      title: widget.currentFormObject.label ?? '',
+      width: 600,
+      contentPadding: const EdgeInsets.symmetric(vertical: 12, horizontal: 24),
+      content: buildMainWidget(),
+      showCancel: true,
+      onConfirm: () {
+        disconnect();
+        Get.back(result: specialInputController.text);
+      },
+      onCanceled: () {
+        disconnect();
+      },
+    );
+  }
+
+  Widget buildInputField() {
+    return Container(
+      width: 350,
+      padding: const EdgeInsets.only(left: 15),
+      child: TextFormField(
+        keyboardType: TextInputType.number,
+        style: const TextStyle(
+          fontSize: 100,
+        ),
+        showCursor: false,
+        controller: specialInputController,
+        decoration: const InputDecoration(
+          labelStyle: TextStyle(
+            fontSize: 100,
+          ),
+        ),
+      ),
+    );
+  }
+
+  Widget buildConnectFailText() {
+    return const Text(
+      '设备连接失败',
+      style: TextStyle(
+        color: Colors.red,
+        fontSize: 25,
+      ),
+      textAlign: TextAlign.left,
+    );
+  }
+
+  Widget buildConnectSuccessText() {
+    return const Text(
+      '设备连接成功',
+      style: TextStyle(
+        color: Colors.green,
+        fontSize: 25,
+      ),
+      textAlign: TextAlign.left,
+    );
+  }
+
+  Widget buildConnectingText() {
+    return const Row(
+      children: [
+        Expanded(
+          child: Text(
+            '设备连接中',
+            style: TextStyle(
+              fontSize: 40,
+              color: Colors.blue,
+            ),
+          ),
+        ),
+        CircularProgressIndicator(
+          valueColor: AlwaysStoppedAnimation(
+            Colors.blue,
+          ),
+        ),
+        SizedBox(
+          width: 20,
+        ),
+      ],
+    );
+  }
+
+  Widget buildReconnectButton() {
+    return Container(
+      margin: const EdgeInsets.only(top: 4),
+      width: 134,
+      child: VButton(
+        onTap: () async {
+          /// TODO
+          await connect();
+          worker.connectErrorEvent.addListener(_onConnectFail);
+          worker.connectedEvent.addListener(_onConnectSuccess);
+
+          /// TODO 后面需要改,这边暂时演示用
+          Future.delayed(const Duration(milliseconds: 8000), () {
+            if (!connectSuccessState) {
+              connectFailState = true;
+            }
+          });
+        },
+        child: const Row(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: [
+            Icon(Icons.connected_tv_rounded, size: 24),
+            SizedBox(
+              width: 8,
+            ),
+            Text("重连", style: TextStyle(fontSize: 20)),
+          ],
+        ),
+      ),
+    );
+  }
+
+  Widget buildConnectStateWidgets() {
+    return Column(
+      children: [
+        if (connectFailState) buildConnectFailText(),
+        if (connectSuccessState) buildConnectSuccessText(),
+        if (isConnect)
+          buildConnectingText()
+        else if (connectFailState)
+          buildReconnectButton(),
+      ],
+    );
+  }
+
+  Widget buildMainWidget() {
+    return SizedBox(
+      height: 100,
+      child: Row(
+        children: [
+          buildInputField(),
+          Expanded(
+            child: buildConnectStateWidgets(),
+          ),
+        ],
+      ),
+    );
+  }
+}

File diff suppressed because it is too large
+ 0 - 1
lib/pages/contract/contract_template/controller.dart


+ 8 - 4
lib/pages/home/widgets/avatar.dart

@@ -10,10 +10,14 @@ class HomeAvatarWidget extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return CircleAvatar(
-      backgroundColor: Colors.black54,
-      radius: size / 2 + 4,
-      child: Icon(Icons.person, color: Colors.white, size: size),
+    return ClipOval(
+      child: CircleAvatar(
+        backgroundColor: Colors.black54,
+        radius: size / 2 + 4,
+        child: Image.asset(
+          'assets/images/avatar.png',
+        ),
+      ),
     );
   }
 }

+ 1 - 0
pubspec.yaml

@@ -62,6 +62,7 @@ dependencies:
   super_tooltip: 2.0.4
   flutter_staggered_grid_view: 0.6.1
   animations: 2.0.2
+  permission_handler: 10.2.0
 
 dependencies_overrides:
   dio: 5.3.2

Some files were not shown because too many files changed in this diff