From 95fdbe4079e62c2961d8549e7de6b51eacdbd00a Mon Sep 17 00:00:00 2001 From: ivan2282 Date: Mon, 17 Nov 2025 21:59:37 +0300 Subject: [PATCH] =?UTF-8?q?=D1=8B=D1=8B=D0=B2=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/api_service_simple.dart | 774 ------------------------------------ lib/example_usage.dart | 264 ------------ 2 files changed, 1038 deletions(-) delete mode 100644 lib/api_service_simple.dart delete mode 100644 lib/example_usage.dart diff --git a/lib/api_service_simple.dart b/lib/api_service_simple.dart deleted file mode 100644 index d6aa10c..0000000 --- a/lib/api_service_simple.dart +++ /dev/null @@ -1,774 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:http/http.dart' as http; -import 'package:image_picker/image_picker.dart'; - -import 'connection/connection_manager_simple.dart'; -import 'connection/connection_logger.dart'; -import 'connection/connection_state.dart'; -import 'connection/health_monitor.dart'; -import 'models/message.dart'; -import 'models/contact.dart'; - - -class ApiServiceSimple { - ApiServiceSimple._privateConstructor(); - static final ApiServiceSimple instance = - ApiServiceSimple._privateConstructor(); - - - final ConnectionManagerSimple _connectionManager = ConnectionManagerSimple(); - - - final ConnectionLogger _logger = ConnectionLogger(); - - - String? _authToken; - bool _isInitialized = false; - - - final Map> _messageCache = {}; - final Map _contactCache = {}; - Map? _lastChatsPayload; - DateTime? _lastChatsAt; - final Duration _chatsCacheTtl = const Duration(seconds: 5); - bool _chatsFetchedInThisSession = false; - - - final Map _presenceData = {}; - - - final StreamController _contactUpdatesController = - StreamController.broadcast(); - final StreamController> _messageController = - StreamController>.broadcast(); - - - Stream> get messages => _messageController.stream; - - - Stream get contactUpdates => _contactUpdatesController.stream; - - - Stream get connectionState => _connectionManager.stateStream; - - - Stream get logs => _connectionManager.logStream; - - - Stream get healthMetrics => - _connectionManager.healthMetricsStream; - - - ConnectionInfo get currentState => _connectionManager.currentState; - - - bool get isOnline => _connectionManager.isConnected; - - - bool get canSendMessages => _connectionManager.canSendMessages; - - - Future initialize() async { - if (_isInitialized) { - _logger.logConnection('ApiServiceSimple уже инициализирован'); - return; - } - - _logger.logConnection('Инициализация ApiServiceSimple'); - - try { - await _connectionManager.initialize(); - _setupMessageHandlers(); - _isInitialized = true; - - _logger.logConnection('ApiServiceSimple успешно инициализирован'); - } catch (e) { - _logger.logError('Ошибка инициализации ApiServiceSimple', error: e); - rethrow; - } - } - - - void _setupMessageHandlers() { - _connectionManager.messageStream.listen((message) { - _handleIncomingMessage(message); - }); - } - - - void _handleIncomingMessage(Map message) { - try { - _logger.logMessage('IN', message); - - - if (message['opcode'] == 128 && message['payload'] != null) { - _handleContactUpdate(message['payload']); - } - - - if (message['opcode'] == 129 && message['payload'] != null) { - _handlePresenceUpdate(message['payload']); - } - - - _messageController.add(message); - } catch (e) { - _logger.logError( - 'Ошибка обработки входящего сообщения', - data: {'message': message, 'error': e.toString()}, - ); - } - } - - - void _handleContactUpdate(Map payload) { - try { - final contact = Contact.fromJson(payload); - _contactCache[contact.id] = contact; - _contactUpdatesController.add(contact); - - _logger.logConnection( - 'Контакт обновлен', - data: {'contact_id': contact.id, 'contact_name': contact.name}, - ); - } catch (e) { - _logger.logError( - 'Ошибка обработки обновления контакта', - data: {'payload': payload, 'error': e.toString()}, - ); - } - } - - - void _handlePresenceUpdate(Map payload) { - try { - _presenceData.addAll(payload); - _logger.logConnection( - 'Presence данные обновлены', - data: {'keys': payload.keys.toList()}, - ); - } catch (e) { - _logger.logError( - 'Ошибка обработки presence данных', - data: {'payload': payload, 'error': e.toString()}, - ); - } - } - - - Future connect() async { - _logger.logConnection('Запрос подключения к серверу'); - - try { - await _connectionManager.connect(authToken: _authToken); - _logger.logConnection('Подключение к серверу успешно'); - } catch (e) { - _logger.logError('Ошибка подключения к серверу', error: e); - rethrow; - } - } - - - Future reconnect() async { - _logger.logConnection('Запрос переподключения'); - - try { - await _connectionManager.connect(authToken: _authToken); - _logger.logConnection('Переподключение успешно'); - } catch (e) { - _logger.logError('Ошибка переподключения', error: e); - rethrow; - } - } - - - Future disconnect() async { - _logger.logConnection('Отключение от сервера'); - - try { - await _connectionManager.disconnect(); - _logger.logConnection('Отключение от сервера успешно'); - } catch (e) { - _logger.logError('Ошибка отключения', error: e); - } - } - - - int _sendMessage(int opcode, Map payload) { - if (!canSendMessages) { - _logger.logConnection( - 'Сообщение не отправлено - соединение не готово', - data: {'opcode': opcode, 'payload': payload}, - ); - return -1; - } - - try { - final seq = _connectionManager.sendMessage(opcode, payload); - _logger.logConnection( - 'Сообщение отправлено', - data: {'opcode': opcode, 'seq': seq, 'payload': payload}, - ); - return seq; - } catch (e) { - _logger.logError( - 'Ошибка отправки сообщения', - data: {'opcode': opcode, 'payload': payload, 'error': e.toString()}, - ); - return -1; - } - } - - - Future sendHandshake() async { - _logger.logConnection('Отправка handshake'); - - final payload = { - "userAgent": { - "deviceType": "WEB", - "locale": "ru", - "deviceLocale": "ru", - "osVersion": "Windows", - "deviceName": "Chrome", - "headerUserAgent": - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", - "appVersion": "25.9.15", - "screen": "1920x1080 1.0x", - "timezone": "Europe/Moscow", - }, - "deviceId": _generateDeviceId(), - }; - - _sendMessage(6, payload); - } - - - void requestOtp(String phoneNumber) { - _logger.logConnection('Запрос OTP', data: {'phone': phoneNumber}); - - final payload = { - "phone": phoneNumber, - "type": "START_AUTH", - "language": "ru", - }; - _sendMessage(17, payload); - } - - - void verifyCode(String token, String code) { - _logger.logConnection( - 'Проверка кода', - data: {'token': token, 'code': code}, - ); - - final payload = { - "token": token, - "verifyCode": code, - "authTokenType": "CHECK_CODE", - }; - _sendMessage(18, payload); - } - - - Future> authenticateWithToken(String token) async { - _logger.logConnection('Аутентификация с токеном'); - - _authToken = token; - await saveToken(token); - - final payload = {"interactive": true, "token": token, "chatsCount": 100}; - - final seq = _sendMessage(19, payload); - - try { - final response = await messages - .firstWhere((msg) => msg['seq'] == seq) - .timeout(const Duration(seconds: 30)); - - _logger.logConnection( - 'Аутентификация успешна', - data: {'seq': seq, 'response_cmd': response['cmd']}, - ); - - return response['payload'] ?? {}; - } catch (e) { - _logger.logError( - 'Ошибка аутентификации', - data: {'token': token, 'error': e.toString()}, - ); - rethrow; - } - } - - - Future> getChatsAndContacts({bool force = false}) async { - _logger.logConnection('Запрос чатов и контактов', data: {'force': force}); - - - if (!force && _lastChatsPayload != null && _lastChatsAt != null) { - if (DateTime.now().difference(_lastChatsAt!) < _chatsCacheTtl) { - _logger.logConnection('Возвращаем данные из кэша'); - return _lastChatsPayload!; - } - } - - try { - final payload = {"chatsCount": 100}; - final seq = _sendMessage(48, payload); - - final response = await messages - .firstWhere((msg) => msg['seq'] == seq) - .timeout(const Duration(seconds: 30)); - - final List chatListJson = response['payload']?['chats'] ?? []; - - if (chatListJson.isEmpty) { - final result = {'chats': [], 'contacts': [], 'profile': null}; - _lastChatsPayload = result; - _lastChatsAt = DateTime.now(); - return result; - } - - - final contactIds = {}; - for (var chatJson in chatListJson) { - final participants = - chatJson['participants'] as Map? ?? {}; - contactIds.addAll(participants.keys.map((id) => int.parse(id))); - } - - final contactSeq = _sendMessage(32, {"contactIds": contactIds.toList()}); - - final contactResponse = await messages - .firstWhere((msg) => msg['seq'] == contactSeq) - .timeout(const Duration(seconds: 30)); - - final List contactListJson = - contactResponse['payload']?['contacts'] ?? []; - - final result = { - 'chats': chatListJson, - 'contacts': contactListJson, - 'profile': null, - 'presence': null, - }; - - _lastChatsPayload = result; - _lastChatsAt = DateTime.now(); - _chatsFetchedInThisSession = true; - - - final contacts = contactListJson - .map((json) => Contact.fromJson(json)) - .toList(); - updateContactCache(contacts); - - _logger.logConnection( - 'Чаты и контакты получены', - data: { - 'chats_count': chatListJson.length, - 'contacts_count': contactListJson.length, - }, - ); - - return result; - } catch (e) { - _logger.logError('Ошибка получения чатов и контактов', error: e); - rethrow; - } - } - - - Future> getMessageHistory( - int chatId, { - bool force = false, - }) async { - _logger.logConnection( - 'Запрос истории сообщений', - data: {'chat_id': chatId, 'force': force}, - ); - - if (!force && _messageCache.containsKey(chatId)) { - _logger.logConnection('История сообщений загружена из кэша'); - return _messageCache[chatId]!; - } - - try { - final payload = { - "chatId": chatId, - "from": DateTime.now() - .add(const Duration(days: 1)) - .millisecondsSinceEpoch, - "forward": 0, - "backward": 1000, - "getMessages": true, - }; - - final seq = _sendMessage(49, payload); - - final response = await messages - .firstWhere((msg) => msg['seq'] == seq) - .timeout(const Duration(seconds: 30)); - - if (response['cmd'] == 3) { - final error = response['payload']; - _logger.logError( - 'Ошибка получения истории сообщений', - data: {'chat_id': chatId, 'error': error}, - ); - throw Exception('Ошибка получения истории: ${error['message']}'); - } - - final List messagesJson = response['payload']?['messages'] ?? []; - final messagesList = - messagesJson.map((json) => Message.fromJson(json)).toList() - ..sort((a, b) => a.time.compareTo(b.time)); - - _messageCache[chatId] = messagesList; - - _logger.logConnection( - 'История сообщений получена', - data: {'chat_id': chatId, 'messages_count': messagesList.length}, - ); - - return messagesList; - } catch (e) { - _logger.logError( - 'Ошибка получения истории сообщений', - data: {'chat_id': chatId, 'error': e.toString()}, - ); - return []; - } - } - - - void sendMessage(int chatId, String text, {String? replyToMessageId}) { - _logger.logConnection( - 'Отправка сообщения', - data: { - 'chat_id': chatId, - 'text_length': text.length, - 'reply_to': replyToMessageId, - }, - ); - - final int clientMessageId = DateTime.now().millisecondsSinceEpoch; - final payload = { - "chatId": chatId, - "message": { - "text": text, - "cid": clientMessageId, - "elements": [], - "attaches": [], - if (replyToMessageId != null) - "link": {"type": "REPLY", "messageId": replyToMessageId}, - }, - "notify": true, - }; - - clearChatsCache(); - _sendMessage(64, payload); - } - - - Future sendPhotoMessage( - int chatId, { - String? localPath, - String? caption, - int? cidOverride, - int? senderId, - }) async { - _logger.logConnection( - 'Отправка фото', - data: {'chat_id': chatId, 'local_path': localPath, 'caption': caption}, - ); - - try { - XFile? image; - if (localPath != null) { - image = XFile(localPath); - } else { - final picker = ImagePicker(); - image = await picker.pickImage(source: ImageSource.gallery); - if (image == null) return; - } - - - final seq80 = _sendMessage(80, {"count": 1}); - final resp80 = await messages - .firstWhere((m) => m['seq'] == seq80) - .timeout(const Duration(seconds: 30)); - - final String uploadUrl = resp80['payload']['url']; - - - var request = http.MultipartRequest('POST', Uri.parse(uploadUrl)); - request.files.add(await http.MultipartFile.fromPath('file', image.path)); - var streamed = await request.send(); - var httpResp = await http.Response.fromStream(streamed); - - if (httpResp.statusCode != 200) { - throw Exception( - 'Ошибка загрузки фото: ${httpResp.statusCode} ${httpResp.body}', - ); - } - - final uploadJson = jsonDecode(httpResp.body) as Map; - final Map photos = uploadJson['photos'] as Map; - if (photos.isEmpty) throw Exception('Не получен токен фото'); - final String photoToken = (photos.values.first as Map)['token']; - - - final int cid = cidOverride ?? DateTime.now().millisecondsSinceEpoch; - final payload = { - "chatId": chatId, - "message": { - "text": caption?.trim() ?? "", - "cid": cid, - "elements": [], - "attaches": [ - {"_type": "PHOTO", "photoToken": photoToken}, - ], - }, - "notify": true, - }; - - clearChatsCache(); - _sendMessage(64, payload); - - _logger.logConnection( - 'Фото отправлено', - data: {'chat_id': chatId, 'photo_token': photoToken}, - ); - } catch (e) { - _logger.logError( - 'Ошибка отправки фото', - data: {'chat_id': chatId, 'error': e.toString()}, - ); - } - } - - - Future blockContact(int contactId) async { - _logger.logConnection( - 'Блокировка контакта', - data: {'contact_id': contactId}, - ); - _sendMessage(34, {'contactId': contactId, 'action': 'BLOCK'}); - } - - - Future unblockContact(int contactId) async { - _logger.logConnection( - 'Разблокировка контакта', - data: {'contact_id': contactId}, - ); - _sendMessage(34, {'contactId': contactId, 'action': 'UNBLOCK'}); - } - - - void getBlockedContacts() { - _logger.logConnection('Запрос заблокированных контактов'); - _sendMessage(36, {'status': 'BLOCKED', 'count': 100, 'from': 0}); - } - - - void createGroup(String name, List participantIds) { - _logger.logConnection( - 'Создание группы', - data: {'name': name, 'participants': participantIds}, - ); - - final payload = {"name": name, "participantIds": participantIds}; - _sendMessage(48, payload); - } - - - void addGroupMember( - int chatId, - List userIds, { - bool showHistory = true, - }) { - _logger.logConnection( - 'Добавление участника в группу', - data: {'chat_id': chatId, 'user_ids': userIds}, - ); - - final payload = { - "chatId": chatId, - "userIds": userIds, - "showHistory": showHistory, - "operation": "add", - }; - _sendMessage(77, payload); - } - - - void removeGroupMember( - int chatId, - List userIds, { - int cleanMsgPeriod = 0, - }) { - _logger.logConnection( - 'Удаление участника из группы', - data: {'chat_id': chatId, 'user_ids': userIds}, - ); - - final payload = { - "chatId": chatId, - "userIds": userIds, - "operation": "remove", - "cleanMsgPeriod": cleanMsgPeriod, - }; - _sendMessage(77, payload); - } - - - void leaveGroup(int chatId) { - _logger.logConnection('Выход из группы', data: {'chat_id': chatId}); - _sendMessage(58, {"chatId": chatId}); - } - - - void sendReaction(int chatId, String messageId, String emoji) { - _logger.logConnection( - 'Отправка реакции', - data: {'chat_id': chatId, 'message_id': messageId, 'emoji': emoji}, - ); - - final payload = { - "chatId": chatId, - "messageId": messageId, - "reaction": {"reactionType": "EMOJI", "id": emoji}, - }; - _sendMessage(178, payload); - } - - - void removeReaction(int chatId, String messageId) { - _logger.logConnection( - 'Удаление реакции', - data: {'chat_id': chatId, 'message_id': messageId}, - ); - - final payload = {"chatId": chatId, "messageId": messageId}; - _sendMessage(179, payload); - } - - - void sendTyping(int chatId, {String type = "TEXT"}) { - final payload = {"chatId": chatId, "type": type}; - _sendMessage(65, payload); - } - - - DateTime? getLastSeen(int userId) { - final userPresence = _presenceData[userId.toString()]; - if (userPresence != null && userPresence['seen'] != null) { - final seenTimestamp = userPresence['seen'] as int; - return DateTime.fromMillisecondsSinceEpoch(seenTimestamp * 1000); - } - return null; - } - - - void updateContactCache(List contacts) { - _contactCache.clear(); - for (final contact in contacts) { - _contactCache[contact.id] = contact; - } - _logger.logConnection( - 'Кэш контактов обновлен', - data: {'contacts_count': contacts.length}, - ); - } - - - Contact? getCachedContact(int contactId) { - return _contactCache[contactId]; - } - - - void clearChatsCache() { - _lastChatsPayload = null; - _lastChatsAt = null; - _chatsFetchedInThisSession = false; - _logger.logConnection('Кэш чатов очищен'); - } - - - void clearMessageCache(int chatId) { - _messageCache.remove(chatId); - _logger.logConnection('Кэш сообщений очищен', data: {'chat_id': chatId}); - } - - - void clearAllCaches() { - _messageCache.clear(); - _contactCache.clear(); - clearChatsCache(); - _logger.logConnection('Все кэши очищены'); - } - - - Future saveToken(String token) async { - _authToken = token; - final prefs = await SharedPreferences.getInstance(); - await prefs.setString('authToken', token); - _logger.logConnection('Токен сохранен'); - } - - - Future hasToken() async { - final prefs = await SharedPreferences.getInstance(); - _authToken = prefs.getString('authToken'); - return _authToken != null; - } - - - Future logout() async { - _logger.logConnection('Выход из системы'); - - try { - final prefs = await SharedPreferences.getInstance(); - await prefs.remove('authToken'); - _authToken = null; - clearAllCaches(); - await disconnect(); - _logger.logConnection('Выход из системы выполнен'); - } catch (e) { - _logger.logError('Ошибка при выходе из системы', error: e); - } - } - - - String _generateDeviceId() { - final timestamp = DateTime.now().millisecondsSinceEpoch; - final random = (timestamp % 1000000).toString().padLeft(6, '0'); - return "$timestamp$random"; - } - - - Map getStatistics() { - return { - 'api_service': { - 'is_initialized': _isInitialized, - 'has_auth_token': _authToken != null, - 'message_cache_size': _messageCache.length, - 'contact_cache_size': _contactCache.length, - 'chats_fetched_in_session': _chatsFetchedInThisSession, - }, - 'connection': _connectionManager.getStatistics(), - }; - } - - - void dispose() { - _logger.logConnection('Освобождение ресурсов ApiServiceSimple'); - _connectionManager.dispose(); - _messageController.close(); - _contactUpdatesController.close(); - } -} diff --git a/lib/example_usage.dart b/lib/example_usage.dart deleted file mode 100644 index 0456d3a..0000000 --- a/lib/example_usage.dart +++ /dev/null @@ -1,264 +0,0 @@ -import 'package:flutter/material.dart'; -import 'api_service_simple.dart'; -import 'connection/connection_state.dart' as conn_state; - - -class ConnectionExample extends StatefulWidget { - const ConnectionExample({super.key}); - - @override - State createState() => _ConnectionExampleState(); -} - -class _ConnectionExampleState extends State { - final ApiServiceSimple _apiService = ApiServiceSimple.instance; - conn_state.ConnectionInfo? _currentState; - String _logs = ''; - - @override - void initState() { - super.initState(); - _initializeService(); - _setupListeners(); - } - - Future _initializeService() async { - try { - await _apiService.initialize(); - _addLog('✅ Сервис инициализирован'); - } catch (e) { - _addLog('❌ Ошибка инициализации: $e'); - } - } - - void _setupListeners() { - - _apiService.connectionState.listen((state) { - setState(() { - _currentState = state; - }); - _addLog('🔄 Состояние: ${_getStateText(state.state)}'); - }); - - - _apiService.logs.listen((log) { - _addLog('📝 ${log.toString()}'); - }); - - - _apiService.healthMetrics.listen((health) { - _addLog( - '🏥 Здоровье: ${health.healthScore}/100 (${health.quality.name})', - ); - }); - } - - void _addLog(String message) { - setState(() { - _logs += - '${DateTime.now().toIso8601String().substring(11, 23)} $message\n'; - }); - } - - String _getStateText(conn_state.ConnectionState state) { - switch (state) { - case conn_state.ConnectionState.disconnected: - return 'Отключен'; - case conn_state.ConnectionState.connecting: - return 'Подключение...'; - case conn_state.ConnectionState.connected: - return 'Подключен'; - case conn_state.ConnectionState.ready: - return 'Готов'; - case conn_state.ConnectionState.reconnecting: - return 'Переподключение...'; - case conn_state.ConnectionState.error: - return 'Ошибка'; - case conn_state.ConnectionState.disabled: - return 'Отключен'; - } - } - - Color _getStateColor(conn_state.ConnectionState state) { - switch (state) { - case conn_state.ConnectionState.ready: - return Colors.green; - case conn_state.ConnectionState.connected: - return Colors.blue; - case conn_state.ConnectionState.connecting: - case conn_state.ConnectionState.reconnecting: - return Colors.orange; - case conn_state.ConnectionState.error: - return Colors.red; - case conn_state.ConnectionState.disconnected: - case conn_state.ConnectionState.disabled: - return Colors.grey; - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Пример подключения'), - backgroundColor: _currentState != null - ? _getStateColor(_currentState!.state) - : Colors.grey, - ), - body: Column( - children: [ - - Container( - width: double.infinity, - padding: const EdgeInsets.all(16), - color: _currentState != null - ? _getStateColor(_currentState!.state).withOpacity(0.1) - : Colors.grey.withOpacity(0.1), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Статус: ${_currentState != null ? _getStateText(_currentState!.state) : 'Неизвестно'}', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - if (_currentState?.message != null) ...[ - const SizedBox(height: 4), - Text('Сообщение: ${_currentState!.message}'), - ], - if (_currentState?.serverUrl != null) ...[ - const SizedBox(height: 4), - Text('Сервер: ${_currentState!.serverUrl}'), - ], - if (_currentState?.latency != null) ...[ - const SizedBox(height: 4), - Text('Задержка: ${_currentState!.latency}ms'), - ], - ], - ), - ), - - - Padding( - padding: const EdgeInsets.all(16), - child: Wrap( - spacing: 8, - runSpacing: 8, - children: [ - ElevatedButton( - onPressed: _connect, - child: const Text('Подключиться'), - ), - ElevatedButton( - onPressed: _disconnect, - child: const Text('Отключиться'), - ), - ElevatedButton( - onPressed: _reconnect, - child: const Text('Переподключиться'), - ), - ElevatedButton( - onPressed: _clearLogs, - child: const Text('Очистить логи'), - ), - ElevatedButton( - onPressed: _showStats, - child: const Text('Статистика'), - ), - ], - ), - ), - - - Expanded( - child: Container( - margin: const EdgeInsets.all(16), - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.grey[100], - borderRadius: BorderRadius.circular(8), - border: Border.all(color: Colors.grey[300]!), - ), - child: SingleChildScrollView( - child: Text( - _logs.isEmpty ? 'Логи появятся здесь...' : _logs, - style: const TextStyle(fontFamily: 'monospace', fontSize: 12), - ), - ), - ), - ), - ], - ), - ); - } - - Future _connect() async { - try { - _addLog('🔄 Попытка подключения...'); - await _apiService.connect(); - _addLog('✅ Подключение успешно'); - } catch (e) { - _addLog('❌ Ошибка подключения: $e'); - } - } - - Future _disconnect() async { - try { - _addLog('🔄 Отключение...'); - await _apiService.disconnect(); - _addLog('✅ Отключение успешно'); - } catch (e) { - _addLog('❌ Ошибка отключения: $e'); - } - } - - Future _reconnect() async { - try { - _addLog('🔄 Переподключение...'); - await _apiService.reconnect(); - _addLog('✅ Переподключение успешно'); - } catch (e) { - _addLog('❌ Ошибка переподключения: $e'); - } - } - - void _clearLogs() { - setState(() { - _logs = ''; - }); - _addLog('🧹 Логи очищены'); - } - - void _showStats() { - final stats = _apiService.getStatistics(); - _addLog('📊 Статистика: ${stats.toString()}'); - - - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Статистика'), - content: SingleChildScrollView( - child: Text( - stats.toString(), - style: const TextStyle(fontFamily: 'monospace', fontSize: 12), - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.of(context).pop(), - child: const Text('Закрыть'), - ), - ], - ), - ); - } - - @override - void dispose() { - _apiService.dispose(); - super.dispose(); - } -}