Files

139 lines
4.4 KiB
Dart

import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
class ProviderCredential {
final String baseUrl;
final String apiKey;
const ProviderCredential({required this.baseUrl, required this.apiKey});
Map<String, String> toJson() => {'baseUrl': baseUrl, 'apiKey': apiKey};
factory ProviderCredential.fromJson(Map<String, dynamic> json) {
return ProviderCredential(
baseUrl: json['baseUrl'] as String? ?? '',
apiKey: json['apiKey'] as String? ?? '',
);
}
}
/// Service for persisting user settings like API keys and model preferences.
class SettingsService {
static const String _keyGeminiApiKey = 'gemini_api_key';
static const String _keyGeminiModel = 'gemini_model';
static const String _keyLlmProvider = 'llm_provider';
static const String _keyLlmBaseUrl = 'llm_base_url';
static const String _keyLlmProviderCredentials = 'llm_provider_credentials';
static const String _keyTargetLanguage = 'target_language';
static const String _keyBilingual = 'bilingual';
static const String _keyBatchSize = 'batch_size';
static const String _keyLastUpdateCheckAt = 'last_update_check_at';
final SharedPreferences _prefs;
SettingsService(this._prefs);
static Future<SettingsService> init() async {
final prefs = await SharedPreferences.getInstance();
return SettingsService(prefs);
}
String get geminiApiKey => _prefs.getString(_keyGeminiApiKey) ?? '';
Future<void> setGeminiApiKey(String value) =>
_prefs.setString(_keyGeminiApiKey, value);
String get geminiModel =>
_prefs.getString(_keyGeminiModel) ?? 'gemini-2.0-flash';
Future<void> setGeminiModel(String value) =>
_prefs.setString(_keyGeminiModel, value);
String get llmProvider {
final provider = _prefs.getString(_keyLlmProvider);
if (provider == null || provider.isEmpty || provider == 'google') {
return 'Gemini (Google)';
}
return provider;
}
Future<void> setLlmProvider(String value) =>
_prefs.setString(_keyLlmProvider, value);
String get llmBaseUrl =>
_prefs.getString(_keyLlmBaseUrl) ??
'https://generativelanguage.googleapis.com/v1beta/openai';
Future<void> setLlmBaseUrl(String value) =>
_prefs.setString(_keyLlmBaseUrl, value);
String get targetLanguage => _prefs.getString(_keyTargetLanguage) ?? 'zh';
Future<void> setTargetLanguage(String value) =>
_prefs.setString(_keyTargetLanguage, value);
bool get bilingual => _prefs.getBool(_keyBilingual) ?? true;
Future<void> setBilingual(bool value) => _prefs.setBool(_keyBilingual, value);
int get batchSize => _prefs.getInt(_keyBatchSize) ?? 25;
Future<void> setBatchSize(int value) => _prefs.setInt(_keyBatchSize, value);
DateTime? get lastUpdateCheckAt {
final timestamp = _prefs.getInt(_keyLastUpdateCheckAt);
if (timestamp == null || timestamp <= 0) {
return null;
}
return DateTime.fromMillisecondsSinceEpoch(timestamp);
}
Future<void> setLastUpdateCheckAt(DateTime value) =>
_prefs.setInt(_keyLastUpdateCheckAt, value.millisecondsSinceEpoch);
Map<String, ProviderCredential> get llmProviderCredentials {
final raw = _prefs.getString(_keyLlmProviderCredentials);
if (raw == null || raw.isEmpty) return {};
try {
final decoded = jsonDecode(raw);
if (decoded is! Map<String, dynamic>) return {};
return decoded.map((provider, value) {
if (value is! Map<String, dynamic>) {
return MapEntry(
provider,
const ProviderCredential(baseUrl: '', apiKey: ''),
);
}
return MapEntry(provider, ProviderCredential.fromJson(value));
});
} catch (_) {
return {};
}
}
Future<void> saveLlmProviderCredential(
String provider,
ProviderCredential credential,
) async {
final credentials = Map<String, ProviderCredential>.from(
llmProviderCredentials,
);
credentials[provider] = credential;
await _prefs.setString(
_keyLlmProviderCredentials,
jsonEncode(
credentials.map((key, value) => MapEntry(key, value.toJson())),
),
);
}
Future<void> deleteLlmProviderCredential(String provider) async {
final credentials = Map<String, ProviderCredential>.from(
llmProviderCredentials,
);
credentials.remove(provider);
await _prefs.setString(
_keyLlmProviderCredentials,
jsonEncode(
credentials.map((key, value) => MapEntry(key, value.toJson())),
),
);
}
}