yay ASv2 removed

This commit is contained in:
ivan2282
2025-11-19 19:19:28 +03:00
parent 575c43ce63
commit 3388b78f8c
6 changed files with 340 additions and 1087 deletions

View File

@@ -5,11 +5,18 @@ import 'dart:convert';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:gwid/connection/connection_logger.dart';
import 'package:gwid/connection/connection_state.dart' as conn_state;
import 'package:gwid/connection/health_monitor.dart';
import 'package:gwid/image_cache_service.dart';
import 'package:gwid/models/contact.dart'; import 'package:gwid/models/contact.dart';
import 'package:gwid/models/message.dart'; import 'package:gwid/models/message.dart';
import 'package:gwid/models/profile.dart'; import 'package:gwid/models/profile.dart';
import 'package:gwid/proxy_service.dart'; import 'package:gwid/proxy_service.dart';
import 'package:gwid/services/account_manager.dart'; import 'package:gwid/services/account_manager.dart';
import 'package:gwid/services/avatar_cache_service.dart';
import 'package:gwid/services/cache_service.dart';
import 'package:gwid/services/chat_cache_service.dart';
import 'package:gwid/spoofing_service.dart'; import 'package:gwid/spoofing_service.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
@@ -82,6 +89,18 @@ class ApiService {
minutes: 5, minutes: 5,
); );
final CacheService _cacheService = CacheService();
final AvatarCacheService _avatarCacheService = AvatarCacheService();
final ChatCacheService _chatCacheService = ChatCacheService();
bool _cacheServicesInitialized = false;
final ConnectionLogger _connectionLogger = ConnectionLogger();
final conn_state.ConnectionStateManager _connectionStateManager =
conn_state.ConnectionStateManager();
final HealthMonitor _healthMonitor = HealthMonitor();
String? _currentServerUrl;
bool _isLoadingBlockedContacts = false; bool _isLoadingBlockedContacts = false;
bool _isSessionReady = false; bool _isSessionReady = false;
@@ -95,6 +114,13 @@ class ApiService {
final _connectionLogController = StreamController<String>.broadcast(); final _connectionLogController = StreamController<String>.broadcast();
Stream<String> get connectionLog => _connectionLogController.stream; Stream<String> get connectionLog => _connectionLogController.stream;
List<LogEntry> get logs => _connectionLogger.logs;
Stream<conn_state.ConnectionInfo> get connectionState =>
_connectionStateManager.stateStream;
Stream<HealthMetrics> get healthMetrics => _healthMonitor.metricsStream;
final List<String> _connectionLogCache = []; final List<String> _connectionLogCache = [];
List<String> get connectionLogCache => _connectionLogCache; List<String> get connectionLogCache => _connectionLogCache;
@@ -133,12 +159,23 @@ class ApiService {
Timer? _reconnectTimer; Timer? _reconnectTimer;
bool _isReconnecting = false; bool _isReconnecting = false;
void _log(String message) { void _log(
String message, {
LogLevel level = LogLevel.info,
String category = 'API',
Map<String, dynamic>? data,
}) {
print(message); print(message);
_connectionLogCache.add(message); _connectionLogCache.add(message);
if (!_connectionLogController.isClosed) { if (!_connectionLogController.isClosed) {
_connectionLogController.add(message); _connectionLogController.add(message);
} }
_connectionLogger.log(
message,
level: level,
category: category,
data: data,
);
} }
void _emitLocal(Map<String, dynamic> frame) { void _emitLocal(Map<String, dynamic> frame) {
@@ -204,6 +241,48 @@ class ApiService {
_isAppInForeground = isForeground; _isAppInForeground = isForeground;
} }
void _updateConnectionState(
conn_state.ConnectionState state, {
String? message,
int? attemptNumber,
Duration? reconnectDelay,
int? latency,
Map<String, dynamic>? metadata,
}) {
_connectionStateManager.setState(
state,
message: message,
attemptNumber: attemptNumber,
reconnectDelay: reconnectDelay,
serverUrl: _currentServerUrl,
latency: latency,
metadata: metadata,
);
}
void _startHealthMonitoring() {
_healthMonitor.startMonitoring(serverUrl: _currentServerUrl);
}
void _stopHealthMonitoring() {
_healthMonitor.stopMonitoring();
}
Future<void> initialize() async {
await _ensureCacheServicesInitialized();
}
Future<void> _ensureCacheServicesInitialized() async {
if (_cacheServicesInitialized) return;
await Future.wait([
_cacheService.initialize(),
_avatarCacheService.initialize(),
_chatCacheService.initialize(),
ImageCacheService.instance.initialize(),
]);
_cacheServicesInitialized = true;
}
Future<String?> getClipboardData() async { Future<String?> getClipboardData() async {
final data = await Clipboard.getData(Clipboard.kTextPlain); final data = await Clipboard.getData(Clipboard.kTextPlain);
return data?.text; return data?.text;

View File

@@ -105,6 +105,28 @@ extension ApiServiceChats on ApiService {
} }
} }
await _ensureCacheServicesInitialized();
if (!force && _lastChatsPayload == null) {
final cachedChats = await _chatCacheService.getCachedChats();
final cachedContacts = await _chatCacheService.getCachedContacts();
if (cachedChats != null &&
cachedContacts != null &&
cachedChats.isNotEmpty) {
final result = {
'chats': cachedChats,
'contacts': cachedContacts.map(_contactToMap).toList(),
'profile': null,
'presence': null,
};
_lastChatsPayload = result;
_lastChatsAt = DateTime.now();
updateContactCache(cachedContacts);
_preloadContactAvatars(cachedContacts);
return result;
}
}
try { try {
final payload = {"chatsCount": 100}; final payload = {"chatsCount": 100};
@@ -152,6 +174,13 @@ extension ApiServiceChats on ApiService {
contactListJson.map((json) => Contact.fromJson(json)).toList(); contactListJson.map((json) => Contact.fromJson(json)).toList();
updateContactCache(contacts); updateContactCache(contacts);
_lastChatsAt = DateTime.now(); _lastChatsAt = DateTime.now();
_preloadContactAvatars(contacts);
unawaited(
_chatCacheService.cacheChats(
chatListJson.cast<Map<String, dynamic>>(),
),
);
unawaited(_chatCacheService.cacheContacts(contacts));
return result; return result;
} catch (e) { } catch (e) {
print('Ошибка получения чатов: $e'); print('Ошибка получения чатов: $e');
@@ -167,12 +196,36 @@ extension ApiServiceChats on ApiService {
throw Exception("Auth token not found - please re-authenticate"); throw Exception("Auth token not found - please re-authenticate");
} }
await _ensureCacheServicesInitialized();
if (!force && _lastChatsPayload != null && _lastChatsAt != null) { if (!force && _lastChatsPayload != null && _lastChatsAt != null) {
if (DateTime.now().difference(_lastChatsAt!) < _chatsCacheTtl) { if (DateTime.now().difference(_lastChatsAt!) < _chatsCacheTtl) {
return _lastChatsPayload!; return _lastChatsPayload!;
} }
} }
if (!force &&
!_chatsFetchedInThisSession &&
_lastChatsPayload == null) {
final cachedChats = await _chatCacheService.getCachedChats();
final cachedContacts = await _chatCacheService.getCachedContacts();
if (cachedChats != null &&
cachedContacts != null &&
cachedChats.isNotEmpty) {
final cachedResult = {
'chats': cachedChats,
'contacts': cachedContacts.map(_contactToMap).toList(),
'profile': null,
'presence': null,
};
_lastChatsPayload = cachedResult;
_lastChatsAt = DateTime.now();
updateContactCache(cachedContacts);
_preloadContactAvatars(cachedContacts);
return cachedResult;
}
}
if (_chatsFetchedInThisSession && _lastChatsPayload != null && !force) { if (_chatsFetchedInThisSession && _lastChatsPayload != null && !force) {
return _lastChatsPayload!; return _lastChatsPayload!;
} }
@@ -232,6 +285,10 @@ extension ApiServiceChats on ApiService {
_isSessionReady = true; _isSessionReady = true;
_connectionStatusController.add("ready"); _connectionStatusController.add("ready");
_updateConnectionState(
conn_state.ConnectionState.ready,
message: 'Авторизация успешна',
);
final profile = chatResponse['payload']?['profile']; final profile = chatResponse['payload']?['profile'];
final contactProfile = profile?['contact']; final contactProfile = profile?['contact'];
@@ -340,6 +397,13 @@ extension ApiServiceChats on ApiService {
contactListJson.map((json) => Contact.fromJson(json)).toList(); contactListJson.map((json) => Contact.fromJson(json)).toList();
updateContactCache(contacts); updateContactCache(contacts);
_lastChatsAt = DateTime.now(); _lastChatsAt = DateTime.now();
_preloadContactAvatars(contacts);
unawaited(
_chatCacheService.cacheChats(
chatListJson.cast<Map<String, dynamic>>(),
),
);
unawaited(_chatCacheService.cacheContacts(contacts));
_chatsFetchedInThisSession = true; _chatsFetchedInThisSession = true;
_inflightChatsCompleter!.complete(result); _inflightChatsCompleter!.complete(result);
_inflightChatsCompleter = null; _inflightChatsCompleter = null;
@@ -389,11 +453,23 @@ extension ApiServiceChats on ApiService {
int chatId, { int chatId, {
bool force = false, bool force = false,
}) async { }) async {
await _ensureCacheServicesInitialized();
if (!force && _messageCache.containsKey(chatId)) { if (!force && _messageCache.containsKey(chatId)) {
print("Загружаем сообщения для чата $chatId из кэша."); print("Загружаем сообщения для чата $chatId из кэша.");
return _messageCache[chatId]!; return _messageCache[chatId]!;
} }
if (!force) {
final cachedMessages =
await _chatCacheService.getCachedChatMessages(chatId);
if (cachedMessages != null && cachedMessages.isNotEmpty) {
print("История сообщений для чата $chatId загружена из ChatCacheService.");
_messageCache[chatId] = cachedMessages;
return cachedMessages;
}
}
print("Запрашиваем историю для чата $chatId с сервера."); print("Запрашиваем историю для чата $chatId с сервера.");
final payload = { final payload = {
"chatId": chatId, "chatId": chatId,
@@ -433,6 +509,8 @@ extension ApiServiceChats on ApiService {
..sort((a, b) => a.time.compareTo(b.time)); ..sort((a, b) => a.time.compareTo(b.time));
_messageCache[chatId] = messagesList; _messageCache[chatId] = messagesList;
_preloadMessageImages(messagesList);
unawaited(_chatCacheService.cacheChatMessages(chatId, messagesList));
return messagesList; return messagesList;
} catch (e) { } catch (e) {
@@ -567,6 +645,9 @@ extension ApiServiceChats on ApiService {
void clearCacheForChat(int chatId) { void clearCacheForChat(int chatId) {
_messageCache.remove(chatId); _messageCache.remove(chatId);
if (_cacheServicesInitialized) {
unawaited(_chatCacheService.clearChatCache(chatId));
}
print("Кэш для чата $chatId очищен."); print("Кэш для чата $chatId очищен.");
} }
@@ -651,9 +732,85 @@ extension ApiServiceChats on ApiService {
clearChatsCache(); clearChatsCache();
_messageCache.clear(); _messageCache.clear();
clearPasswordAuthData(); clearPasswordAuthData();
if (_cacheServicesInitialized) {
unawaited(_cacheService.clear());
unawaited(_chatCacheService.clearAllChatCache());
unawaited(_avatarCacheService.clearAvatarCache());
unawaited(ImageCacheService.instance.clearCache());
}
print("Все кэши очищены из-за ошибки подключения."); print("Все кэши очищены из-за ошибки подключения.");
} }
Future<Map<String, dynamic>> getStatistics() async {
await _ensureCacheServicesInitialized();
final cacheStats = await _cacheService.getCacheStats();
final chatCacheStats = await _chatCacheService.getChatCacheStats();
final avatarStats = await _avatarCacheService.getAvatarCacheStats();
final imageStats = await ImageCacheService.instance.getCacheStats();
return {
'api_service': {
'is_online': _isSessionOnline,
'is_ready': _isSessionReady,
'cached_chats': (_lastChatsPayload?['chats'] as List?)?.length ?? 0,
'contacts_in_memory': _contactCache.length,
'message_cache_entries': _messageCache.length,
'message_queue_length': _messageQueue.length,
},
'connection': {
'current_url': _currentUrlIndex < _wsUrls.length
? _wsUrls[_currentUrlIndex]
: null,
'reconnect_attempts': _reconnectAttempts,
'last_action_time': _lastActionTime,
},
'cache_service': cacheStats,
'chat_cache': chatCacheStats,
'avatar_cache': avatarStats,
'image_cache': imageStats,
};
}
void _preloadContactAvatars(List<Contact> contacts) {
if (!_cacheServicesInitialized || contacts.isEmpty) return;
final photoUrls = contacts.map((c) => c.photoBaseUrl).toList();
if (photoUrls.isEmpty) return;
unawaited(ImageCacheService.instance.preloadContactAvatars(photoUrls));
}
void _preloadMessageImages(List<Message> messages) {
if (!_cacheServicesInitialized || messages.isEmpty) return;
final urls = <String>{};
for (final message in messages) {
for (final attach in message.attaches) {
final url = attach['url'] ?? attach['baseUrl'];
if (url is String && url.isNotEmpty) {
urls.add(url);
}
}
}
for (final url in urls) {
unawaited(ImageCacheService.instance.preloadImage(url));
}
}
Map<String, dynamic> _contactToMap(Contact contact) {
return {
'id': contact.id,
'name': contact.name,
'firstName': contact.firstName,
'lastName': contact.lastName,
'description': contact.description,
'photoBaseUrl': contact.photoBaseUrl,
'isBlocked': contact.isBlocked,
'isBlockedByMe': contact.isBlockedByMe,
'accountStatus': contact.accountStatus,
'status': contact.status,
'options': contact.options,
};
}
void sendMessage( void sendMessage(
int chatId, int chatId,
String text, { String text, {

View File

@@ -3,6 +3,10 @@ part of 'api_service.dart';
extension ApiServiceConnection on ApiService { extension ApiServiceConnection on ApiService {
Future<void> _connectWithFallback() async { Future<void> _connectWithFallback() async {
_log('Начало подключения...'); _log('Начало подключения...');
_updateConnectionState(
conn_state.ConnectionState.connecting,
message: 'Поиск доступного сервера',
);
while (_currentUrlIndex < _wsUrls.length) { while (_currentUrlIndex < _wsUrls.length) {
final currentUrl = _wsUrls[_currentUrlIndex]; final currentUrl = _wsUrls[_currentUrlIndex];
@@ -17,6 +21,11 @@ extension ApiServiceConnection on ApiService {
? 'Подключено к основному серверу' ? 'Подключено к основному серверу'
: 'Подключено через резервный сервер'; : 'Подключено через резервный сервер';
_connectionLogController.add('$successMessage'); _connectionLogController.add('$successMessage');
_updateConnectionState(
conn_state.ConnectionState.connecting,
message: 'Соединение установлено, ожидание handshake',
metadata: {'server': currentUrl},
);
if (_currentUrlIndex > 0) { if (_currentUrlIndex > 0) {
_connectionStatusController.add('Подключено через резервный сервер'); _connectionStatusController.add('Подключено через резервный сервер');
} }
@@ -25,6 +34,7 @@ extension ApiServiceConnection on ApiService {
final errorMessage = '❌ Ошибка: ${e.toString().split(':').first}'; final errorMessage = '❌ Ошибка: ${e.toString().split(':').first}';
print('Ошибка подключения к $currentUrl: $e'); print('Ошибка подключения к $currentUrl: $e');
_connectionLogController.add(errorMessage); _connectionLogController.add(errorMessage);
_healthMonitor.onError(errorMessage);
_currentUrlIndex++; _currentUrlIndex++;
if (_currentUrlIndex < _wsUrls.length) { if (_currentUrlIndex < _wsUrls.length) {
@@ -35,12 +45,18 @@ extension ApiServiceConnection on ApiService {
_log('Все серверы недоступны'); _log('Все серверы недоступны');
_connectionStatusController.add('Все серверы недоступны'); _connectionStatusController.add('Все серверы недоступны');
_updateConnectionState(
conn_state.ConnectionState.error,
message: 'Все серверы недоступны',
);
_stopHealthMonitoring();
throw Exception('Не удалось подключиться ни к одному серверу'); throw Exception('Не удалось подключиться ни к одному серверу');
} }
Future<void> _connectToUrl(String url) async { Future<void> _connectToUrl(String url) async {
_isSessionOnline = false; _isSessionOnline = false;
_onlineCompleter = Completer<void>(); _onlineCompleter = Completer<void>();
_currentServerUrl = url;
final bool hadChatsFetched = _chatsFetchedInThisSession; final bool hadChatsFetched = _chatsFetchedInThisSession;
final bool hasValidToken = authToken != null; final bool hasValidToken = authToken != null;
@@ -96,6 +112,11 @@ extension ApiServiceConnection on ApiService {
print("Сессия была завершена сервером"); print("Сессия была завершена сервером");
_isSessionOnline = false; _isSessionOnline = false;
_isSessionReady = false; _isSessionReady = false;
_stopHealthMonitoring();
_updateConnectionState(
conn_state.ConnectionState.disconnected,
message: 'Сессия завершена сервером',
);
authToken = null; authToken = null;
@@ -111,6 +132,12 @@ extension ApiServiceConnection on ApiService {
print("Обработка недействительного токена"); print("Обработка недействительного токена");
_isSessionOnline = false; _isSessionOnline = false;
_isSessionReady = false; _isSessionReady = false;
_stopHealthMonitoring();
_healthMonitor.onError('invalid_token');
_updateConnectionState(
conn_state.ConnectionState.error,
message: 'Недействительный токен',
);
authToken = null; authToken = null;
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
@@ -177,6 +204,10 @@ extension ApiServiceConnection on ApiService {
_isSessionReady = false; _isSessionReady = false;
_connectionStatusController.add("connecting"); _connectionStatusController.add("connecting");
_updateConnectionState(
conn_state.ConnectionState.connecting,
message: 'Инициализация подключения',
);
await _connectWithFallback(); await _connectWithFallback();
} }
@@ -273,6 +304,7 @@ extension ApiServiceConnection on ApiService {
try { try {
final decoded = jsonDecode(message) as Map<String, dynamic>; final decoded = jsonDecode(message) as Map<String, dynamic>;
if (decoded['opcode'] == 2) { if (decoded['opcode'] == 2) {
_healthMonitor.onPongReceived();
loggableMessage = '⬅️ RECV (pong) seq: ${decoded['seq']}'; loggableMessage = '⬅️ RECV (pong) seq: ${decoded['seq']}';
} else { } else {
Map<String, dynamic> loggableDecoded = Map.from(decoded); Map<String, dynamic> loggableDecoded = Map.from(decoded);
@@ -323,6 +355,11 @@ extension ApiServiceConnection on ApiService {
_isSessionReady = false; _isSessionReady = false;
_reconnectDelaySeconds = 2; _reconnectDelaySeconds = 2;
_connectionStatusController.add("authorizing"); _connectionStatusController.add("authorizing");
_updateConnectionState(
conn_state.ConnectionState.connected,
message: 'Handshake успешен',
);
_startHealthMonitoring();
if (_onlineCompleter != null && !_onlineCompleter!.isCompleted) { if (_onlineCompleter != null && !_onlineCompleter!.isCompleted) {
_onlineCompleter!.complete(); _onlineCompleter!.complete();
@@ -334,6 +371,11 @@ extension ApiServiceConnection on ApiService {
if (decodedMessage is Map && decodedMessage['cmd'] == 3) { if (decodedMessage is Map && decodedMessage['cmd'] == 3) {
final error = decodedMessage['payload']; final error = decodedMessage['payload'];
print('Ошибка сервера: $error'); print('Ошибка сервера: $error');
_healthMonitor.onError(error?['message'] ?? 'server_error');
_updateConnectionState(
conn_state.ConnectionState.error,
message: error?['message'],
);
if (error != null && error['localizedMessage'] != null) { if (error != null && error['localizedMessage'] != null) {
_errorController.add(error['localizedMessage']); _errorController.add(error['localizedMessage']);
@@ -557,12 +599,22 @@ extension ApiServiceConnection on ApiService {
print('Ошибка WebSocket: $error'); print('Ошибка WebSocket: $error');
_isSessionOnline = false; _isSessionOnline = false;
_isSessionReady = false; _isSessionReady = false;
_healthMonitor.onError(error.toString());
_updateConnectionState(
conn_state.ConnectionState.error,
message: error.toString(),
);
_reconnect(); _reconnect();
}, },
onDone: () { onDone: () {
print('WebSocket соединение закрыто. Попытка переподключения...'); print('WebSocket соединение закрыто. Попытка переподключения...');
_isSessionOnline = false; _isSessionOnline = false;
_isSessionReady = false; _isSessionReady = false;
_stopHealthMonitoring();
_updateConnectionState(
conn_state.ConnectionState.disconnected,
message: 'Соединение закрыто',
);
if (!_isSessionReady) { if (!_isSessionReady) {
_reconnect(); _reconnect();
@@ -577,6 +629,7 @@ extension ApiServiceConnection on ApiService {
_isReconnecting = true; _isReconnecting = true;
_reconnectAttempts++; _reconnectAttempts++;
_healthMonitor.onReconnect();
if (_reconnectAttempts > ApiService._maxReconnectAttempts) { if (_reconnectAttempts > ApiService._maxReconnectAttempts) {
print( print(
@@ -584,6 +637,10 @@ extension ApiServiceConnection on ApiService {
); );
_connectionStatusController.add("disconnected"); _connectionStatusController.add("disconnected");
_isReconnecting = false; _isReconnecting = false;
_updateConnectionState(
conn_state.ConnectionState.error,
message: 'Превышено число попыток переподключения',
);
return; return;
} }
@@ -607,6 +664,11 @@ extension ApiServiceConnection on ApiService {
"Переподключаемся после ${delay.inSeconds}s... (попытка $_reconnectAttempts/${ApiService._maxReconnectAttempts})", "Переподключаемся после ${delay.inSeconds}s... (попытка $_reconnectAttempts/${ApiService._maxReconnectAttempts})",
); );
_isReconnecting = false; _isReconnecting = false;
_updateConnectionState(
conn_state.ConnectionState.reconnecting,
attemptNumber: _reconnectAttempts,
reconnectDelay: delay,
);
_connectWithFallback(); _connectWithFallback();
}); });
} }
@@ -708,6 +770,11 @@ extension ApiServiceConnection on ApiService {
_handshakeSent = false; _handshakeSent = false;
_onlineCompleter = Completer<void>(); _onlineCompleter = Completer<void>();
_chatsFetchedInThisSession = false; _chatsFetchedInThisSession = false;
_stopHealthMonitoring();
_updateConnectionState(
conn_state.ConnectionState.disconnected,
message: 'Отключено пользователем',
);
_channel?.sink.close(status.goingAway); _channel?.sink.close(status.goingAway);
_channel = null; _channel = null;

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@ import 'dart:async';
import '../connection/connection_logger.dart'; import '../connection/connection_logger.dart';
import '../connection/connection_state.dart' as conn_state; import '../connection/connection_state.dart' as conn_state;
import '../connection/health_monitor.dart'; import '../connection/health_monitor.dart';
import '../api_service_v2.dart'; import 'package:gwid/api/api_service.dart';
class ConnectionDebugPanel extends StatefulWidget { class ConnectionDebugPanel extends StatefulWidget {
@@ -39,7 +39,7 @@ class _ConnectionDebugPanelState extends State<ConnectionDebugPanel>
void _setupSubscriptions() { void _setupSubscriptions() {
_logsSubscription = Stream.periodic(const Duration(seconds: 1)) _logsSubscription = Stream.periodic(const Duration(seconds: 1))
.asyncMap((_) async => ApiServiceV2.instance.logs.take(100).toList()) .asyncMap((_) async => ApiService.instance.logs.take(100).toList())
.listen((logs) { .listen((logs) {
if (mounted) { if (mounted) {
setState(() { setState(() {
@@ -49,7 +49,7 @@ class _ConnectionDebugPanelState extends State<ConnectionDebugPanel>
}); });
_stateSubscription = ApiServiceV2.instance.connectionState.listen((state) { _stateSubscription = ApiService.instance.connectionState.listen((state) {
if (mounted) { if (mounted) {
setState(() { setState(() {
_stateHistory.add(state); _stateHistory.add(state);
@@ -61,7 +61,7 @@ class _ConnectionDebugPanelState extends State<ConnectionDebugPanel>
}); });
_healthSubscription = ApiServiceV2.instance.healthMetrics.listen((health) { _healthSubscription = ApiService.instance.healthMetrics.listen((health) {
if (mounted) { if (mounted) {
setState(() { setState(() {
_healthMetrics.add(health); _healthMetrics.add(health);
@@ -93,7 +93,7 @@ class _ConnectionDebugPanelState extends State<ConnectionDebugPanel>
borderRadius: const BorderRadius.vertical(top: Radius.circular(16)), borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Colors.black.withOpacity(0.1), color: Colors.black.withValues(alpha: 0.1),
blurRadius: 10, blurRadius: 10,
offset: const Offset(0, -5), offset: const Offset(0, -5),
), ),
@@ -113,7 +113,7 @@ class _ConnectionDebugPanelState extends State<ConnectionDebugPanel>
return Container( return Container(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary.withOpacity(0.1), color: Theme.of(context).colorScheme.primary.withValues(alpha: 0.1),
borderRadius: const BorderRadius.vertical(top: Radius.circular(16)), borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
), ),
child: Row( child: Row(
@@ -223,10 +223,10 @@ class _ConnectionDebugPanelState extends State<ConnectionDebugPanel>
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: _getLogColor(log.level).withOpacity(0.1), color: _getLogColor(log.level).withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
border: Border.all( border: Border.all(
color: _getLogColor(log.level).withOpacity(0.3), color: _getLogColor(log.level).withValues(alpha: 0.3),
width: 1, width: 1,
), ),
), ),
@@ -297,10 +297,10 @@ class _ConnectionDebugPanelState extends State<ConnectionDebugPanel>
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: _getStateColor(state.state).withOpacity(0.1), color: _getStateColor(state.state).withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
border: Border.all( border: Border.all(
color: _getStateColor(state.state).withOpacity(0.3), color: _getStateColor(state.state).withValues(alpha: 0.3),
width: 1, width: 1,
), ),
), ),
@@ -372,10 +372,10 @@ class _ConnectionDebugPanelState extends State<ConnectionDebugPanel>
margin: const EdgeInsets.all(8), margin: const EdgeInsets.all(8),
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
decoration: BoxDecoration( decoration: BoxDecoration(
color: _getHealthColor(health.quality).withOpacity(0.1), color: _getHealthColor(health.quality).withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
border: Border.all( border: Border.all(
color: _getHealthColor(health.quality).withOpacity(0.3), color: _getHealthColor(health.quality).withValues(alpha: 0.3),
width: 1, width: 1,
), ),
), ),
@@ -444,7 +444,7 @@ class _ConnectionDebugPanelState extends State<ConnectionDebugPanel>
color: Theme.of(context).colorScheme.surface, color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
border: Border.all( border: Border.all(
color: Theme.of(context).colorScheme.outline.withOpacity(0.2), color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.2),
), ),
), ),
child: const Center( child: const Center(
@@ -455,7 +455,7 @@ class _ConnectionDebugPanelState extends State<ConnectionDebugPanel>
Widget _buildStatsTab() { Widget _buildStatsTab() {
return FutureBuilder<Map<String, dynamic>>( return FutureBuilder<Map<String, dynamic>>(
future: ApiServiceV2.instance future: ApiService.instance
.getStatistics(), // Указываем Future, который нужно ожидать .getStatistics(), // Указываем Future, который нужно ожидать
builder: (context, snapshot) { builder: (context, snapshot) {
@@ -667,7 +667,12 @@ class _ConnectionDebugPanelState extends State<ConnectionDebugPanel>
} }
void _clearLogs() { void _clearLogs() {
ConnectionLogger().clearLogs();
if (mounted) {
setState(() {
_logs = [];
});
}
} }
void _exportLogs() { void _exportLogs() {

View File

@@ -3,7 +3,9 @@ import 'dart:async';
import '../connection/connection_state.dart' as conn_state; import '../connection/connection_state.dart' as conn_state;
import '../connection/health_monitor.dart'; import '../connection/health_monitor.dart';
import '../api_service_v2.dart'; import 'package:gwid/api/api_service.dart';
class ConnectionStatusWidget extends StatefulWidget { class ConnectionStatusWidget extends StatefulWidget {
@@ -37,7 +39,7 @@ class _ConnectionStatusWidgetState extends State<ConnectionStatusWidget> {
} }
void _setupSubscriptions() { void _setupSubscriptions() {
_stateSubscription = ApiServiceV2.instance.connectionState.listen((state) { _stateSubscription = ApiService.instance.connectionState.listen((state) {
if (mounted) { if (mounted) {
setState(() { setState(() {
_currentState = state; _currentState = state;
@@ -46,7 +48,7 @@ class _ConnectionStatusWidgetState extends State<ConnectionStatusWidget> {
}); });
if (widget.showHealthMetrics) { if (widget.showHealthMetrics) {
_healthSubscription = ApiServiceV2.instance.healthMetrics.listen(( _healthSubscription = ApiService.instance.healthMetrics.listen((
health, health,
) { ) {
if (mounted) { if (mounted) {
@@ -77,10 +79,10 @@ class _ConnectionStatusWidgetState extends State<ConnectionStatusWidget> {
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: _getStatusColor().withOpacity(0.1), color: _getStatusColor().withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
border: Border.all( border: Border.all(
color: _getStatusColor().withOpacity(0.3), color: _getStatusColor().withValues(alpha: 0.3),
width: 1, width: 1,
), ),
), ),
@@ -125,7 +127,7 @@ class _ConnectionStatusWidgetState extends State<ConnectionStatusWidget> {
shape: BoxShape.circle, shape: BoxShape.circle,
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: _getStatusColor().withOpacity(0.5), color: _getStatusColor().withValues(alpha: 0.5),
blurRadius: 4, blurRadius: 4,
spreadRadius: 1, spreadRadius: 1,
), ),
@@ -177,7 +179,7 @@ class _ConnectionStatusWidgetState extends State<ConnectionStatusWidget> {
Text( Text(
'$label: ', '$label: ',
style: TextStyle( style: TextStyle(
color: _getStatusColor().withOpacity(0.7), color: _getStatusColor().withValues(alpha: 0.7),
fontSize: 10, fontSize: 10,
), ),
), ),
@@ -200,9 +202,9 @@ class _ConnectionStatusWidgetState extends State<ConnectionStatusWidget> {
return Container( return Container(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: _getHealthColor().withOpacity(0.1), color: _getHealthColor().withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
border: Border.all(color: _getHealthColor().withOpacity(0.3), width: 1), border: Border.all(color: _getHealthColor().withValues(alpha: 0.3), width: 1),
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -233,7 +235,7 @@ class _ConnectionStatusWidgetState extends State<ConnectionStatusWidget> {
return Container( return Container(
height: 4, height: 4,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.grey.withOpacity(0.2), color: Colors.grey.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(2), borderRadius: BorderRadius.circular(2),
), ),
child: FractionallySizedBox( child: FractionallySizedBox(
@@ -348,7 +350,7 @@ class _ConnectionIndicatorState extends State<ConnectionIndicator> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return StreamBuilder<conn_state.ConnectionInfo>( return StreamBuilder<conn_state.ConnectionInfo>(
stream: ApiServiceV2.instance.connectionState, stream: ApiService.instance.connectionState,
builder: (context, snapshot) { builder: (context, snapshot) {
if (!snapshot.hasData) { if (!snapshot.hasData) {
return SizedBox( return SizedBox(
@@ -382,11 +384,11 @@ class _ConnectionIndicatorState extends State<ConnectionIndicator> {
width: widget.size, width: widget.size,
height: widget.size, height: widget.size,
decoration: BoxDecoration( decoration: BoxDecoration(
color: color.withOpacity(0.3 + (0.7 * value)), color: color.withValues(alpha: 0.3 + (0.7 * value)),
shape: BoxShape.circle, shape: BoxShape.circle,
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: color.withOpacity(0.5 * value), color: color.withValues(alpha: 0.5 * value),
blurRadius: 8 * value, blurRadius: 8 * value,
spreadRadius: 2 * value, spreadRadius: 2 * value,
), ),
@@ -412,7 +414,7 @@ class _ConnectionIndicatorState extends State<ConnectionIndicator> {
shape: BoxShape.circle, shape: BoxShape.circle,
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: color.withOpacity(0.5), color: color.withValues(alpha: 0.5),
blurRadius: 4, blurRadius: 4,
spreadRadius: 1, spreadRadius: 1,
), ),