import "package:flutter/foundation.dart"; import "package:uuid/uuid.dart"; import "../../src/project_store.dart"; import "../../src/session/conversation_history.dart"; import "../../src/session/session_store.dart"; import "../../src/session/session_types.dart"; class SessionProvider extends ChangeNotifier { SessionProvider(this._projectStore) { _loadSessions(); } final ProjectStore _projectStore; final SessionStore _sessionStore = SessionStore.instance; final ConversationHistory _conversationHistory = ConversationHistory(); List _sessions = []; String? _currentSessionId; ConversationSession? _currentSession; String? _activeWorkingDirectory; List get sessions => _sessions; String? get currentSessionId => _currentSessionId; ConversationSession? get currentSession => _currentSession; String? get activeWorkingDirectory => _activeWorkingDirectory; List sessionsForWorkingDirectory(String? workingDirectory) { final normalizedDirectory = workingDirectory?.trim(); if (normalizedDirectory == null || normalizedDirectory.isEmpty) { return List.unmodifiable(_sessions); } return List.unmodifiable( _sessions.where( (session) => session.workingDirectory == normalizedDirectory, ), ); } void selectWorkingDirectory(String? workingDirectory) { _activeWorkingDirectory = workingDirectory?.trim(); notifyListeners(); } void clearCurrentSession({String? workingDirectory}) { _conversationHistory.setSession( ConversationSession( id: "", name: "", created: DateTime.now().toUtc(), updated: DateTime.now().toUtc(), workingDirectory: workingDirectory?.trim(), ), ); _currentSession = null; _currentSessionId = null; _activeWorkingDirectory = workingDirectory?.trim(); notifyListeners(); } Future _loadSessions() async { try { final workingDirs = _projectStore.projects .map((p) => p.workingDirectory) .where((d) => d.isNotEmpty) .toList(); _sessions = await _sessionStore.listAllSessions(workingDirs); notifyListeners(); } catch (error, stackTrace) { _logException("Failed to load sessions", error, stackTrace); _sessions = []; } } Future createNewSession({ String? workingDirectory, String? name, String? model, }) async { try { const uuid = Uuid(); final newSessionId = uuid.v4(); final now = DateTime.now().toUtc(); final normalizedDirectory = workingDirectory?.trim(); final newSession = ConversationSession( id: newSessionId, name: name ?? "New Chat", created: now, updated: now, workingDirectory: normalizedDirectory == null || normalizedDirectory.isEmpty ? null : normalizedDirectory, model: model, ); await _sessionStore.saveSession(newSession); _conversationHistory.setSession(newSession); _currentSession = newSession; _currentSessionId = newSessionId; _activeWorkingDirectory = newSession.workingDirectory; await _loadSessions(); notifyListeners(); } catch (error, stackTrace) { _logException("Failed to create a new session", error, stackTrace); } } Future loadSession(SessionSummary summary) async { try { final workingDir = summary.workingDirectory; if (workingDir == null || workingDir.isEmpty) return; final session = await _sessionStore.loadSession( summary.id, workingDirectory: workingDir, ); if (session != null) { _conversationHistory.setSession(session); _currentSession = session; _currentSessionId = summary.id; _activeWorkingDirectory = session.workingDirectory; notifyListeners(); } } catch (error, stackTrace) { _logException("Failed to load session ${summary.id}", error, stackTrace); _currentSession = null; _currentSessionId = null; _activeWorkingDirectory = null; } } Future deleteSession(SessionSummary summary) async { try { final workingDir = summary.workingDirectory; if (workingDir == null || workingDir.isEmpty) return; await _sessionStore.deleteSession(summary.id, workingDirectory: workingDir); if (_currentSessionId == summary.id) { _conversationHistory.setSession( ConversationSession( id: "", name: "", created: DateTime.now().toUtc(), updated: DateTime.now().toUtc(), ), ); _currentSession = null; _currentSessionId = null; _activeWorkingDirectory = null; } await _loadSessions(); notifyListeners(); } catch (error, stackTrace) { _logException("Failed to delete session ${summary.id}", error, stackTrace); } } Future refreshSessions() async { try { await _loadSessions(); } catch (error, stackTrace) { _logException("Failed to refresh sessions", error, stackTrace); } } // Updates the model on the current in-memory session and persists it Future updateSessionModel(String model) async { final session = _currentSession; if (session == null) return; session.model = model; await _sessionStore.saveSession(session); } ConversationHistory getConversationHistory() => _conversationHistory; void _logException(String message, Object error, StackTrace stackTrace) { print("$message: $error"); print(stackTrace); } }