import 'dart:async'; import 'package:flutter/foundation.dart'; import '../models/message.dart'; import '../services/chat_service.dart'; import '../providers/auth_provider.dart'; class ChatProvider with ChangeNotifier { final ChatService _chatService = ChatService(); final List _messages = []; AuthProvider? _authProvider; StreamSubscription? _messageSubscription; StreamSubscription? _stateSubscription; String? _currentConversationId; bool _isTyping = false; String _streamingContent = ''; Message? _streamingMessage; List get messages => List.unmodifiable(_messages); bool get isTyping => _isTyping; bool get isConnected => _chatService.currentState == ChatConnectionState.connected; ChatConnectionState get connectionState => _chatService.currentState; String? get currentConversationId => _currentConversationId; void updateAuth(AuthProvider auth) { _authProvider = auth; _chatService.setToken(auth.token); if (auth.isAuthenticated && !isConnected) { connect(); } else if (!auth.isAuthenticated && isConnected) { disconnect(); } } Future connect() async { if (_authProvider?.token == null) return; _chatService.setToken(_authProvider!.token); _stateSubscription?.cancel(); _stateSubscription = _chatService.connectionState.listen((state) { notifyListeners(); }); _messageSubscription?.cancel(); _messageSubscription = _chatService.messages.listen(_handleMessage); await _chatService.connect(); } void _handleMessage(Map data) { final type = data['type']; switch (type) { case 'connected': notifyListeners(); break; case 'start': _currentConversationId = data['conversation_id']; _isTyping = true; _streamingContent = ''; _streamingMessage = Message( role: 'assistant', content: '', isStreaming: true, ); _messages.add(_streamingMessage!); notifyListeners(); break; case 'delta': _streamingContent += data['content'] ?? ''; if (_streamingMessage != null) { final index = _messages.indexOf(_streamingMessage!); if (index >= 0) { _messages[index] = _streamingMessage!.copyWith( content: _streamingContent, ); } } notifyListeners(); break; case 'done': _isTyping = false; if (_streamingMessage != null) { final index = _messages.indexOf(_streamingMessage!); if (index >= 0) { _messages[index] = _streamingMessage!.copyWith( content: data['content'] ?? _streamingContent, isStreaming: false, ); } } _streamingMessage = null; _streamingContent = ''; notifyListeners(); break; case 'error': _isTyping = false; _messages.add(Message( role: 'assistant', content: 'Error: ${data['message']}', )); notifyListeners(); break; } } void sendMessage(String content, {List? files}) { if (content.trim().isEmpty) return; _messages.add(Message( role: 'user', content: content, attachments: files, )); notifyListeners(); _chatService.sendMessage(content, files: files); } void clearMessages() { _messages.clear(); _currentConversationId = null; notifyListeners(); } void disconnect() { _chatService.disconnect(); _messageSubscription?.cancel(); _stateSubscription?.cancel(); } @override void dispose() { disconnect(); _chatService.dispose(); super.dispose(); } }