init cc
This commit is contained in:
480
lib/core/database/repositories/cache_repository.dart
Normal file
480
lib/core/database/repositories/cache_repository.dart
Normal file
@@ -0,0 +1,480 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import '../hive_service.dart';
|
||||
import '../models/cache_item.dart';
|
||||
|
||||
/// Repository for managing cached data using Hive
|
||||
class CacheRepository {
|
||||
/// Store data in cache with expiration
|
||||
Future<void> put<T>({
|
||||
required String key,
|
||||
required T data,
|
||||
required Duration expirationDuration,
|
||||
Map<String, dynamic>? metadata,
|
||||
}) async {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
final cacheItem = CacheItem.create(
|
||||
key: key,
|
||||
data: data,
|
||||
expirationDuration: expirationDuration,
|
||||
metadata: metadata,
|
||||
);
|
||||
await box.put(key, cacheItem);
|
||||
debugPrint('✅ Cache item stored: $key');
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('❌ Error storing cache item $key: $e');
|
||||
debugPrint('Stack trace: $stackTrace');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Store permanent data in cache (never expires)
|
||||
Future<void> putPermanent<T>({
|
||||
required String key,
|
||||
required T data,
|
||||
Map<String, dynamic>? metadata,
|
||||
}) async {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
final cacheItem = CacheItem.permanent(
|
||||
key: key,
|
||||
data: data,
|
||||
metadata: metadata,
|
||||
);
|
||||
await box.put(key, cacheItem);
|
||||
debugPrint('✅ Permanent cache item stored: $key');
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('❌ Error storing permanent cache item $key: $e');
|
||||
debugPrint('Stack trace: $stackTrace');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get data from cache
|
||||
T? get<T>(String key) {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
final cacheItem = box.get(key);
|
||||
|
||||
if (cacheItem == null) {
|
||||
debugPrint('📭 Cache miss: $key');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (cacheItem.isExpired) {
|
||||
debugPrint('⏰ Cache expired: $key');
|
||||
// Optionally remove expired item
|
||||
delete(key);
|
||||
return null;
|
||||
}
|
||||
|
||||
debugPrint('✅ Cache hit: $key');
|
||||
return cacheItem.data as T?;
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error getting cache item $key: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get cache item with full metadata
|
||||
CacheItem? getCacheItem(String key) {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
final cacheItem = box.get(key);
|
||||
|
||||
if (cacheItem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (cacheItem.isExpired) {
|
||||
// Optionally remove expired item
|
||||
delete(key);
|
||||
return null;
|
||||
}
|
||||
|
||||
return cacheItem;
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error getting cache item $key: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if key exists and is valid (not expired)
|
||||
bool contains(String key) {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
final cacheItem = box.get(key);
|
||||
|
||||
if (cacheItem == null) return false;
|
||||
if (cacheItem.isExpired) {
|
||||
delete(key);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error checking cache item $key: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if key exists regardless of expiration
|
||||
bool containsKey(String key) {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
return box.containsKey(key);
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error checking key $key: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete specific cache item
|
||||
Future<void> delete(String key) async {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
await box.delete(key);
|
||||
debugPrint('🗑️ Cache item deleted: $key');
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error deleting cache item $key: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete multiple cache items
|
||||
Future<void> deleteMultiple(List<String> keys) async {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
for (final key in keys) {
|
||||
await box.delete(key);
|
||||
}
|
||||
debugPrint('🗑️ Multiple cache items deleted: ${keys.length} items');
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error deleting multiple cache items: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear all expired items
|
||||
Future<int> cleanExpiredItems() async {
|
||||
return await clearExpired();
|
||||
}
|
||||
|
||||
/// Clear all expired items
|
||||
Future<int> clearExpired() async {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
final expiredKeys = <String>[];
|
||||
final now = DateTime.now();
|
||||
|
||||
for (final key in box.keys) {
|
||||
final cacheItem = box.get(key);
|
||||
if (cacheItem != null && now.isAfter(cacheItem.expiresAt)) {
|
||||
expiredKeys.add(key as String);
|
||||
}
|
||||
}
|
||||
|
||||
for (final key in expiredKeys) {
|
||||
await box.delete(key);
|
||||
}
|
||||
|
||||
debugPrint('🧹 Cleared ${expiredKeys.length} expired cache items');
|
||||
return expiredKeys.length;
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error clearing expired items: $e');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear all cache items
|
||||
Future<void> clearAll() async {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
final count = box.length;
|
||||
await box.clear();
|
||||
debugPrint('🧹 Cleared all cache items: $count items');
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error clearing all cache items: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear cache items by pattern
|
||||
Future<int> clearByPattern(Pattern pattern) async {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
final keysToDelete = <String>[];
|
||||
|
||||
for (final key in box.keys) {
|
||||
if (key is String && key.contains(pattern)) {
|
||||
keysToDelete.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
for (final key in keysToDelete) {
|
||||
await box.delete(key);
|
||||
}
|
||||
|
||||
debugPrint('🧹 Cleared ${keysToDelete.length} cache items matching pattern: $pattern');
|
||||
return keysToDelete.length;
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error clearing cache items by pattern: $e');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear cache items by type
|
||||
Future<int> clearByType(String dataType) async {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
final keysToDelete = <String>[];
|
||||
|
||||
for (final key in box.keys) {
|
||||
final cacheItem = box.get(key);
|
||||
if (cacheItem != null && cacheItem.dataType == dataType) {
|
||||
keysToDelete.add(key as String);
|
||||
}
|
||||
}
|
||||
|
||||
for (final key in keysToDelete) {
|
||||
await box.delete(key);
|
||||
}
|
||||
|
||||
debugPrint('🧹 Cleared ${keysToDelete.length} cache items of type: $dataType');
|
||||
return keysToDelete.length;
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error clearing cache items by type: $e');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Refresh cache item with new expiration
|
||||
Future<bool> refresh(String key, Duration newExpirationDuration) async {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
final cacheItem = box.get(key);
|
||||
|
||||
if (cacheItem == null) return false;
|
||||
|
||||
final refreshedItem = cacheItem.refresh(newExpirationDuration);
|
||||
await box.put(key, refreshedItem);
|
||||
|
||||
debugPrint('🔄 Cache item refreshed: $key');
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error refreshing cache item $key: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Update cache item data
|
||||
Future<bool> update<T>(String key, T newData, {Duration? newExpirationDuration}) async {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
final cacheItem = box.get(key);
|
||||
|
||||
if (cacheItem == null) return false;
|
||||
|
||||
final updatedItem = cacheItem.updateData(newData, newExpirationDuration: newExpirationDuration);
|
||||
await box.put(key, updatedItem);
|
||||
|
||||
debugPrint('📝 Cache item updated: $key');
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error updating cache item $key: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get all keys in cache
|
||||
List<String> getAllKeys() {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
return box.keys.cast<String>().toList();
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error getting all keys: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// Get keys by pattern
|
||||
List<String> getKeysByPattern(Pattern pattern) {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
return box.keys
|
||||
.cast<String>()
|
||||
.where((key) => key.contains(pattern))
|
||||
.toList();
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error getting keys by pattern: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// Get keys by data type
|
||||
List<String> getKeysByType(String dataType) {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
final keys = <String>[];
|
||||
|
||||
for (final key in box.keys) {
|
||||
final cacheItem = box.get(key);
|
||||
if (cacheItem != null && cacheItem.dataType == dataType) {
|
||||
keys.add(key as String);
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error getting keys by type: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// Get cache statistics
|
||||
CacheStats getStats() {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
final now = DateTime.now();
|
||||
var validItems = 0;
|
||||
var expiredItems = 0;
|
||||
DateTime? oldestItem;
|
||||
DateTime? newestItem;
|
||||
final typeCount = <String, int>{};
|
||||
|
||||
for (final key in box.keys) {
|
||||
final cacheItem = box.get(key);
|
||||
if (cacheItem == null) continue;
|
||||
|
||||
// Count by expiration status
|
||||
if (now.isAfter(cacheItem.expiresAt)) {
|
||||
expiredItems++;
|
||||
} else {
|
||||
validItems++;
|
||||
}
|
||||
|
||||
// Track oldest and newest items
|
||||
if (oldestItem == null || cacheItem.createdAt.isBefore(oldestItem)) {
|
||||
oldestItem = cacheItem.createdAt;
|
||||
}
|
||||
if (newestItem == null || cacheItem.createdAt.isAfter(newestItem)) {
|
||||
newestItem = cacheItem.createdAt;
|
||||
}
|
||||
|
||||
// Count by type
|
||||
typeCount[cacheItem.dataType] = (typeCount[cacheItem.dataType] ?? 0) + 1;
|
||||
}
|
||||
|
||||
return CacheStats(
|
||||
totalItems: box.length,
|
||||
validItems: validItems,
|
||||
expiredItems: expiredItems,
|
||||
oldestItem: oldestItem ?? DateTime.now(),
|
||||
newestItem: newestItem ?? DateTime.now(),
|
||||
typeCount: typeCount,
|
||||
);
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error getting cache stats: $e');
|
||||
return CacheStats(
|
||||
totalItems: 0,
|
||||
validItems: 0,
|
||||
expiredItems: 0,
|
||||
oldestItem: DateTime.now(),
|
||||
newestItem: DateTime.now(),
|
||||
typeCount: const {},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get cache size in bytes (approximate)
|
||||
int getApproximateSize() {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
// This is an approximation as Hive doesn't provide exact size
|
||||
return box.length * 1024; // Assume average 1KB per item
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error getting cache size: $e');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Compact cache storage
|
||||
Future<void> compact() async {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
await box.compact();
|
||||
debugPrint('✅ Cache storage compacted');
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error compacting cache: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Export cache data (for debugging or backup)
|
||||
Map<String, dynamic> exportCache({bool includeExpired = false}) {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
final now = DateTime.now();
|
||||
final exportData = <String, dynamic>{};
|
||||
|
||||
for (final key in box.keys) {
|
||||
final cacheItem = box.get(key);
|
||||
if (cacheItem == null) continue;
|
||||
|
||||
if (!includeExpired && now.isAfter(cacheItem.expiresAt)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
exportData[key as String] = cacheItem.toMap();
|
||||
}
|
||||
|
||||
return exportData;
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error exporting cache: $e');
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/// Watch cache changes for a specific key
|
||||
Stream<CacheItem?> watch(String key) {
|
||||
try {
|
||||
final box = HiveService.cacheBox;
|
||||
return box.watch(key: key).map((event) => event.value as CacheItem?);
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error watching cache key $key: $e');
|
||||
return Stream.value(null);
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform cache maintenance (cleanup expired items, compact storage)
|
||||
Future<Map<String, dynamic>> performMaintenance() async {
|
||||
try {
|
||||
final startTime = DateTime.now();
|
||||
|
||||
// Get stats before maintenance
|
||||
final statsBefore = getStats();
|
||||
|
||||
// Clear expired items
|
||||
final expiredCount = await clearExpired();
|
||||
|
||||
// Compact storage
|
||||
await compact();
|
||||
|
||||
// Get stats after maintenance
|
||||
final statsAfter = getStats();
|
||||
|
||||
final maintenanceTime = DateTime.now().difference(startTime);
|
||||
|
||||
final result = {
|
||||
'expiredItemsRemoved': expiredCount,
|
||||
'itemsBefore': statsBefore.totalItems,
|
||||
'itemsAfter': statsAfter.totalItems,
|
||||
'maintenanceTimeMs': maintenanceTime.inMilliseconds,
|
||||
'completedAt': DateTime.now().toIso8601String(),
|
||||
};
|
||||
|
||||
debugPrint('🔧 Cache maintenance completed: $result');
|
||||
return result;
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error during cache maintenance: $e');
|
||||
return {'error': e.toString()};
|
||||
}
|
||||
}
|
||||
}
|
||||
249
lib/core/database/repositories/settings_repository.dart
Normal file
249
lib/core/database/repositories/settings_repository.dart
Normal file
@@ -0,0 +1,249 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import '../hive_service.dart';
|
||||
import '../models/app_settings.dart';
|
||||
|
||||
/// Repository for managing application settings using Hive
|
||||
class SettingsRepository {
|
||||
static const String _defaultKey = 'app_settings';
|
||||
|
||||
/// Get the current app settings
|
||||
AppSettings getSettings() {
|
||||
try {
|
||||
final box = HiveService.appSettingsBox;
|
||||
final settings = box.get(_defaultKey);
|
||||
|
||||
if (settings == null) {
|
||||
// Return default settings if none exist
|
||||
final defaultSettings = AppSettings.defaultSettings();
|
||||
saveSettings(defaultSettings);
|
||||
return defaultSettings;
|
||||
}
|
||||
|
||||
// Check if settings need migration
|
||||
if (settings.version < 1) {
|
||||
final migratedSettings = _migrateSettings(settings);
|
||||
saveSettings(migratedSettings);
|
||||
return migratedSettings;
|
||||
}
|
||||
|
||||
return settings;
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('Error getting settings: $e');
|
||||
debugPrint('Stack trace: $stackTrace');
|
||||
|
||||
// Return default settings on error
|
||||
return AppSettings.defaultSettings();
|
||||
}
|
||||
}
|
||||
|
||||
/// Save app settings
|
||||
Future<void> saveSettings(AppSettings settings) async {
|
||||
try {
|
||||
final box = HiveService.appSettingsBox;
|
||||
final updatedSettings = settings.copyWith(lastUpdated: DateTime.now());
|
||||
await box.put(_defaultKey, updatedSettings);
|
||||
debugPrint('✅ Settings saved successfully');
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('❌ Error saving settings: $e');
|
||||
debugPrint('Stack trace: $stackTrace');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Update theme mode
|
||||
Future<void> updateThemeMode(String themeMode) async {
|
||||
final currentSettings = getSettings();
|
||||
final updatedSettings = currentSettings.copyWith(themeMode: themeMode);
|
||||
await saveSettings(updatedSettings);
|
||||
}
|
||||
|
||||
/// Update locale
|
||||
Future<void> updateLocale(String locale) async {
|
||||
final currentSettings = getSettings();
|
||||
final updatedSettings = currentSettings.copyWith(locale: locale);
|
||||
await saveSettings(updatedSettings);
|
||||
}
|
||||
|
||||
/// Update notifications enabled
|
||||
Future<void> updateNotificationsEnabled(bool enabled) async {
|
||||
final currentSettings = getSettings();
|
||||
final updatedSettings = currentSettings.copyWith(notificationsEnabled: enabled);
|
||||
await saveSettings(updatedSettings);
|
||||
}
|
||||
|
||||
/// Update analytics enabled
|
||||
Future<void> updateAnalyticsEnabled(bool enabled) async {
|
||||
final currentSettings = getSettings();
|
||||
final updatedSettings = currentSettings.copyWith(analyticsEnabled: enabled);
|
||||
await saveSettings(updatedSettings);
|
||||
}
|
||||
|
||||
/// Update cache strategy
|
||||
Future<void> updateCacheStrategy(String strategy) async {
|
||||
final currentSettings = getSettings();
|
||||
final updatedSettings = currentSettings.copyWith(cacheStrategy: strategy);
|
||||
await saveSettings(updatedSettings);
|
||||
}
|
||||
|
||||
/// Update cache expiration hours
|
||||
Future<void> updateCacheExpirationHours(int hours) async {
|
||||
final currentSettings = getSettings();
|
||||
final updatedSettings = currentSettings.copyWith(cacheExpirationHours: hours);
|
||||
await saveSettings(updatedSettings);
|
||||
}
|
||||
|
||||
/// Update auto update enabled
|
||||
Future<void> updateAutoUpdateEnabled(bool enabled) async {
|
||||
final currentSettings = getSettings();
|
||||
final updatedSettings = currentSettings.copyWith(autoUpdateEnabled: enabled);
|
||||
await saveSettings(updatedSettings);
|
||||
}
|
||||
|
||||
/// Set custom setting
|
||||
Future<void> setCustomSetting(String key, dynamic value) async {
|
||||
final currentSettings = getSettings();
|
||||
final updatedSettings = currentSettings.setCustomSetting(key, value);
|
||||
await saveSettings(updatedSettings);
|
||||
}
|
||||
|
||||
/// Get custom setting
|
||||
T? getCustomSetting<T>(String key) {
|
||||
final settings = getSettings();
|
||||
return settings.getCustomSetting<T>(key);
|
||||
}
|
||||
|
||||
/// Remove custom setting
|
||||
Future<void> removeCustomSetting(String key) async {
|
||||
final currentSettings = getSettings();
|
||||
final updatedSettings = currentSettings.removeCustomSetting(key);
|
||||
await saveSettings(updatedSettings);
|
||||
}
|
||||
|
||||
/// Reset to default settings
|
||||
Future<void> resetToDefault() async {
|
||||
final defaultSettings = AppSettings.defaultSettings();
|
||||
await saveSettings(defaultSettings);
|
||||
debugPrint('✅ Settings reset to default');
|
||||
}
|
||||
|
||||
/// Export settings to Map (for backup)
|
||||
Map<String, dynamic> exportSettings() {
|
||||
try {
|
||||
final settings = getSettings();
|
||||
return settings.toMap();
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error exporting settings: $e');
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/// Import settings from Map (for restore)
|
||||
Future<bool> importSettings(Map<String, dynamic> settingsMap) async {
|
||||
try {
|
||||
final settings = AppSettings.fromMap(settingsMap);
|
||||
await saveSettings(settings);
|
||||
debugPrint('✅ Settings imported successfully');
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error importing settings: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if settings exist
|
||||
bool hasSettings() {
|
||||
try {
|
||||
final box = HiveService.appSettingsBox;
|
||||
return box.containsKey(_defaultKey);
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error checking settings existence: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear all settings (use with caution)
|
||||
Future<void> clearSettings() async {
|
||||
try {
|
||||
final box = HiveService.appSettingsBox;
|
||||
await box.delete(_defaultKey);
|
||||
debugPrint('✅ Settings cleared');
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error clearing settings: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get settings statistics
|
||||
Map<String, dynamic> getSettingsStats() {
|
||||
try {
|
||||
final settings = getSettings();
|
||||
final box = HiveService.appSettingsBox;
|
||||
|
||||
return {
|
||||
'hasCustomSettings': settings.customSettings?.isNotEmpty ?? false,
|
||||
'customSettingsCount': settings.customSettings?.length ?? 0,
|
||||
'lastUpdated': settings.lastUpdated.toIso8601String(),
|
||||
'version': settings.version,
|
||||
'settingsAge': DateTime.now().difference(settings.lastUpdated).inDays,
|
||||
'isExpired': settings.isExpired(),
|
||||
'totalSettingsInBox': box.length,
|
||||
};
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error getting settings stats: $e');
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/// Migrate settings from older version
|
||||
AppSettings _migrateSettings(AppSettings oldSettings) {
|
||||
debugPrint('🔄 Migrating settings from version ${oldSettings.version} to 1');
|
||||
|
||||
// Perform any necessary migrations here
|
||||
// For now, just update the version and timestamp
|
||||
return oldSettings.copyWith(
|
||||
version: 1,
|
||||
lastUpdated: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Validate settings
|
||||
bool validateSettings(AppSettings settings) {
|
||||
try {
|
||||
// Basic validation
|
||||
if (settings.version < 1) return false;
|
||||
if (settings.cacheExpirationHours < 1) return false;
|
||||
if (!['light', 'dark', 'system'].contains(settings.themeMode)) return false;
|
||||
if (!['aggressive', 'normal', 'minimal'].contains(settings.cacheStrategy)) return false;
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error validating settings: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Watch settings changes
|
||||
Stream<AppSettings> watchSettings() {
|
||||
try {
|
||||
final box = HiveService.appSettingsBox;
|
||||
return box.watch(key: _defaultKey).map((event) {
|
||||
final settings = event.value as AppSettings?;
|
||||
return settings ?? AppSettings.defaultSettings();
|
||||
});
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error watching settings: $e');
|
||||
return Stream.value(AppSettings.defaultSettings());
|
||||
}
|
||||
}
|
||||
|
||||
/// Compact settings storage
|
||||
Future<void> compact() async {
|
||||
try {
|
||||
final box = HiveService.appSettingsBox;
|
||||
await box.compact();
|
||||
debugPrint('✅ Settings storage compacted');
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error compacting settings: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
329
lib/core/database/repositories/user_preferences_repository.dart
Normal file
329
lib/core/database/repositories/user_preferences_repository.dart
Normal file
@@ -0,0 +1,329 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import '../hive_service.dart';
|
||||
import '../models/user_preferences.dart';
|
||||
|
||||
/// Repository for managing user preferences using Hive
|
||||
class UserPreferencesRepository {
|
||||
static const String _defaultKey = 'current_user_preferences';
|
||||
|
||||
/// Get the current user preferences (alias for getUserPreferences)
|
||||
UserPreferences? getPreferences([String? userId]) {
|
||||
return getUserPreferences(userId);
|
||||
}
|
||||
|
||||
/// Get the current user preferences
|
||||
UserPreferences? getUserPreferences([String? userId]) {
|
||||
try {
|
||||
final box = HiveService.userDataBox;
|
||||
final key = userId ?? _defaultKey;
|
||||
|
||||
final preferences = box.get(key);
|
||||
if (preferences == null) return null;
|
||||
|
||||
// Check if preferences need migration
|
||||
if (preferences.needsMigration()) {
|
||||
final migratedPreferences = preferences.migrate();
|
||||
saveUserPreferences(migratedPreferences, userId);
|
||||
return migratedPreferences;
|
||||
}
|
||||
|
||||
return preferences;
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('Error getting user preferences: $e');
|
||||
debugPrint('Stack trace: $stackTrace');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Save user preferences
|
||||
Future<void> saveUserPreferences(UserPreferences preferences, [String? userId]) async {
|
||||
try {
|
||||
final box = HiveService.userDataBox;
|
||||
final key = userId ?? _defaultKey;
|
||||
|
||||
final updatedPreferences = preferences.copyWith(lastUpdated: DateTime.now());
|
||||
await box.put(key, updatedPreferences);
|
||||
|
||||
debugPrint('✅ User preferences saved for key: $key');
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('❌ Error saving user preferences: $e');
|
||||
debugPrint('Stack trace: $stackTrace');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Create new user preferences
|
||||
Future<UserPreferences> createUserPreferences({
|
||||
required String userId,
|
||||
required String displayName,
|
||||
String? email,
|
||||
String? avatarUrl,
|
||||
Map<String, dynamic>? preferences,
|
||||
List<String>? favoriteItems,
|
||||
}) async {
|
||||
final userPreferences = UserPreferences.create(
|
||||
userId: userId,
|
||||
displayName: displayName,
|
||||
email: email,
|
||||
avatarUrl: avatarUrl,
|
||||
preferences: preferences,
|
||||
favoriteItems: favoriteItems,
|
||||
);
|
||||
|
||||
await saveUserPreferences(userPreferences, userId);
|
||||
return userPreferences;
|
||||
}
|
||||
|
||||
/// Update user profile information
|
||||
Future<void> updateProfile({
|
||||
String? userId,
|
||||
String? displayName,
|
||||
String? email,
|
||||
String? avatarUrl,
|
||||
}) async {
|
||||
final currentPreferences = getUserPreferences(userId);
|
||||
if (currentPreferences == null) return;
|
||||
|
||||
final updatedPreferences = currentPreferences.copyWith(
|
||||
displayName: displayName ?? currentPreferences.displayName,
|
||||
email: email ?? currentPreferences.email,
|
||||
avatarUrl: avatarUrl ?? currentPreferences.avatarUrl,
|
||||
);
|
||||
|
||||
await saveUserPreferences(updatedPreferences, userId);
|
||||
}
|
||||
|
||||
/// Set a user preference
|
||||
Future<void> setPreference(String key, dynamic value, [String? userId]) async {
|
||||
final currentPreferences = getUserPreferences(userId);
|
||||
if (currentPreferences == null) return;
|
||||
|
||||
final updatedPreferences = currentPreferences.setPreference(key, value);
|
||||
await saveUserPreferences(updatedPreferences, userId);
|
||||
}
|
||||
|
||||
/// Get a user preference with type safety
|
||||
T getPreference<T>(String key, T defaultValue, [String? userId]) {
|
||||
final preferences = getUserPreferences(userId);
|
||||
if (preferences == null) return defaultValue;
|
||||
|
||||
return preferences.getPreference<T>(key, defaultValue);
|
||||
}
|
||||
|
||||
/// Remove a user preference
|
||||
Future<void> removePreference(String key, [String? userId]) async {
|
||||
final currentPreferences = getUserPreferences(userId);
|
||||
if (currentPreferences == null) return;
|
||||
|
||||
final updatedPreferences = currentPreferences.removePreference(key);
|
||||
await saveUserPreferences(updatedPreferences, userId);
|
||||
}
|
||||
|
||||
/// Add item to favorites
|
||||
Future<void> addFavorite(String itemId, [String? userId]) async {
|
||||
final currentPreferences = getUserPreferences(userId);
|
||||
if (currentPreferences == null) return;
|
||||
|
||||
final updatedPreferences = currentPreferences.addFavorite(itemId);
|
||||
await saveUserPreferences(updatedPreferences, userId);
|
||||
}
|
||||
|
||||
/// Remove item from favorites
|
||||
Future<void> removeFavorite(String itemId, [String? userId]) async {
|
||||
final currentPreferences = getUserPreferences(userId);
|
||||
if (currentPreferences == null) return;
|
||||
|
||||
final updatedPreferences = currentPreferences.removeFavorite(itemId);
|
||||
await saveUserPreferences(updatedPreferences, userId);
|
||||
}
|
||||
|
||||
/// Check if item is favorite
|
||||
bool isFavorite(String itemId, [String? userId]) {
|
||||
final preferences = getUserPreferences(userId);
|
||||
return preferences?.isFavorite(itemId) ?? false;
|
||||
}
|
||||
|
||||
/// Get all favorite items
|
||||
List<String> getFavorites([String? userId]) {
|
||||
final preferences = getUserPreferences(userId);
|
||||
return preferences?.favoriteItems ?? [];
|
||||
}
|
||||
|
||||
/// Update last accessed time for an item
|
||||
Future<void> updateLastAccessed(String itemId, [String? userId]) async {
|
||||
final currentPreferences = getUserPreferences(userId);
|
||||
if (currentPreferences == null) return;
|
||||
|
||||
final updatedPreferences = currentPreferences.updateLastAccessed(itemId);
|
||||
await saveUserPreferences(updatedPreferences, userId);
|
||||
}
|
||||
|
||||
/// Get last accessed time for an item
|
||||
DateTime? getLastAccessed(String itemId, [String? userId]) {
|
||||
final preferences = getUserPreferences(userId);
|
||||
return preferences?.getLastAccessed(itemId);
|
||||
}
|
||||
|
||||
/// Get recently accessed items
|
||||
List<String> getRecentlyAccessed({int limit = 10, String? userId}) {
|
||||
final preferences = getUserPreferences(userId);
|
||||
return preferences?.getRecentlyAccessed(limit: limit) ?? [];
|
||||
}
|
||||
|
||||
/// Clean old access records
|
||||
Future<void> cleanOldAccess({int maxAgeDays = 30, String? userId}) async {
|
||||
final currentPreferences = getUserPreferences(userId);
|
||||
if (currentPreferences == null) return;
|
||||
|
||||
final updatedPreferences = currentPreferences.cleanOldAccess(maxAgeDays: maxAgeDays);
|
||||
await saveUserPreferences(updatedPreferences, userId);
|
||||
}
|
||||
|
||||
/// Get user statistics
|
||||
Map<String, dynamic> getUserStats([String? userId]) {
|
||||
final preferences = getUserPreferences(userId);
|
||||
return preferences?.getStats() ?? {};
|
||||
}
|
||||
|
||||
/// Export user preferences to Map (for backup)
|
||||
Map<String, dynamic> exportUserPreferences([String? userId]) {
|
||||
try {
|
||||
final preferences = getUserPreferences(userId);
|
||||
return preferences?.toMap() ?? {};
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error exporting user preferences: $e');
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/// Import user preferences from Map (for restore)
|
||||
Future<bool> importUserPreferences(Map<String, dynamic> preferencesMap, [String? userId]) async {
|
||||
try {
|
||||
final preferences = UserPreferences.fromMap(preferencesMap);
|
||||
await saveUserPreferences(preferences, userId);
|
||||
debugPrint('✅ User preferences imported successfully');
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error importing user preferences: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if user preferences exist
|
||||
bool hasUserPreferences([String? userId]) {
|
||||
try {
|
||||
final box = HiveService.userDataBox;
|
||||
final key = userId ?? _defaultKey;
|
||||
return box.containsKey(key);
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error checking user preferences existence: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear user preferences (use with caution)
|
||||
Future<void> clearUserPreferences([String? userId]) async {
|
||||
try {
|
||||
final box = HiveService.userDataBox;
|
||||
final key = userId ?? _defaultKey;
|
||||
await box.delete(key);
|
||||
debugPrint('✅ User preferences cleared for key: $key');
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error clearing user preferences: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get all user IDs that have preferences stored
|
||||
List<String> getAllUserIds() {
|
||||
try {
|
||||
final box = HiveService.userDataBox;
|
||||
return box.keys.cast<String>().where((key) => key != _defaultKey).toList();
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error getting all user IDs: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete preferences for a specific user
|
||||
Future<void> deleteUserPreferences(String userId) async {
|
||||
try {
|
||||
final box = HiveService.userDataBox;
|
||||
await box.delete(userId);
|
||||
debugPrint('✅ User preferences deleted for user: $userId');
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error deleting user preferences: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get multiple users' preferences
|
||||
Map<String, UserPreferences> getMultipleUserPreferences(List<String> userIds) {
|
||||
final result = <String, UserPreferences>{};
|
||||
|
||||
for (final userId in userIds) {
|
||||
final preferences = getUserPreferences(userId);
|
||||
if (preferences != null) {
|
||||
result[userId] = preferences;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Validate user preferences
|
||||
bool validateUserPreferences(UserPreferences preferences) {
|
||||
try {
|
||||
// Basic validation
|
||||
if (preferences.userId.isEmpty) return false;
|
||||
if (preferences.displayName.isEmpty) return false;
|
||||
if (preferences.version < 1) return false;
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error validating user preferences: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Watch user preferences changes
|
||||
Stream<UserPreferences?> watchUserPreferences([String? userId]) {
|
||||
try {
|
||||
final box = HiveService.userDataBox;
|
||||
final key = userId ?? _defaultKey;
|
||||
return box.watch(key: key).map((event) => event.value as UserPreferences?);
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error watching user preferences: $e');
|
||||
return Stream.value(null);
|
||||
}
|
||||
}
|
||||
|
||||
/// Compact user preferences storage
|
||||
Future<void> compact() async {
|
||||
try {
|
||||
final box = HiveService.userDataBox;
|
||||
await box.compact();
|
||||
debugPrint('✅ User preferences storage compacted');
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error compacting user preferences: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Get storage statistics
|
||||
Map<String, dynamic> getStorageStats() {
|
||||
try {
|
||||
final box = HiveService.userDataBox;
|
||||
final allUserIds = getAllUserIds();
|
||||
|
||||
return {
|
||||
'totalUsers': allUserIds.length,
|
||||
'hasDefaultUser': hasUserPreferences(),
|
||||
'totalEntries': box.length,
|
||||
'userIds': allUserIds,
|
||||
};
|
||||
} catch (e) {
|
||||
debugPrint('❌ Error getting storage stats: $e');
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user