Initial commit: Captain Claude Mobile App
- Flutter app with chat and terminal screens - WebSocket integration for real-time chat - xterm integration for screen sessions - Markdown rendering with code blocks - JWT authentication Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
145
lib/providers/chat_provider.dart
Normal file
145
lib/providers/chat_provider.dart
Normal file
@@ -0,0 +1,145 @@
|
||||
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<Message> _messages = [];
|
||||
|
||||
AuthProvider? _authProvider;
|
||||
StreamSubscription? _messageSubscription;
|
||||
StreamSubscription? _stateSubscription;
|
||||
|
||||
String? _currentConversationId;
|
||||
bool _isTyping = false;
|
||||
String _streamingContent = '';
|
||||
Message? _streamingMessage;
|
||||
|
||||
List<Message> 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<void> 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<String, dynamic> 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<String>? 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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user