Change PIN to 1451

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
ARCHITECT
2026-01-17 23:31:52 +00:00
parent c152cacb90
commit f199daf4ba
171 changed files with 10492 additions and 2 deletions

View File

@@ -0,0 +1,52 @@
import 'package:flutter/foundation.dart';
import '../services/auth_service.dart';
class AuthProvider with ChangeNotifier {
final AuthService _authService = AuthService();
bool _isLoading = false;
String? _error;
bool get isLoading => _isLoading;
bool get isAuthenticated => _authService.isAuthenticated;
String? get token => _authService.token;
String? get username => _authService.username;
String? get error => _error;
Future<void> init() async {
_isLoading = true;
notifyListeners();
await _authService.loadStoredAuth();
_isLoading = false;
notifyListeners();
}
Future<bool> login(String username, String password) async {
_isLoading = true;
_error = null;
notifyListeners();
final success = await _authService.login(username, password);
if (!success) {
_error = _authService.lastError ?? 'Login failed';
}
_isLoading = false;
notifyListeners();
return success;
}
Future<void> logout() async {
await _authService.logout();
notifyListeners();
}
void clearError() {
_error = null;
notifyListeners();
}
}

View File

@@ -0,0 +1,295 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import '../models/message.dart';
import '../services/chat_service.dart';
import '../providers/auth_provider.dart';
/// Chat provider for v3 API (dynamic Claude sessions)
class ChatProvider with ChangeNotifier {
final ChatService _chatService = ChatService();
final List<Message> _messages = [];
static const int _maxMessages = 500;
AuthProvider? _authProvider;
StreamSubscription? _messageSubscription;
StreamSubscription? _stateSubscription;
StreamSubscription? _errorSubscription;
List<ChatSession> _sessions = [];
ChatSession? _currentSession;
bool _isProcessing = false;
String? _error;
List<Message> get messages => List.unmodifiable(_messages);
List<ChatSession> get sessions => List.unmodifiable(_sessions);
ChatSession? get currentSession => _currentSession;
bool get isProcessing => _isProcessing;
bool get isConnected => _chatService.currentState == ChatConnectionState.connected;
bool get isSessionConnected => _currentSession != null;
ChatConnectionState get connectionState => _chatService.currentState;
String? get error => _error;
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();
});
_errorSubscription?.cancel();
_errorSubscription = _chatService.errors.listen((error) {
_error = error;
notifyListeners();
});
_messageSubscription?.cancel();
_messageSubscription = _chatService.messages.listen(_handleMessage);
await _chatService.connect();
}
void _handleMessage(Map<String, dynamic> data) {
final type = data['type'];
debugPrint('ChatProvider: type=$type');
switch (type) {
// Initial state with sessions
case 'init':
final sessionsList = data['sessions'] as List<dynamic>?;
if (sessionsList != null) {
_sessions = sessionsList
.map((s) => ChatSession.fromJson(s))
.toList();
}
notifyListeners();
break;
// Sessions list update
case 'sessions_list':
final sessionsList = data['sessions'] as List<dynamic>?;
if (sessionsList != null) {
_sessions = sessionsList
.map((s) => ChatSession.fromJson(s))
.toList();
}
notifyListeners();
break;
// Session created (v3)
case 'session_created':
final sessionId = data['session_id'] as String?;
final name = data['name'] as String?;
if (sessionId != null) {
final newSession = ChatSession(
sessionId: sessionId,
name: name ?? 'New Session',
);
_sessions.add(newSession);
_messages.add(Message(
role: 'system',
content: 'Sesión creada: ${newSession.name}',
));
// Auto-connect to new session
connectToSession(sessionId);
}
notifyListeners();
break;
// Connected to session (v3)
case 'session_connected':
final sessionId = data['session_id'] as String?;
final name = data['name'] as String?;
if (sessionId != null) {
_currentSession = _sessions.firstWhere(
(s) => s.sessionId == sessionId,
orElse: () => ChatSession(
sessionId: sessionId,
name: name ?? 'Session',
),
);
_messages.clear();
_messages.add(Message(
role: 'system',
content: 'Conectado a: ${_currentSession!.name}',
));
}
notifyListeners();
break;
// Output from Claude (v3)
case 'output':
final content = data['content'] as String? ?? '';
if (content.isEmpty) break;
debugPrint('ChatProvider: OUTPUT "${content.substring(0, content.length > 50 ? 50 : content.length)}"');
_isProcessing = true;
// Check if it's a progress indicator
if (content.startsWith('procesando')) {
// Update or create progress message
if (_messages.isNotEmpty && _messages.last.role == 'assistant' && _messages.last.isStreaming == true) {
final lastIndex = _messages.length - 1;
_messages[lastIndex] = Message(
role: 'assistant',
content: content,
isStreaming: true,
);
} else {
_messages.add(Message(
role: 'assistant',
content: content,
isStreaming: true,
));
}
} else {
// Real content - replace progress or add new
if (_messages.isNotEmpty && _messages.last.role == 'assistant' && _messages.last.isStreaming == true) {
final lastIndex = _messages.length - 1;
final lastContent = _messages[lastIndex].content;
// If last message was progress, replace it. Otherwise append.
if (lastContent.startsWith('procesando')) {
_messages[lastIndex] = Message(
role: 'assistant',
content: content,
isStreaming: true,
);
} else {
// Append to existing response
_messages[lastIndex] = Message(
role: 'assistant',
content: lastContent + content,
isStreaming: true,
);
}
} else {
_messages.add(Message(
role: 'assistant',
content: content,
isStreaming: true,
));
}
}
_trimMessages();
notifyListeners();
break;
// Response complete (v3)
case 'done':
_isProcessing = false;
// Mark last assistant message as complete
if (_messages.isNotEmpty && _messages.last.role == 'assistant') {
final lastIndex = _messages.length - 1;
_messages[lastIndex] = Message(
role: 'assistant',
content: _messages[lastIndex].content,
isStreaming: false,
);
}
notifyListeners();
break;
case 'error':
_isProcessing = false;
final errorMsg = data['message'] ?? data['content'] ?? 'Error';
if (errorMsg.toString().isNotEmpty) {
_error = errorMsg;
_messages.add(Message(
role: 'system',
content: 'Error: $errorMsg',
));
}
notifyListeners();
break;
}
}
void _trimMessages() {
while (_messages.length > _maxMessages) {
_messages.removeAt(0);
}
}
/// Create and connect to a new session
void createSession(String name) {
_chatService.createSession(name);
}
/// Connect to an existing session
void connectToSession(String sessionId) {
_chatService.connectToSession(sessionId);
}
/// Refresh sessions list
void refreshSessions() {
_chatService.listSessions();
}
/// Send message to current session
void sendMessage(String content) {
if (content.trim().isEmpty) return;
if (!isConnected) {
_error = 'No conectado al servidor';
notifyListeners();
return;
}
if (_currentSession == null) {
_error = 'No hay sesión activa';
notifyListeners();
return;
}
if (_isProcessing) {
_error = 'Espera a que termine la respuesta anterior';
notifyListeners();
return;
}
_messages.add(Message(
role: 'user',
content: content,
));
_trimMessages();
_isProcessing = true;
notifyListeners();
_chatService.sendMessage(content);
}
void clearMessages() {
_messages.clear();
notifyListeners();
}
void clearError() {
_error = null;
notifyListeners();
}
void disconnect() {
_chatService.disconnect();
_messageSubscription?.cancel();
_stateSubscription?.cancel();
_errorSubscription?.cancel();
_currentSession = null;
}
@override
void dispose() {
disconnect();
_chatService.dispose();
super.dispose();
}
}