The-Agency/lib/ui/providers/home_coordinator.dart

141 lines
4.3 KiB
Dart

import "package:file_picker/file_picker.dart";
import "package:flutter/foundation.dart";
import "../../src/project_store.dart";
import "../../src/session/session_types.dart";
import "chat_provider.dart";
import "../models/attachment.dart";
import "projects_provider.dart";
import "session_provider.dart";
import "settings_provider.dart";
class HomeCoordinator extends ChangeNotifier {
HomeCoordinator(this._projects, this._session, this._chat, this._settings);
final ProjectsProvider _projects;
final SessionProvider _session;
final ChatProvider _chat;
final SettingsProvider _settings;
String? _error;
String? get error => _error;
void clearError() {
_error = null;
notifyListeners();
}
void _setError(String msg) {
_error = msg;
notifyListeners();
}
Future<void> pickProjectDirectory() async {
try {
final selectedDirectory = await FilePicker.platform.getDirectoryPath(
dialogTitle: "Select project directory",
);
if (selectedDirectory == null) return;
final project = await _projects.addProject(selectedDirectory);
if (project == null) {
_setError("The selected folder could not be added as a project.");
return;
}
_projects.selectProject(project.id);
_session.clearCurrentSession(workingDirectory: project.workingDirectory);
_chat.clearConversation();
await _settings.setActiveProject(project.workingDirectory);
} catch (e, st) {
print("Project directory picker failed: $e");
print(st);
_setError(e.toString());
}
}
void createNewChat() {
final selectedProject = _projects.selectedProject;
if (selectedProject == null) {
_setError("Choose a project first so the new chat has a working directory.");
return;
}
// Don't create the session yet — that happens on first message send.
// Just clear the current state so the UI shows a blank chat.
_session.clearCurrentSession(workingDirectory: selectedProject.workingDirectory);
_chat.clearConversation();
}
Future<void> selectProject(ProjectRecord project) async {
_projects.selectProject(project.id);
await _settings.setActiveProject(project.workingDirectory);
if (_session.currentSession?.workingDirectory == project.workingDirectory) return;
_session.clearCurrentSession(workingDirectory: project.workingDirectory);
_settings.setThreadModel(null);
_chat.clearConversation();
}
Future<void> openSession(SessionSummary session) async {
// If a live runtime exists for this session, just switch focus to it
// without reloading from disk — avoids disrupting an in-progress turn.
if (_chat.isSessionRunning(session.id)) {
_chat.activateSessionById(session.id);
_session.setActiveSessionId(session.id);
_projects.selectProjectByWorkingDirectory(session.workingDirectory);
_settings.setThreadModel(session.model);
return;
}
await _session.loadSession(session);
final loaded = _session.currentSession;
if (loaded != null) {
_chat.activateSession(loaded);
}
_projects.selectProjectByWorkingDirectory(_session.activeWorkingDirectory);
_settings.setThreadModel(_session.currentSession?.model);
}
Future<void> sendMessage(String text, {List<Attachment>? attachments}) async {
final hasAttachments = attachments != null && attachments.isNotEmpty;
if (text.isEmpty && !hasAttachments) return;
if (_session.currentSession == null) {
final selectedProject = _projects.selectedProject;
if (selectedProject == null) {
_setError("Pick a project before starting a chat.");
return;
}
await _session.createNewSession(
workingDirectory: selectedProject.workingDirectory,
name: "New Chat",
model: _settings.settings.model,
);
_settings.setThreadModel(_settings.settings.model);
final newSession = _session.currentSession;
if (newSession != null) {
_chat.activateSession(newSession);
}
}
try {
await _chat.sendMessage(text, attachments: attachments);
} catch (e, st) {
print("Failed to send message: $e");
print(st);
_setError(e.toString());
} finally {
await _session.refreshSessions();
}
}
Future<void> deleteSession(SessionSummary session) async {
await _session.deleteSession(session);
}
}