193 lines
5.7 KiB
Dart
193 lines
5.7 KiB
Dart
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<SessionSummary> _sessions = <SessionSummary>[];
|
|
String? _currentSessionId;
|
|
ConversationSession? _currentSession;
|
|
String? _activeWorkingDirectory;
|
|
|
|
List<SessionSummary> get sessions => _sessions;
|
|
String? get currentSessionId => _currentSessionId;
|
|
ConversationSession? get currentSession => _currentSession;
|
|
String? get activeWorkingDirectory => _activeWorkingDirectory;
|
|
|
|
void setActiveSessionId(String id) {
|
|
_currentSessionId = id;
|
|
notifyListeners();
|
|
}
|
|
|
|
List<SessionSummary> sessionsForWorkingDirectory(String? workingDirectory) {
|
|
final normalizedDirectory = workingDirectory?.trim();
|
|
if (normalizedDirectory == null || normalizedDirectory.isEmpty) {
|
|
return List<SessionSummary>.unmodifiable(_sessions);
|
|
}
|
|
|
|
return List<SessionSummary>.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<void> _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 = <SessionSummary>[];
|
|
}
|
|
}
|
|
|
|
Future<void> 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<void> 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<void> 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<void> 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<void> 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);
|
|
}
|
|
}
|