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

144 lines
4.2 KiB
Dart

import "package:flutter/foundation.dart";
import "../../src/local_state.dart";
import "../../src/project_settings_store.dart";
class SettingsProvider extends ChangeNotifier {
SettingsProvider(this._settingsStore) : _globalSettings = _settingsStore.settings;
static const Map<String, String> _legacyModelAliases = {
"google/gemini-2.0-flash": "google/gemini-2.0-flash-001",
};
final SettingsStore _settingsStore;
LocalSettings _globalSettings;
LocalSettings? _projectSettings;
String? _threadModel;
String? _activeProjectDir;
// Effective settings: global → project override → thread model
LocalSettings get settings {
var merged = _globalSettings.mergeWith(_projectSettings);
if (_threadModel != null && _threadModel!.isNotEmpty) {
merged = merged.copyWith(model: _threadModel);
}
return merged;
}
String normalizeModelId(String? modelId) {
if (modelId == null || modelId.isEmpty) {
return "anthropic/claude-sonnet-4.6";
}
return _legacyModelAliases[modelId] ?? modelId;
}
// Called when the active project changes
Future<void> setActiveProject(String? workingDirectory) async {
_activeProjectDir = workingDirectory;
_projectSettings = null;
_threadModel = null;
if (workingDirectory != null && workingDirectory.isNotEmpty) {
_projectSettings = await ProjectSettingsStore.instance.load(workingDirectory);
}
notifyListeners();
}
// Called when a thread is loaded or cleared
void setThreadModel(String? model) {
_threadModel = model != null ? normalizeModelId(model) : null;
notifyListeners();
}
Future<void> updateModel(String newModel) async {
final normalized = normalizeModelId(newModel);
// update thread model in memory
_threadModel = normalized;
// also persist to global settings as the new default
await _settingsStore.update(
(current) => current.copyWith(model: normalized),
);
_globalSettings = _settingsStore.settings;
notifyListeners();
}
Future<void> updateApiKey(String newKey) async {
await _settingsStore.update(
(current) => current.copyWith(openRouterApiKey: newKey),
);
_globalSettings = _settingsStore.settings;
notifyListeners();
}
Future<void> updateTheme(String newTheme) async {
await _settingsStore.update((current) => current.copyWith(theme: newTheme));
_globalSettings = _settingsStore.settings;
notifyListeners();
}
Future<void> updateAdvisorEffortLevel(String? level) async {
await _settingsStore.update(
(current) => current.copyWith(advisorEffortLevel: level),
);
_globalSettings = _settingsStore.settings;
notifyListeners();
}
Future<void> updateAdvisorModel(String? model) async {
await _settingsStore.update(
(current) => current.copyWith(advisorModel: model),
);
_globalSettings = _settingsStore.settings;
notifyListeners();
}
Future<void> updateEffortLevel(String newLevel) async {
await _settingsStore.update(
(current) => current.copyWith(effortLevel: newLevel),
);
_globalSettings = _settingsStore.settings;
notifyListeners();
}
Future<void> updatePermissionMode(String mode) async {
await _settingsStore.update(
(current) => current.copyWith(permissionMode: mode),
);
_globalSettings = _settingsStore.settings;
notifyListeners();
}
Future<void> addAlwaysAllowRule(String toolName) async {
final current = _globalSettings.alwaysAllowRules;
if (current.contains(toolName)) return;
await _settingsStore.update(
(s) => s.copyWith(alwaysAllowRules: [...current, toolName]),
);
_globalSettings = _settingsStore.settings;
notifyListeners();
}
Future<void> resetToDefaults() async {
await _settingsStore.update((_) => const LocalSettings());
_globalSettings = _settingsStore.settings;
_projectSettings = null;
_threadModel = null;
notifyListeners();
}
// Save project-level settings override
Future<void> updateProjectSetting(LocalSettings projectOverride) async {
final dir = _activeProjectDir;
if (dir == null || dir.isEmpty) return;
await ProjectSettingsStore.instance.save(dir, projectOverride);
_projectSettings = projectOverride;
notifyListeners();
}
}