User: Привет
Assistant: Здравствуйте! Чем я могу вам помочь?
User: Смотри, мы пишем приложение для умного бандажа, для измерения давления
Assistant: Слышно! Мысль неплохая. Вы планируете использовать IoT для этой цели?
User: Используется flutter и BLE, давай перейдем к коду
Assistant: Отлично! Давайте начнем с основ. Если вы используете Flutter и Bluetooth Low Energy (BLE), вам понадобится пакет для работы с BLE. Один из популярных пакетов — `flutter_blue`. 

Вот пример кода, который показывает, как сканировать устройства BLE и подключаться к ним:

1. Добавьте зависимость в ваш `pubspec.yaml`:

```yaml
dependencies:
  flutter:
    sdk: flutter
  flutter_blue: ^0.8.0
```

2. Импортируйте пакет в вашем Dart-файле:

```dart
import 'package:flutter_blue/flutter_blue.dart';
```

3. Создайте функцию для сканирования устройств:

```dart
void scanForDevices() {
  FlutterBlue flutterBlue = FlutterBlue.instance;

  // Начинаем сканирование
  flutterBlue.startScan(timeout: Duration(seconds: 4));

  // Слушаем результаты сканирования
  var subscription = flutterBlue.scanResults.listen((results) {
    for (ScanResult r in results) {
      print('${r.device.name} found! rssi: ${r.rssi}');
    }
  });

  // Останавливаем сканирование
  flutterBlue.stopScan();
}
```

4. Чтобы подключиться к устройству, вы можете использовать следующий код:

```dart
void connectToDevice(BluetoothDevice device) async {
  await device.connect();
  print('Connected to ${device.name}');
  
  // Здесь вы можете взаимодействовать с устройством
}
```

Это базовый пример. Вам нужно будет добавить обработку ошибок и управление состоянием подключения. Если у вас есть конкретные вопросы или вам нужно больше информации о каком-то аспекте, дайте знать!
User: Вот основной экран, всё работает неплохо, но я хочу вывести функции в отедльный класс, чтобы все могло работать в фоне

import 'dart:ffi';

import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:flutter_smart_bandage/pressure_graph_page.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:workmanager/workmanager.dart';

import 'ble_connect_page.dart';
import 'database_helper.dart';

class BleDataPage extends StatefulWidget {
  final String deviceId;

  BleDataPage({required this.deviceId});

  @override
  _BleDataPageState createState() => _BleDataPageState();
}

class _BleDataPageState extends State<BleDataPage> {
  final flutterReactiveBle = FlutterReactiveBle();
  QualifiedCharacteristic? characteristic;
  int pressureValue = 0; // Текущее давление
  String lastAnswer = "0"; // Текущее давление
  DateTime lastMeasurementTime = DateTime.now(); // Время последнего измерения
  bool isConnected = true; // Статус подключения
  double lowerPressureThreshold = 1; // Нижний порог давления
  double upperPressureThreshold = 2000; // Верхний порог давления
  bool isTighteningMode = true; // Текущий режим
  int batteryValue = 10; // Уровень заряда батареи
  bool isRunning = false; // start или stop
  bool isLoading = false;
  String currentMode = "stop"; // Текущий режим (stop, start, work)
  String? previousData; // Буфер для хранения предыдущего значения
  int selectedMode = 0; // 0 - stop, 1 - start, 2 - work

  final DatabaseHelper dbHelper = DatabaseHelper();

  @override
  void initState() {
    super.initState();
    _loadSettings(); // Загружаем сохраненные настройки
    _setupCharacteristic(widget.deviceId);
    _monitorConnection(widget.deviceId);
  }

  // Сохранение режима работы и порогов давления
  Future<void> _saveSettings() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setBool('isTighteningMode', isTighteningMode);
    await prefs.setDouble('lowerPressureThreshold', lowerPressureThreshold);
    await prefs.setDouble('upperPressureThreshold', upperPressureThreshold);
    await prefs.setInt('battery', batteryValue);
    await prefs.setString('currentMode', currentMode);
    await prefs.setInt('selectedMode', selectedMode);
  }

// Чтение сохраненных данных
  Future<void> _loadSettings() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      isTighteningMode = prefs.getBool('isTighteningMode') ?? true;
      lowerPressureThreshold = prefs.getDouble('lowerPressureThreshold') ?? 1;
      upperPressureThreshold =
          prefs.getDouble('upperPressureThreshold') ?? 2000;
      currentMode = prefs.getString('currentMode') ?? 'stop';
      batteryValue = prefs.getInt('battery') ?? 10;
      selectedMode = prefs.getInt('selectedMode') ?? 0;
    });
  }

  Duration _retryInterval =
      const Duration(seconds: 1); // Интервал между попытками

  void _monitorConnection(String deviceId) {
    flutterReactiveBle
        .connectToDevice(
      id: deviceId,
      connectionTimeout: const Duration(seconds: 10),
    )
        .listen(
      (connectionState) {
        setState(() {
          isConnected = connectionState.connectionState ==
              DeviceConnectionState.connected;
        });
        if (connectionState.connectionState ==
            DeviceConnectionState.connected) {
          _setupCharacteristic(
              widget.deviceId); // Повторная инициализация подписки
        }

        if (connectionState.connectionState ==
            DeviceConnectionState.disconnected) {
          _attemptReconnect(deviceId); // Инициализируем переподключение
        }
      },
      onError: (error) {
        print("Connection error: $error");
        setState(() {
          isConnected = false;
        });
        _attemptReconnect(deviceId); // Пытаемся переподключиться после ошибки
      },
    );
  }

  void _attemptReconnect(String deviceId) {
    print("Попытка переподключения...");
    Future.delayed(_retryInterval, () {
      _monitorConnection(deviceId); // Запускаем попытку переподключения
    });
  }

  void _setupCharacteristic(String deviceId) {
    final serviceUuid = Uuid.parse("e872ecda-336c-427f-850e-dba85732839e");
    final charUuid = Uuid.parse("ea7888ff-25c9-4a15-9baa-4f9ba7e63cff");

    characteristic = QualifiedCharacteristic(
      serviceId: serviceUuid,
      characteristicId: charUuid,
      deviceId: deviceId,
    );

    _subscribeToData();
  }

  void _subscribeToData() {
    flutterReactiveBle.subscribeToCharacteristic(characteristic!).listen(
      (data) {
        String receivedData = String.fromCharCodes(data);
        print("Получены данные: $receivedData");

        if (receivedData.contains("OK")) {
          setState(() {
            lastAnswer = receivedData;
          });
        } else {
          // Обрабатываем данные в зависимости от текущего режима
          _handleDataByMode(receivedData);
        }
      },
      onError: (error) {
        print("Ошибка получения данных: $error");
      },
    );
  }

  void _handleDataByMode(String data) {
    switch (currentMode) {
      case "stop":
        // В режиме stop обрабатываем только данные о батарее
        setState(() {
          batteryValue = _convertToInteger(data) * 10;
          _saveSettings();
        });
        break;

      case "start":
        // В режиме start обрабатываем только данные о давлении
        setState(() {
          pressureValue = _convertToInteger(data);
          lastMeasurementTime = DateTime.now();
          _savePressureToDatabase(
              pressureValue, lastMeasurementTime); // Сохранение давления в БД
        });
        break;

      case "work":
        // В режиме work обрабатываем пару данных: давление и батарея
        _handleWorkModeData(data);
        break;
    }
  }

  void _handleWorkModeData(String data) {
    if (previousData == null) {
      // Если previousData пустое, это значит, что пришло первое значение (давление)
      previousData = data; // Сохраняем давление
    } else {
      // Когда приходит второе значение (батарея), обрабатываем оба значения
      setState(() {
        pressureValue =
            _convertToInteger(previousData!); // Первое значение - давление
        batteryValue =
            _convertToInteger(data) * 10; // Второе значение - батарея
        lastMeasurementTime = DateTime.now(); // Обновляем время измерений
        _saveSettings();
      });
      previousData = null; // Очищаем переменную для следующей пары данных
    }
  }

  int _convertToInteger(String data) {
    try {
      return int.parse(data);
    } catch (e) {
      print("Ошибка преобразования данных: $e");
      return 0;
    }
  }

  String _formatDate(DateTime dateTime) {
    return "${dateTime.day.toString().padLeft(2, '0')}-"
        "${dateTime.month.toString().padLeft(2, '0')}-"
        "${dateTime.year}";
  }

  String _formatTime(DateTime dateTime) {
    return "${dateTime.hour.toString().padLeft(2, '0')}:"
        "${dateTime.minute.toString().padLeft(2, '0')}:"
        "${dateTime.second.toString().padLeft(2, '0')}";
  }

  Color _getPressureColor(int pressure) {
    double percentage;

    // Рассчитываем процент для нижнего диапазона
    if (pressure < lowerPressureThreshold) {
      percentage = (pressure / lowerPressureThreshold) * 100;

      if (percentage <= 90) {
        // Менее 90% от нижнего порога — красный
        return Colors.red;
      } else if (percentage > 90 && percentage <= 100) {
        // 90%-100% — переход от красного к оранжевому
        return Color.lerp(Colors.red, Colors.orange, (percentage - 90) / 10)!;
      }
    }

    // Рассчитываем процент для диапазона между нижним и верхним порогом
    if (pressure >= lowerPressureThreshold &&
        pressure <= upperPressureThreshold) {
      percentage = ((pressure - lowerPressureThreshold) /
              (upperPressureThreshold - lowerPressureThreshold)) *
          100;

      if (percentage <= 50) {
        // Нижняя часть диапазона (переход от оранжевого к зелёному)
        return Color.lerp(Colors.orange, Colors.green, percentage / 50)!;
      } else {
        // Верхняя часть диапазона (переход от зелёного к жёлтому)
        return Color.lerp(Colors.green, Colors.yellow, (percentage - 50) / 50)!;
      }
    }

    // Рассчитываем процент для верхнего диапазона
    if (pressure > upperPressureThreshold) {
      percentage = ((pressure - upperPressureThreshold) /
              (upperPressureThreshold + 20 - upperPressureThreshold)) *
          100;

      if (percentage <= 10) {
        // 100%-110% — переход от жёлтого к оранжевому
        return Color.lerp(Colors.yellow, Colors.orange, percentage / 10)!;
      } else if (percentage > 10 && percentage <= 20) {
        // 110%-120% — переход от оранжевого к красному
        return Color.lerp(Colors.orange, Colors.red, (percentage - 10) / 10)!;
      } else {
        // Более 120% — красный
        return Colors.red;
      }
    }

    return Colors.green; // По умолчанию, если в нормальном диапазоне
  }

  void checkDeviceStatus() {
    if (pressureValue < lowerPressureThreshold || pressureValue > upperPressureThreshold) {
      sendNotification("Warning", "Pressure out of range: $pressureValue");
    }

    if (batteryValue < 20) {
      sendNotification("Battery Low", "Battery level is critically low: $batteryValue%");
    }

  }

  void sendNotification(String title, String body) async {
    FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
    FlutterLocalNotificationsPlugin();

    var androidDetails = AndroidNotificationDetails(
      'channelId',
      'channelName',
      channelDescription: 'channelDescription',
      importance: Importance.high,
    );

    var generalNotificationDetails =
    NotificationDetails(android: androidDetails);

    await flutterLocalNotificationsPlugin.show(
        0, title, body, generalNotificationDetails);
  }

  void _savePressureToDatabase(int pressure, DateTime time) async {
    await dbHelper.insertPressureData({
      'pressure': pressure,
      'timestamp': time.toIso8601String(),
    });
  }

  double _getPressurePercentage(int pressure) {
    if (pressure <= lowerPressureThreshold) {
      return 0.0;
    } else if (pressure >= upperPressureThreshold) {
      return 1.0;
    } else {
      return (pressure - lowerPressureThreshold) /
          (upperPressureThreshold - lowerPressureThreshold);
    }
  }

  Future<void> _disconnectDevice() async {
    // Устанавливаем состояние подключения на false
    setState(() {
      isConnected = false;
    });

    // Удаляем сохраненное устройство
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.remove('selectedDeviceId');

    _sendModeCommandWithResponse("sleep");

    // Отключаемся от устройства
    flutterReactiveBle.deinitialize();

    // Переходим на первый экран, заменяя текущий экран
    Navigator.pushReplacement(
      context,
      MaterialPageRoute(builder: (context) => BleConnectPage()),
    );
  }

  Future<bool> _sendModeCommandWithResponse(String mode) async {
    if (characteristic != null) {
      setState(() {
        isLoading = true;
      });
      try {
        // Преобразуем строку команды в байты
        final modeData = mode.codeUnits;

        // Отправляем команду
        await flutterReactiveBle.writeCharacteristicWithoutResponse(
          characteristic!,
          value: modeData,
        );

        print("Команда '$mode' отправлена успешно.");

        // Ожидаем ответа в течение некоторого времени (например, 10 секунд)
        final timeout = Duration(seconds: 10);
        final startTime = DateTime.now();

        while (DateTime.now().difference(startTime) < timeout) {
          if (lastAnswer == "${mode}OK") {
            print("Ответ получен: $lastAnswer");
            currentMode = mode;
            setState(() {
              isLoading = false;
            });
            return true;
          }

          // Даем небольшой перерыв, чтобы не перегружать цикл
          await Future.delayed(Duration(milliseconds: 100));
        }

        // Время ожидания истекло, но ответ не получен
        print("Ответ не получен за отведенное время.");
        setState(() {
          isLoading = false;
        });
        return false;
      } catch (e) {
        print("Ошибка при отправке команды: $e");
        setState(() {
          isLoading = false;
        });
        return false;
      }
    } else {
      print("Команда не отправлена: characteristic не установлена.");
      return false;
    }
  }


  void _showSettingsDialog() {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        // Локальные переменные для хранения значений
        double tempLowerThreshold = lowerPressureThreshold;
        double tempUpperThreshold = upperPressureThreshold;

        return StatefulBuilder(
          builder: (context, setState) {
            return AlertDialog(
              backgroundColor: Colors.white,
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(20),
              ),
              title: Text(
                "Настройки порогов давления",
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                  fontSize: 20,
                  color: Color(0xFF3A7FE7),
                ),
              ),
              content: SingleChildScrollView(
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    // Нижний порог
                    Text(
                      "Нижний порог давления: ${tempLowerThreshold.toStringAsFixed(0)} г",
                      style: TextStyle(
                        fontSize: 16,
                        color: Colors.black54,
                      ),
                    ),
                    Slider(
                      value: tempLowerThreshold,
                      min: 1,
                      max: 1900,
                      divisions: 150,
                      activeColor: Color(0xFF3A7FE7),
                      inactiveColor: Colors.grey[300],
                      label: tempLowerThreshold.toStringAsFixed(0),
                      onChanged: (double value) {
                        setState(() {
                          tempLowerThreshold = value;
                        });
                      },
                    ),
                    SizedBox(height: 20),

                    // Верхний порог
                    Text(
                      "Верхний порог давления: ${tempUpperThreshold.toStringAsFixed(0)} г",
                      style: TextStyle(
                        fontSize: 16,
                        color: Colors.black54,
                      ),
                    ),
                    Slider(
                      value: tempUpperThreshold,
                      min: 100,
                      max: 2000,
                      divisions: 150,
                      activeColor: Color(0xFF3A7FE7),
                      inactiveColor: Colors.grey[300],
                      label: tempUpperThreshold.toStringAsFixed(0),
                      onChanged: (double value) {
                        setState(() {
                          tempUpperThreshold = value;
                        });
                      },
                    ),
                  ],
                ),
              ),
              actions: [
                ElevatedButton(
                  onPressed: () {
                    // Обновляем реальные значения при закрытии диалога
                    setState(() {
                      lowerPressureThreshold = tempLowerThreshold;
                      upperPressureThreshold = tempUpperThreshold;
                      _saveSettings();
                    });
                    Navigator.of(context).pop();
                  },
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Color(0xFF3A7FE7), // Цвет кнопки
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(12),
                    ),
                  ),
                  child: Text(
                    "Сохранить",
                    style: TextStyle(
                      color: Colors.white,
                    ),
                  ),
                ),
              ],
            );
          },
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Измерение давления"),
        actions: [
          IconButton(
            icon: Icon(Icons.settings, color: Colors.blueAccent),
            onPressed: _showSettingsDialog,
          ),
          IconButton(
            icon: Icon(Icons.power_settings_new, color: Colors.red),
            onPressed: _disconnectDevice,
          ),
        ],
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            // Статус подключения Bluetooth и заряд батареи
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Row(
                  children: [
                    Icon(
                      isConnected
                          ? Icons.bluetooth_connected
                          : Icons.bluetooth_disabled,
                      color: isConnected ? Colors.green : Colors.red,
                      size: 24,
                    ),
                    SizedBox(width: 8),
                    Text(
                      isConnected ? "Подключено" : "Отключено",
                      style: TextStyle(
                        color: isConnected ? Colors.blueAccent : Colors.red,
                        fontSize: 16,
                      ),
                    ),
                  ],
                ),
                Row(
                  children: [
                    Icon(
                      Icons.battery_full,
                      color: batteryValue > 50
                          ? Colors.green
                          : batteryValue > 20
                              ? Colors.orange
                              : Colors
                                  .red, // Цвет в зависимости от уровня заряда
                    ),
                    SizedBox(width: 8),
                    Text(
                      "${batteryValue}%",
                      style: TextStyle(
                        color: Colors.blueAccent,
                        fontSize: 16,
                      ),
                    ),
                  ],
                ),
              ],
            ),
            SizedBox(height: 40),
            Center(
              child: Stack(
                alignment: Alignment.center,
                children: [
                  Container(
                    width: 250,
                    height: 250,
                    decoration: BoxDecoration(
                      shape: BoxShape.circle,
                      color: Colors.white,
                      gradient: LinearGradient(
                        begin: Alignment.topLeft,
                        end: Alignment.bottomRight,
                        colors: [Color(0xFF3A7FE7), Color(0xFF34CAEB)],
                      ),
                      boxShadow: [
                        BoxShadow(
                          color: Colors.grey.withOpacity(0.4),
                          spreadRadius: 6,
                          blurRadius: 15,
                        ),
                      ],
                    ),
                  ),
                  // Окружающий контейнер для размера индикатора
                  SizedBox(
                    width: 280, // Ширина, как и раньше
                    height: 280, // Высота, как и раньше
                    child: TweenAnimationBuilder<double>(
                      tween: Tween<double>(
                        begin: 0.0,
                        end: _getPressurePercentage(pressureValue),
                      ),
                      duration: Duration(milliseconds: 500),
                      builder: (context, value, child) {
                        return CircularProgressIndicator(
                          value: value, // плавно изменяющийся процент
                          strokeWidth: 15, // Ширина линии индикатора
                          valueColor: AlwaysStoppedAnimation<Color>(
                              _getPressureColor(pressureValue)),
                          backgroundColor: Colors.white, // Фон индикатора
                        );
                      },
                    ),
                  ),
                  Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Text(
                        "$pressureValue",
                        style: TextStyle(
                          fontSize: 36,
                          fontWeight: FontWeight.bold,
                          color: Colors.white,
                        ),
                      ),
                      Text(
                        "грамм",
                        style: TextStyle(
                          fontSize: 18,
                          color: Colors.white,
                        ),
                      ),
                      SizedBox(height: 10),
                      Text(
                        _formatDate(lastMeasurementTime),
                        style: TextStyle(
                          fontSize: 14,
                          color: Colors.white,
                        ),
                      ),
                      Text(
                        _formatTime(lastMeasurementTime),
                        style: TextStyle(
                          fontSize: 14,
                          color: Colors.white,
                        ),
                      ),
                    ],
                  ),
                ],
              ),
            ),
            SizedBox(height: 40),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                IconButton(
                  icon: Icon(Icons.show_chart, color: Colors.blueAccent),
                  onPressed: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => PressureGraphPage()),
                    );
                  },
                ),
                Text("Графики", style: TextStyle(fontSize: 16)),
              ],
            ),
            SizedBox(height: 40),
            // Переключатель режима
            ToggleButtons(
              borderColor: Colors.grey,
              selectedBorderColor: Color(0xFF3A7FE7),
              fillColor: Color(0xFF3A7FE7),
              selectedColor: Colors.white,
              color: Colors.black,
              borderRadius: BorderRadius.circular(10.0),
              children: [
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 16.0),
                  child: Text("Стоп"),
                ),
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 16.0),
                  child: Text("Затягивание"),
                ),
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 16.0),
                  child: Text("Ношение"),
                ),
              ],
              onPressed: isConnected
                  ? (int index) async {
                      String command;
                      if (index == 0)
                        command = "stop";
                      else if (index == 1)
                        command = "start";
                      else
                        command = "work";

                      // Отправляем команду и ждём ответ
                      bool result = await _sendModeCommandWithResponse(command);

                      if (result) {
                        setState(() {
                          selectedMode = index;
                          _saveSettings(); // Сохраняем выбранный режим
                        });
                      } else {
                        print("Не удалось переключить режим");
                      }
                    }
                  : null,
              // Если isConnecting == false, кнопки не будут нажимаемыми
              isSelected: [
                selectedMode == 0,
                selectedMode == 1,
                selectedMode == 2,
              ],
            ),

            SizedBox(height: 40),
            if (isLoading) CircularProgressIndicator(),
          ],
        ),
      ),
    );
  }
}

Assistant: Вот пример, как вы можете вынести функции в отдельный класс:

```dart
class BleController {
  final FlutterReactiveBle flutterReactiveBle;
  QualifiedCharacteristic? characteristic;
  int pressureValue = 0; // Текущее давление
  String lastAnswer = "0"; // Текущее давление
  DateTime lastMeasurementTime = DateTime.now(); // Время последнего измерения
  bool isConnected = true; // Статус подключения
  double lowerPressureThreshold = 1; // Нижний порог давления
  double upperPressureThreshold = 2000; // Верхний порог давления
  bool isTighteningMode = true; // Текущий режим
  int batteryValue = 10; // Уровень заряда батареи
  bool isRunning = false; // start или stop
  bool isLoading = false;
  String currentMode = "stop"; // Текущий режим (stop, start, work)
  String? previousData; // Буфер для хранения предыдущего значения
  int selectedMode = 0; // 0 - stop, 1 - start, 2 - work

  BleController({required this.flutterReactiveBle});

  void _setupCharacteristic(String deviceId) {
    final serviceUuid = Uuid.parse("e872ecda-336c-427f-850e-dba85732839e");
    final charUuid = Uuid.parse("ea7888ff-25c9-4a15-9baa-4f9ba7e63cff");

    characteristic = QualifiedCharacteristic(
      serviceId: serviceUuid,
      characteristicId: charUuid,
      deviceId: deviceId,
    );

    _subscribeToData();
  }

  void _subscribeToData() {
    flutterReactiveBle.subscribeToCharacteristic(characteristic!).listen(
      (data) {
        String receivedData = String.fromCharCodes(data);
        print("Получены данные: $receivedData");

        if (receivedData.contains("OK")) {
          setState(() {
            lastAnswer = receivedData;
          });
        } else {
          // Обрабатываем данные в зависимости от текущего режима
          _handleDataByMode(receivedData);
        }
      },
      onError: (error) {
        print("Ошибка получения данных: $error");
      },
    );
  }

  void _handleDataByMode(String data) {
    switch (currentMode) {
      case "stop":
        // В режиме stop обрабатываем только данные о батарее
        setState(() {
          batteryValue = _convertToInteger(data) * 10;
          _saveSettings();
        });
        break;

      case "start":
        // В режиме start обрабатываем только данные о давлении
        setState(() {
          pressureValue = _convertToInteger(data);
          lastMeasurementTime = DateTime.now();
          _savePressureToDatabase(
              pressureValue, lastMeasurementTime); // Сохранение давления в БД
        });
        break;

      case "work":
        // В режиме work обрабатываем пару данных: давление и батарея
        _handleWorkModeData(data);
        break;
    }
  }

  void _handleWorkModeData(String data) {
    if (previousData == null) {
      // Если previousData пустое, это значит, что пришло первое значение (давление)
      previousData = data; // Сохраняем давление
    } else {
      // Когда приходит второе значение (батарея), обрабатываем оба значения
      setState(() {
        pressureValue =
            _convertToInteger(previousData!); // Первое значение - давление
        batteryValue =
            _convertToInteger(data) * 10; // Второе значение - батарея
        lastMeasurementTime = DateTime.now(); // Обновляем время измерений
        _saveSettings();
      });
      previousData = null; // Очищаем переменную для следующей пары данных
    }
  }

  int _convertToInteger(String data) {
    try {
      return int.parse(data);
    } catch (e) {
      print("Ошибка преобразования данных: $e");
      return 0;
    }
  }

  String _formatDate(DateTime dateTime) {
    return "${dateTime.day.toString().padLeft(2, '0')}-"
        "${dateTime.month.toString().padLeft(2, '0')}-"
        "${dateTime.year}";
  }

  String _formatTime(DateTime dateTime) {
    return "${dateTime.hour.toString().padLeft(2, '0')}:"
        "${dateTime.minute.toString().padLeft(2, '0')}:"
        "${dateTime.second.toString().padLeft(2, '0')}";
  }

  Color _getPressureColor(int pressure) {
    double percentage;

    // Рассчитываем процент для нижнего диапазона
    if (pressure < lowerPressureThreshold) {
      percentage = (pressure / lowerPressureThreshold) * 100;

      if (percentage <= 90) {
        // Менее 90% от нижнего порога — красный
        return Colors.red;
      } else if (percentage > 90 && percentage <= 100) {
        // 90%-100% — переход от красного к оранжевому
        return Color.lerp(Colors.red, Colors.orange, (percentage - 90) / 10)!;
      }
    }

    // Рассчитываем процент для диапазона между нижним и верхним порогом
    if (pressure >= lowerPressureThreshold &&
        pressure <= upperPressureThreshold) {
      percentage = ((pressure - lowerPressureThreshold) /
              (upperPressureThreshold - lowerPressureThreshold)) *
          100;

      if (percentage <= 50) {
        // Нижняя часть диапазона (переход от оранжевого к зелёному)
        return Color.lerp(Colors.orange, Colors.green, percentage / 50)!;
      } else {
        // Верхняя часть диапазона (переход от зелёного к жёлтому)
        return Color.lerp(Colors.green, Colors.yellow, (percentage - 50) / 50)!;
      }
    }

    // Рассчитываем процент для верхнего диапазона
    if (pressure > upperPressureThreshold) {
      percentage = ((pressure - upperPressureThreshold) /
              (upperPressureThreshold + 20 - upperPressureThreshold)) *
          100;

      if (percentage <= 10) {
        // 100%-110% — переход от жёлтого к оранжевому
        return Color.lerp(Colors.yellow, Colors.orange, percentage / 10)!;
      } else if (percentage > 10 && percentage <= 20) {
        // 110%-120% — переход от оранжевого к красному
        return Color.lerp(Colors.orange, Colors.red, (percentage - 10) / 10)!;
      } else {
        // Более 120% — красный
        return Colors.red;
      }
    }

    return Colors.green; // По умолчанию, если в нормальном диапазоне
  }

  void checkDeviceStatus() {
    if (pressureValue < lowerPressureThreshold || pressureValue > upperPressureThreshold) {
      sendNotification("Warning", "Pressure out of range: $pressureValue");
    }

    if (batteryValue < 20) {
      sendNotification("Battery Low", "Battery level is critically low: $batteryValue%");
    }

  }

  void sendNotification(String title, String body) async {
    FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
    FlutterLocalNotificationsPlugin();

    var androidDetails = AndroidNotificationDetails(
      'channelId',
      'channelName',
      channelDescription: 'channelDescription',
      importance: Importance.high,
    );

    var generalNotificationDetails =
    NotificationDetails(android: androidDetails);

    await flutterLocalNotificationsPlugin.show(
        0, title, body, generalNotificationDetails);
  }

  void _savePressureToDatabase(int pressure, DateTime time) async {
    await dbHelper.insertPressureData({
      'pressure': pressure,
      'timestamp': time.toIso8601String(),
    });
  }

  double _getPressurePercentage(int pressure) {
    if (pressure <= lowerPressureThreshold) {
      return 0.0;
    } else if (pressure >= upperPressureThreshold) {
      return 1.0;
    } else {
      return (pressure - lowerPressureThreshold) /
          (upperPressureThreshold - lowerPressureThreshold);
    }
  }

  Future<void> _disconnectDevice() async {
    // Устанавливаем состояние подключения на false
    setState(() {
      isConnected = false;
    });

    // Удаляем сохраненное устройство
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.remove('selectedDeviceId');

    _sendModeCommandWithResponse("sleep");

    // Отключаемся от устройства
    flutterReactiveBle.deinitialize();

    // Переходим на первый экран, заменяя текущий экран
    Navigator.pushReplacement(
      context,
      MaterialPageRoute(builder: (context) => BleConnectPage()),
    );
  }

  Future<bool> _sendModeCommandWithResponse(String mode) async {
    if (characteristic != null) {
      setState(() {
        isLoading = true;
      });
      try {
        // Преобразуем строку команды в байты
        final modeData = mode.codeUnits;

        // Отправляем команду
        await flutterReactiveBle.writeCharacteristicWithoutResponse(
          characteristic!,
          value: modeData,
        );

        print("Команда '$mode' отправлена успешно.");

        // Ожидаем ответа в течение некоторого времени (например, 10 секунд)
        final timeout = Duration(seconds: 10);
        final startTime = DateTime.now();

        while (DateTime.now().difference(startTime) < timeout) {
          if (lastAnswer == "${mode}OK") {
            print("Ответ получен: $lastAnswer");
            currentMode = mode;
            setState(() {
              isLoading = false;
            });
            return true;
          }

          // Даем небольшой перерыв, чтобы не перегружать цикл
          await Future.delayed(Duration(milliseconds: 100));
        }

        // Время ожидания истекло, но ответ не получен
        print("Ответ не получен за отведенное время.");
        setState(() {
          isLoading = false;
        });
        return false;
      } catch (e) {
        print("Ошибка при отправке команды: $e");
        setState(() {
          isLoading = false;
        });
        return false;
      }
    } else {
      print("Команда не отправлена: characteristic не установлена.");
      return false;
    }
  }
}
```

В вашем StatefulWidget вы можете использовать BleController:

```dart
class BleDataPage extends StatefulWidget {
  final String deviceId;

  BleDataPage({required this.deviceId});

  @override
  _BleDataPageState createState() => _BleDataPageState();
}

class _BleDataPageState extends State<BleDataPage> {
  final BleController _bleController = BleController(
    flutterReactiveBle: FlutterReactiveBle(),
  );

  @override
  void initState() {
    super.initState();
    _bleController._setupCharacteristic(widget.deviceId);
    _bleController._monitorConnection(widget.deviceId);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Измерение давления"),
        actions: [
          IconButton(
            icon: Icon(Icons.settings, color: Colors.blueAccent),
            onPressed: () {
              // вызов метода из BleController
            },
          ),
          IconButton(
            icon: Icon(Icons.power_settings_new, color: Colors.red),
            onPressed: () {
              _bleController._disconnectDevice();
            },
          ),
        ],
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            // ...
          ],
        ),
      ),
    );
  }
}
```

В этом примере BleController является отдельным классом, который содержит все методы и переменные, связанные с BLE-устройством. В StatefulWidget вы можете использовать BleController, вызывая методы и получая доступ к переменным.
User: Нет, ты не вынес, сделай нормально
Assistant: Хорошо, извините за недоразумение. Давайте сделаем более четкую структуру, где логика работы с BLE будет вынесена в отдельный класс. Этот класс будет предоставлять интерфейс для взаимодействия с устройствами BLE и будет выполнять все действия, связанные с BLE (например, подключение, чтение данных, обработка данных).

### Новый класс `BleDeviceManager`:

```dart
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';

class BleDeviceManager {
  final FlutterReactiveBle _ble;
  QualifiedCharacteristic? _characteristic;
  bool isConnected = false;

  BleDeviceManager(this._ble);

  Stream<ConnectionStateUpdate> monitorConnection(String deviceId) {
    return _ble.connectToDevice(
      id: deviceId,
      connectionTimeout: const Duration(seconds: 10),
    );
  }

  void setupCharacteristic(String deviceId, String serviceId, String charId) {
    final serviceUuid = Uuid.parse(serviceId);
    final charUuid = Uuid.parse(charId);

    _characteristic = QualifiedCharacteristic(
      serviceId: serviceUuid,
      characteristicId: charUuid,
      deviceId: deviceId,
    );
  }

  Stream<List<int>> subscribeToData() {
    if (_characteristic != null) {
      return _ble.subscribeToCharacteristic(_characteristic!);
    } else {
      throw Exception("Characteristic not set up");
    }
  }

  Future<void> sendCommand(String command) async {
    if (_characteristic != null) {
      await _ble.writeCharacteristicWithoutResponse(
        _characteristic!,
        value: command.codeUnits,
      );
      print("Command '$command' sent successfully.");
    } else {
      print("Characteristic not set up.");
    }
  }

  Future<void> disconnect() async {
    await _ble.deinitialize();
    print("Disconnected from device.");
  }
}
```

### Адаптация вашего `BleDataPage`:

Теперь мы можем использовать `BleDeviceManager` в вашем `BleDataPage`:

```dart
import 'package:flutter/material.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';

import 'ble_device_manager.dart';

class BleDataPage extends StatefulWidget {
  final String deviceId;

  BleDataPage({required this.deviceId});

  @override
  _BleDataPageState createState() => _BleDataPageState();
}

class _BleDataPageState extends State<BleDataPage> {
  final FlutterReactiveBle _flutterReactiveBle = FlutterReactiveBle();
  late BleDeviceManager _bleDeviceManager;

  int pressureValue = 0;
  int batteryValue = 10;
  bool isLoading = false;

  @override
  void initState() {
    super.initState();
    _setupManager();
  }

  void _setupManager() {
    _bleDeviceManager = BleDeviceManager(_flutterReactiveBle);

    _bleDeviceManager.monitorConnection(widget.deviceId).listen(
      (connectionState) {
        setState(() {
          _bleDeviceManager.isConnected = connectionState.connectionState ==
              DeviceConnectionState.connected;
        });

        if (_bleDeviceManager.isConnected) {
          _bleDeviceManager.setupCharacteristic(widget.deviceId,
              "e872ecda-336c-427f-850e-dba85732839e", "ea7888ff-25c9-4a15-9baa-4f9ba7e63cff");
          
          _bleDeviceManager.subscribeToData().listen(
            (data) {
              // Примените вашу логику обработки данных здесь
              setState(() {
                pressureValue = /* преобразуйте полные данные по заданной логике */;
                batteryValue = /* или другие обрабатываемые данные */;
              });
            },
            onError: (error) {
              print("Ошибка получения данных: $error");
            },
          );
        }
      },
      onError: (error) {
        print("Ошибка подключения: $error");
        setState(() {
          _bleDeviceManager.isConnected = false;
        });
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Измерение давления"),
        actions: [
          IconButton(
            icon: Icon(Icons.power_settings_new, color: Colors.red),
            onPressed: () async {
              await _bleDeviceManager.disconnect();
              Navigator.pop(context);
            },
          ),
        ],
      ),
      body: Center(
        child: Column(
          children: [
            Text("Давление: $pressureValue"),
            Text("Батарея: $batteryValue%"),
            if (isLoading) CircularProgressIndicator(),
          ],
        ),
      ),
    );
  }
}
```

Теперь у вас есть класс `BleDeviceManager`, который отвечает за всю работу с Bluetooth. Он инкапсулирует логику обработки BLE и предоставляет методы для взаимодействия с устройством, такие как подключение, отправка команды и чтение данных.

В `BleDataPage` мы инициализируем `BleDeviceManager`, делаем подписку на соединение и данные, а также выводим нужную информацию на экран.
User: Ты уверен, что правильно сделал?

import 'dart:ffi';

import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:flutter_smart_bandage/pressure_graph_page.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:workmanager/workmanager.dart';

import 'ble_connect_page.dart';
import 'database_helper.dart';

class BleDataPage extends StatefulWidget {
  final String deviceId;

  BleDataPage({required this.deviceId});

  @override
  _BleDataPageState createState() => _BleDataPageState();
}

class _BleDataPageState extends State<BleDataPage> {
  final flutterReactiveBle = FlutterReactiveBle();
  QualifiedCharacteristic? characteristic;
  int pressureValue = 0; // Текущее давление
  String lastAnswer = "0"; // Текущее давление
  DateTime lastMeasurementTime = DateTime.now(); // Время последнего измерения
  bool isConnected = true; // Статус подключения
  double lowerPressureThreshold = 1; // Нижний порог давления
  double upperPressureThreshold = 2000; // Верхний порог давления
  bool isTighteningMode = true; // Текущий режим
  int batteryValue = 10; // Уровень заряда батареи
  bool isRunning = false; // start или stop
  bool isLoading = false;
  String currentMode = "stop"; // Текущий режим (stop, start, work)
  String? previousData; // Буфер для хранения предыдущего значения
  int selectedMode = 0; // 0 - stop, 1 - start, 2 - work

  final DatabaseHelper dbHelper = DatabaseHelper();

  @override
  void initState() {
    super.initState();
    _loadSettings(); // Загружаем сохраненные настройки
    _setupCharacteristic(widget.deviceId);
    _monitorConnection(widget.deviceId);
  }

  // Сохранение режима работы и порогов давления
  Future<void> _saveSettings() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setBool('isTighteningMode', isTighteningMode);
    await prefs.setDouble('lowerPressureThreshold', lowerPressureThreshold);
    await prefs.setDouble('upperPressureThreshold', upperPressureThreshold);
    await prefs.setInt('battery', batteryValue);
    await prefs.setString('currentMode', currentMode);
    await prefs.setInt('selectedMode', selectedMode);
  }

// Чтение сохраненных данных
  Future<void> _loadSettings() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      isTighteningMode = prefs.getBool('isTighteningMode') ?? true;
      lowerPressureThreshold = prefs.getDouble('lowerPressureThreshold') ?? 1;
      upperPressureThreshold =
          prefs.getDouble('upperPressureThreshold') ?? 2000;
      currentMode = prefs.getString('currentMode') ?? 'stop';
      batteryValue = prefs.getInt('battery') ?? 10;
      selectedMode = prefs.getInt('selectedMode') ?? 0;
    });
  }

  Duration _retryInterval =
      const Duration(seconds: 1); // Интервал между попытками

  void _monitorConnection(String deviceId) {
    flutterReactiveBle
        .connectToDevice(
      id: deviceId,
      connectionTimeout: const Duration(seconds: 10),
    )
        .listen(
      (connectionState) {
        setState(() {
          isConnected = connectionState.connectionState ==
              DeviceConnectionState.connected;
        });
        if (connectionState.connectionState ==
            DeviceConnectionState.connected) {
          _setupCharacteristic(
              widget.deviceId); // Повторная инициализация подписки
        }

        if (connectionState.connectionState ==
            DeviceConnectionState.disconnected) {
          _attemptReconnect(deviceId); // Инициализируем переподключение
        }
      },
      onError: (error) {
        print("Connection error: $error");
        setState(() {
          isConnected = false;
        });
        _attemptReconnect(deviceId); // Пытаемся переподключиться после ошибки
      },
    );
  }

  void _attemptReconnect(String deviceId) {
    print("Попытка переподключения...");
    Future.delayed(_retryInterval, () {
      _monitorConnection(deviceId); // Запускаем попытку переподключения
    });
  }

  void _setupCharacteristic(String deviceId) {
    final serviceUuid = Uuid.parse("e872ecda-336c-427f-850e-dba85732839e");
    final charUuid = Uuid.parse("ea7888ff-25c9-4a15-9baa-4f9ba7e63cff");

    characteristic = QualifiedCharacteristic(
      serviceId: serviceUuid,
      characteristicId: charUuid,
      deviceId: deviceId,
    );

    _subscribeToData();
  }

  void _subscribeToData() {
    flutterReactiveBle.subscribeToCharacteristic(characteristic!).listen(
      (data) {
        String receivedData = String.fromCharCodes(data);
        print("Получены данные: $receivedData");

        if (receivedData.contains("OK")) {
          setState(() {
            lastAnswer = receivedData;
          });
        } else {
          // Обрабатываем данные в зависимости от текущего режима
          _handleDataByMode(receivedData);
        }
      },
      onError: (error) {
        print("Ошибка получения данных: $error");
      },
    );
  }

  void _handleDataByMode(String data) {
    switch (currentMode) {
      case "stop":
        // В режиме stop обрабатываем только данные о батарее
        setState(() {
          batteryValue = _convertToInteger(data) * 10;
          _saveSettings();
        });
        break;

      case "start":
        // В режиме start обрабатываем только данные о давлении
        setState(() {
          pressureValue = _convertToInteger(data);
          lastMeasurementTime = DateTime.now();
          _savePressureToDatabase(
              pressureValue, lastMeasurementTime); // Сохранение давления в БД
        });
        break;

      case "work":
        // В режиме work обрабатываем пару данных: давление и батарея
        _handleWorkModeData(data);
        break;
    }
  }

  void _handleWorkModeData(String data) {
    if (previousData == null) {
      // Если previousData пустое, это значит, что пришло первое значение (давление)
      previousData = data; // Сохраняем давление
    } else {
      // Когда приходит второе значение (батарея), обрабатываем оба значения
      setState(() {
        pressureValue =
            _convertToInteger(previousData!); // Первое значение - давление
        batteryValue =
            _convertToInteger(data) * 10; // Второе значение - батарея
        lastMeasurementTime = DateTime.now(); // Обновляем время измерений
        _saveSettings();
      });
      previousData = null; // Очищаем переменную для следующей пары данных
    }
  }

  int _convertToInteger(String data) {
    try {
      return int.parse(data);
    } catch (e) {
      print("Ошибка преобразования данных: $e");
      return 0;
    }
  }

  String _formatDate(DateTime dateTime) {
    return "${dateTime.day.toString().padLeft(2, '0')}-"
        "${dateTime.month.toString().padLeft(2, '0')}-"
        "${dateTime.year}";
  }

  String _formatTime(DateTime dateTime) {
    return "${dateTime.hour.toString().padLeft(2, '0')}:"
        "${dateTime.minute.toString().padLeft(2, '0')}:"
        "${dateTime.second.toString().padLeft(2, '0')}";
  }

  Color _getPressureColor(int pressure) {
    double percentage;

    // Рассчитываем процент для нижнего диапазона
    if (pressure < lowerPressureThreshold) {
      percentage = (pressure / lowerPressureThreshold) * 100;

      if (percentage <= 90) {
        // Менее 90% от нижнего порога — красный
        return Colors.red;
      } else if (percentage > 90 && percentage <= 100) {
        // 90%-100% — переход от красного к оранжевому
        return Color.lerp(Colors.red, Colors.orange, (percentage - 90) / 10)!;
      }
    }

    // Рассчитываем процент для диапазона между нижним и верхним порогом
    if (pressure >= lowerPressureThreshold &&
        pressure <= upperPressureThreshold) {
      percentage = ((pressure - lowerPressureThreshold) /
              (upperPressureThreshold - lowerPressureThreshold)) *
          100;

      if (percentage <= 50) {
        // Нижняя часть диапазона (переход от оранжевого к зелёному)
        return Color.lerp(Colors.orange, Colors.green, percentage / 50)!;
      } else {
        // Верхняя часть диапазона (переход от зелёного к жёлтому)
        return Color.lerp(Colors.green, Colors.yellow, (percentage - 50) / 50)!;
      }
    }

    // Рассчитываем процент для верхнего диапазона
    if (pressure > upperPressureThreshold) {
      percentage = ((pressure - upperPressureThreshold) /
              (upperPressureThreshold + 20 - upperPressureThreshold)) *
          100;

      if (percentage <= 10) {
        // 100%-110% — переход от жёлтого к оранжевому
        return Color.lerp(Colors.yellow, Colors.orange, percentage / 10)!;
      } else if (percentage > 10 && percentage <= 20) {
        // 110%-120% — переход от оранжевого к красному
        return Color.lerp(Colors.orange, Colors.red, (percentage - 10) / 10)!;
      } else {
        // Более 120% — красный
        return Colors.red;
      }
    }

    return Colors.green; // По умолчанию, если в нормальном диапазоне
  }

  void checkDeviceStatus() {
    if (pressureValue < lowerPressureThreshold || pressureValue > upperPressureThreshold) {
      sendNotification("Warning", "Pressure out of range: $pressureValue");
    }

    if (batteryValue < 20) {
      sendNotification("Battery Low", "Battery level is critically low: $batteryValue%");
    }

  }

  void sendNotification(String title, String body) async {
    FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
    FlutterLocalNotificationsPlugin();

    var androidDetails = AndroidNotificationDetails(
      'channelId',
      'channelName',
      channelDescription: 'channelDescription',
      importance: Importance.high,
    );

    var generalNotificationDetails =
    NotificationDetails(android: androidDetails);

    await flutterLocalNotificationsPlugin.show(
        0, title, body, generalNotificationDetails);
  }

  void _savePressureToDatabase(int pressure, DateTime time) async {
    await dbHelper.insertPressureData({
      'pressure': pressure,
      'timestamp': time.toIso8601String(),
    });
  }

  double _getPressurePercentage(int pressure) {
    if (pressure <= lowerPressureThreshold) {
      return 0.0;
    } else if (pressure >= upperPressureThreshold) {
      return 1.0;
    } else {
      return (pressure - lowerPressureThreshold) /
          (upperPressureThreshold - lowerPressureThreshold);
    }
  }

  Future<void> _disconnectDevice() async {
    // Устанавливаем состояние подключения на false
    setState(() {
      isConnected = false;
    });

    // Удаляем сохраненное устройство
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.remove('selectedDeviceId');

    _sendModeCommandWithResponse("sleep");

    // Отключаемся от устройства
    flutterReactiveBle.deinitialize();

    // Переходим на первый экран, заменяя текущий экран
    Navigator.pushReplacement(
      context,
      MaterialPageRoute(builder: (context) => BleConnectPage()),
    );
  }

  Future<bool> _sendModeCommandWithResponse(String mode) async {
    if (characteristic != null) {
      setState(() {
        isLoading = true;
      });
      try {
        // Преобразуем строку команды в байты
        final modeData = mode.codeUnits;

        // Отправляем команду
        await flutterReactiveBle.writeCharacteristicWithoutResponse(
          characteristic!,
          value: modeData,
        );

        print("Команда '$mode' отправлена успешно.");

        // Ожидаем ответа в течение некоторого времени (например, 10 секунд)
        final timeout = Duration(seconds: 10);
        final startTime = DateTime.now();

        while (DateTime.now().difference(startTime) < timeout) {
          if (lastAnswer == "${mode}OK") {
            print("Ответ получен: $lastAnswer");
            currentMode = mode;
            setState(() {
              isLoading = false;
            });
            return true;
          }

          // Даем небольшой перерыв, чтобы не перегружать цикл
          await Future.delayed(Duration(milliseconds: 100));
        }

        // Время ожидания истекло, но ответ не получен
        print("Ответ не получен за отведенное время.");
        setState(() {
          isLoading = false;
        });
        return false;
      } catch (e) {
        print("Ошибка при отправке команды: $e");
        setState(() {
          isLoading = false;
        });
        return false;
      }
    } else {
      print("Команда не отправлена: characteristic не установлена.");
      return false;
    }
  }


  void _showSettingsDialog() {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        // Локальные переменные для хранения значений
        double tempLowerThreshold = lowerPressureThreshold;
        double tempUpperThreshold = upperPressureThreshold;

        return StatefulBuilder(
          builder: (context, setState) {
            return AlertDialog(
              backgroundColor: Colors.white,
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(20),
              ),
              title: Text(
                "Настройки порогов давления",
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                  fontSize: 20,
                  color: Color(0xFF3A7FE7),
                ),
              ),
              content: SingleChildScrollView(
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    // Нижний порог
                    Text(
                      "Нижний порог давления: ${tempLowerThreshold.toStringAsFixed(0)} г",
                      style: TextStyle(
                        fontSize: 16,
                        color: Colors.black54,
                      ),
                    ),
                    Slider(
                      value: tempLowerThreshold,
                      min: 1,
                      max: 1900,
                      divisions: 150,
                      activeColor: Color(0xFF3A7FE7),
                      inactiveColor: Colors.grey[300],
                      label: tempLowerThreshold.toStringAsFixed(0),
                      onChanged: (double value) {
                        setState(() {
                          tempLowerThreshold = value;
                        });
                      },
                    ),
                    SizedBox(height: 20),

                    // Верхний порог
                    Text(
                      "Верхний порог давления: ${tempUpperThreshold.toStringAsFixed(0)} г",
                      style: TextStyle(
                        fontSize: 16,
                        color: Colors.black54,
                      ),
                    ),
                    Slider(
                      value: tempUpperThreshold,
                      min: 100,
                      max: 2000,
                      divisions: 150,
                      activeColor: Color(0xFF3A7FE7),
                      inactiveColor: Colors.grey[300],
                      label: tempUpperThreshold.toStringAsFixed(0),
                      onChanged: (double value) {
                        setState(() {
                          tempUpperThreshold = value;
                        });
                      },
                    ),
                  ],
                ),
              ),
              actions: [
                ElevatedButton(
                  onPressed: () {
                    // Обновляем реальные значения при закрытии диалога
                    setState(() {
                      lowerPressureThreshold = tempLowerThreshold;
                      upperPressureThreshold = tempUpperThreshold;
                      _saveSettings();
                    });
                    Navigator.of(context).pop();
                  },
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Color(0xFF3A7FE7), // Цвет кнопки
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(12),
                    ),
                  ),
                  child: Text(
                    "Сохранить",
                    style: TextStyle(
                      color: Colors.white,
                    ),
                  ),
                ),
              ],
            );
          },
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Измерение давления"),
        actions: [
          IconButton(
            icon: Icon(Icons.settings, color: Colors.blueAccent),
            onPressed: _showSettingsDialog,
          ),
          IconButton(
            icon: Icon(Icons.power_settings_new, color: Colors.red),
            onPressed: _disconnectDevice,
          ),
        ],
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            // Статус подключения Bluetooth и заряд батареи
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Row(
                  children: [
                    Icon(
                      isConnected
                          ? Icons.bluetooth_connected
                          : Icons.bluetooth_disabled,
                      color: isConnected ? Colors.green : Colors.red,
                      size: 24,
                    ),
                    SizedBox(width: 8),
                    Text(
                      isConnected ? "Подключено" : "Отключено",
                      style: TextStyle(
                        color: isConnected ? Colors.blueAccent : Colors.red,
                        fontSize: 16,
                      ),
                    ),
                  ],
                ),
                Row(
                  children: [
                    Icon(
                      Icons.battery_full,
                      color: batteryValue > 50
                          ? Colors.green
                          : batteryValue > 20
                              ? Colors.orange
                              : Colors
                                  .red, // Цвет в зависимости от уровня заряда
                    ),
                    SizedBox(width: 8),
                    Text(
                      "${batteryValue}%",
                      style: TextStyle(
                        color: Colors.blueAccent,
                        fontSize: 16,
                      ),
                    ),
                  ],
                ),
              ],
            ),
            SizedBox(height: 40),
            Center(
              child: Stack(
                alignment: Alignment.center,
                children: [
                  Container(
                    width: 250,
                    height: 250,
                    decoration: BoxDecoration(
                      shape: BoxShape.circle,
                      color: Colors.white,
                      gradient: LinearGradient(
                        begin: Alignment.topLeft,
                        end: Alignment.bottomRight,
                        colors: [Color(0xFF3A7FE7), Color(0xFF34CAEB)],
                      ),
                      boxShadow: [
                        BoxShadow(
                          color: Colors.grey.withOpacity(0.4),
                          spreadRadius: 6,
                          blurRadius: 15,
                        ),
                      ],
                    ),
                  ),
                  // Окружающий контейнер для размера индикатора
                  SizedBox(
                    width: 280, // Ширина, как и раньше
                    height: 280, // Высота, как и раньше
                    child: TweenAnimationBuilder<double>(
                      tween: Tween<double>(
                        begin: 0.0,
                        end: _getPressurePercentage(pressureValue),
                      ),
                      duration: Duration(milliseconds: 500),
                      builder: (context, value, child) {
                        return CircularProgressIndicator(
                          value: value, // плавно изменяющийся процент
                          strokeWidth: 15, // Ширина линии индикатора
                          valueColor: AlwaysStoppedAnimation<Color>(
                              _getPressureColor(pressureValue)),
                          backgroundColor: Colors.white, // Фон индикатора
                        );
                      },
                    ),
                  ),
                  Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Text(
                        "$pressureValue",
                        style: TextStyle(
                          fontSize: 36,
                          fontWeight: FontWeight.bold,
                          color: Colors.white,
                        ),
                      ),
                      Text(
                        "грамм",
                        style: TextStyle(
                          fontSize: 18,
                          color: Colors.white,
                        ),
                      ),
                      SizedBox(height: 10),
                      Text(
                        _formatDate(lastMeasurementTime),
                        style: TextStyle(
                          fontSize: 14,
                          color: Colors.white,
                        ),
                      ),
                      Text(
                        _formatTime(lastMeasurementTime),
                        style: TextStyle(
                          fontSize: 14,
                          color: Colors.white,
                        ),
                      ),
                    ],
                  ),
                ],
              ),
            ),
            SizedBox(height: 40),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                IconButton(
                  icon: Icon(Icons.show_chart, color: Colors.blueAccent),
                  onPressed: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => PressureGraphPage()),
                    );
                  },
                ),
                Text("Графики", style: TextStyle(fontSize: 16)),
              ],
            ),
            SizedBox(height: 40),
            // Переключатель режима
            ToggleButtons(
              borderColor: Colors.grey,
              selectedBorderColor: Color(0xFF3A7FE7),
              fillColor: Color(0xFF3A7FE7),
              selectedColor: Colors.white,
              color: Colors.black,
              borderRadius: BorderRadius.circular(10.0),
              children: [
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 16.0),
                  child: Text("Стоп"),
                ),
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 16.0),
                  child: Text("Затягивание"),
                ),
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 16.0),
                  child: Text("Ношение"),
                ),
              ],
              onPressed: isConnected
                  ? (int index) async {
                      String command;
                      if (index == 0)
                        command = "stop";
                      else if (index == 1)
                        command = "start";
                      else
                        command = "work";

                      // Отправляем команду и ждём ответ
                      bool result = await _sendModeCommandWithResponse(command);

                      if (result) {
                        setState(() {
                          selectedMode = index;
                          _saveSettings(); // Сохраняем выбранный режим
                        });
                      } else {
                        print("Не удалось переключить режим");
                      }
                    }
                  : null,
              // Если isConnecting == false, кнопки не будут нажимаемыми
              isSelected: [
                selectedMode == 0,
                selectedMode == 1,
                selectedMode == 2,
              ],
            ),

            SizedBox(height: 40),
            if (isLoading) CircularProgressIndicator(),
          ],
        ),
      ),
    );
  }
}

Assistant: