init cc
This commit is contained in:
212
lib/core/database/models/app_settings.dart
Normal file
212
lib/core/database/models/app_settings.dart
Normal file
@@ -0,0 +1,212 @@
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
part 'app_settings.g.dart';
|
||||
|
||||
/// App settings model for storing application-wide configuration
|
||||
@HiveType(typeId: 0)
|
||||
class AppSettings extends HiveObject {
|
||||
@HiveField(0)
|
||||
final int version;
|
||||
|
||||
@HiveField(1)
|
||||
final String themeMode; // 'light', 'dark', 'system'
|
||||
|
||||
@HiveField(2)
|
||||
final String locale; // Language code (e.g., 'en', 'es')
|
||||
|
||||
@HiveField(3)
|
||||
final bool notificationsEnabled;
|
||||
|
||||
@HiveField(4)
|
||||
final bool analyticsEnabled;
|
||||
|
||||
@HiveField(5)
|
||||
final String cacheStrategy; // 'aggressive', 'normal', 'minimal'
|
||||
|
||||
@HiveField(6)
|
||||
final int cacheExpirationHours;
|
||||
|
||||
@HiveField(7)
|
||||
final bool autoUpdateEnabled;
|
||||
|
||||
@HiveField(8)
|
||||
final DateTime lastUpdated;
|
||||
|
||||
@HiveField(9)
|
||||
final Map<String, dynamic>? customSettings;
|
||||
|
||||
AppSettings({
|
||||
this.version = 1,
|
||||
this.themeMode = 'system',
|
||||
this.locale = 'en',
|
||||
this.notificationsEnabled = true,
|
||||
this.analyticsEnabled = false,
|
||||
this.cacheStrategy = 'normal',
|
||||
this.cacheExpirationHours = 24,
|
||||
this.autoUpdateEnabled = true,
|
||||
required this.lastUpdated,
|
||||
this.customSettings,
|
||||
});
|
||||
|
||||
/// Create a copy with modified fields
|
||||
AppSettings copyWith({
|
||||
int? version,
|
||||
String? themeMode,
|
||||
String? locale,
|
||||
bool? notificationsEnabled,
|
||||
bool? analyticsEnabled,
|
||||
String? cacheStrategy,
|
||||
int? cacheExpirationHours,
|
||||
bool? autoUpdateEnabled,
|
||||
DateTime? lastUpdated,
|
||||
Map<String, dynamic>? customSettings,
|
||||
}) {
|
||||
return AppSettings(
|
||||
version: version ?? this.version,
|
||||
themeMode: themeMode ?? this.themeMode,
|
||||
locale: locale ?? this.locale,
|
||||
notificationsEnabled: notificationsEnabled ?? this.notificationsEnabled,
|
||||
analyticsEnabled: analyticsEnabled ?? this.analyticsEnabled,
|
||||
cacheStrategy: cacheStrategy ?? this.cacheStrategy,
|
||||
cacheExpirationHours: cacheExpirationHours ?? this.cacheExpirationHours,
|
||||
autoUpdateEnabled: autoUpdateEnabled ?? this.autoUpdateEnabled,
|
||||
lastUpdated: lastUpdated ?? this.lastUpdated,
|
||||
customSettings: customSettings ?? this.customSettings,
|
||||
);
|
||||
}
|
||||
|
||||
/// Create default app settings
|
||||
factory AppSettings.defaultSettings() {
|
||||
return AppSettings(
|
||||
version: 1,
|
||||
themeMode: 'system',
|
||||
locale: 'en',
|
||||
notificationsEnabled: true,
|
||||
analyticsEnabled: false,
|
||||
cacheStrategy: 'normal',
|
||||
cacheExpirationHours: 24,
|
||||
autoUpdateEnabled: true,
|
||||
lastUpdated: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Convert to Map for JSON serialization
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'version': version,
|
||||
'themeMode': themeMode,
|
||||
'locale': locale,
|
||||
'notificationsEnabled': notificationsEnabled,
|
||||
'analyticsEnabled': analyticsEnabled,
|
||||
'cacheStrategy': cacheStrategy,
|
||||
'cacheExpirationHours': cacheExpirationHours,
|
||||
'autoUpdateEnabled': autoUpdateEnabled,
|
||||
'lastUpdated': lastUpdated.toIso8601String(),
|
||||
'customSettings': customSettings,
|
||||
};
|
||||
}
|
||||
|
||||
/// Create from Map for JSON deserialization
|
||||
factory AppSettings.fromMap(Map<String, dynamic> map) {
|
||||
return AppSettings(
|
||||
version: map['version'] ?? 1,
|
||||
themeMode: map['themeMode'] ?? 'system',
|
||||
locale: map['locale'] ?? 'en',
|
||||
notificationsEnabled: map['notificationsEnabled'] ?? true,
|
||||
analyticsEnabled: map['analyticsEnabled'] ?? false,
|
||||
cacheStrategy: map['cacheStrategy'] ?? 'normal',
|
||||
cacheExpirationHours: map['cacheExpirationHours'] ?? 24,
|
||||
autoUpdateEnabled: map['autoUpdateEnabled'] ?? true,
|
||||
lastUpdated: DateTime.parse(map['lastUpdated'] ?? DateTime.now().toIso8601String()),
|
||||
customSettings: map['customSettings']?.cast<String, dynamic>(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Check if settings are expired (for auto-refresh logic)
|
||||
bool isExpired({int maxAgeHours = 168}) { // Default 1 week
|
||||
final now = DateTime.now();
|
||||
final difference = now.difference(lastUpdated);
|
||||
return difference.inHours > maxAgeHours;
|
||||
}
|
||||
|
||||
/// Get custom setting value
|
||||
T? getCustomSetting<T>(String key) {
|
||||
return customSettings?[key] as T?;
|
||||
}
|
||||
|
||||
/// Set custom setting value
|
||||
AppSettings setCustomSetting(String key, dynamic value) {
|
||||
final updatedCustomSettings = Map<String, dynamic>.from(customSettings ?? {});
|
||||
updatedCustomSettings[key] = value;
|
||||
|
||||
return copyWith(
|
||||
customSettings: updatedCustomSettings,
|
||||
lastUpdated: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Remove custom setting
|
||||
AppSettings removeCustomSetting(String key) {
|
||||
if (customSettings == null) return this;
|
||||
|
||||
final updatedCustomSettings = Map<String, dynamic>.from(customSettings!);
|
||||
updatedCustomSettings.remove(key);
|
||||
|
||||
return copyWith(
|
||||
customSettings: updatedCustomSettings.isNotEmpty ? updatedCustomSettings : null,
|
||||
lastUpdated: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AppSettings{version: $version, themeMode: $themeMode, locale: $locale, '
|
||||
'notificationsEnabled: $notificationsEnabled, analyticsEnabled: $analyticsEnabled, '
|
||||
'cacheStrategy: $cacheStrategy, cacheExpirationHours: $cacheExpirationHours, '
|
||||
'autoUpdateEnabled: $autoUpdateEnabled, lastUpdated: $lastUpdated, '
|
||||
'customSettings: $customSettings}';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is AppSettings &&
|
||||
other.version == version &&
|
||||
other.themeMode == themeMode &&
|
||||
other.locale == locale &&
|
||||
other.notificationsEnabled == notificationsEnabled &&
|
||||
other.analyticsEnabled == analyticsEnabled &&
|
||||
other.cacheStrategy == cacheStrategy &&
|
||||
other.cacheExpirationHours == cacheExpirationHours &&
|
||||
other.autoUpdateEnabled == autoUpdateEnabled &&
|
||||
other.lastUpdated == lastUpdated &&
|
||||
_mapEquals(other.customSettings, customSettings);
|
||||
}
|
||||
|
||||
bool _mapEquals(Map<String, dynamic>? a, Map<String, dynamic>? b) {
|
||||
if (a == null) return b == null;
|
||||
if (b == null) return false;
|
||||
if (a.length != b.length) return false;
|
||||
for (final key in a.keys) {
|
||||
if (!b.containsKey(key) || a[key] != b[key]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return Object.hash(
|
||||
version,
|
||||
themeMode,
|
||||
locale,
|
||||
notificationsEnabled,
|
||||
analyticsEnabled,
|
||||
cacheStrategy,
|
||||
cacheExpirationHours,
|
||||
autoUpdateEnabled,
|
||||
lastUpdated,
|
||||
customSettings?.hashCode ?? 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
68
lib/core/database/models/app_settings.g.dart
Normal file
68
lib/core/database/models/app_settings.g.dart
Normal file
@@ -0,0 +1,68 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'app_settings.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// TypeAdapterGenerator
|
||||
// **************************************************************************
|
||||
|
||||
class AppSettingsAdapter extends TypeAdapter<AppSettings> {
|
||||
@override
|
||||
final int typeId = 0;
|
||||
|
||||
@override
|
||||
AppSettings read(BinaryReader reader) {
|
||||
final numOfFields = reader.readByte();
|
||||
final fields = <int, dynamic>{
|
||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||
};
|
||||
return AppSettings(
|
||||
version: fields[0] as int,
|
||||
themeMode: fields[1] as String,
|
||||
locale: fields[2] as String,
|
||||
notificationsEnabled: fields[3] as bool,
|
||||
analyticsEnabled: fields[4] as bool,
|
||||
cacheStrategy: fields[5] as String,
|
||||
cacheExpirationHours: fields[6] as int,
|
||||
autoUpdateEnabled: fields[7] as bool,
|
||||
lastUpdated: fields[8] as DateTime,
|
||||
customSettings: (fields[9] as Map?)?.cast<String, dynamic>(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, AppSettings obj) {
|
||||
writer
|
||||
..writeByte(10)
|
||||
..writeByte(0)
|
||||
..write(obj.version)
|
||||
..writeByte(1)
|
||||
..write(obj.themeMode)
|
||||
..writeByte(2)
|
||||
..write(obj.locale)
|
||||
..writeByte(3)
|
||||
..write(obj.notificationsEnabled)
|
||||
..writeByte(4)
|
||||
..write(obj.analyticsEnabled)
|
||||
..writeByte(5)
|
||||
..write(obj.cacheStrategy)
|
||||
..writeByte(6)
|
||||
..write(obj.cacheExpirationHours)
|
||||
..writeByte(7)
|
||||
..write(obj.autoUpdateEnabled)
|
||||
..writeByte(8)
|
||||
..write(obj.lastUpdated)
|
||||
..writeByte(9)
|
||||
..write(obj.customSettings);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => typeId.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is AppSettingsAdapter &&
|
||||
runtimeType == other.runtimeType &&
|
||||
typeId == other.typeId;
|
||||
}
|
||||
274
lib/core/database/models/cache_item.dart
Normal file
274
lib/core/database/models/cache_item.dart
Normal file
@@ -0,0 +1,274 @@
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
part 'cache_item.g.dart';
|
||||
|
||||
/// Generic cache wrapper for storing any data with expiration logic
|
||||
@HiveType(typeId: 1)
|
||||
class CacheItem extends HiveObject {
|
||||
@HiveField(0)
|
||||
@override
|
||||
final String key;
|
||||
|
||||
@HiveField(1)
|
||||
final dynamic data;
|
||||
|
||||
@HiveField(2)
|
||||
final DateTime createdAt;
|
||||
|
||||
@HiveField(3)
|
||||
final DateTime expiresAt;
|
||||
|
||||
@HiveField(4)
|
||||
final String dataType; // Type identifier for runtime type safety
|
||||
|
||||
@HiveField(5)
|
||||
final Map<String, dynamic>? metadata; // Additional cache metadata
|
||||
|
||||
@HiveField(6)
|
||||
final int version; // Cache version for migration support
|
||||
|
||||
CacheItem({
|
||||
required this.key,
|
||||
required this.data,
|
||||
required this.createdAt,
|
||||
required this.expiresAt,
|
||||
required this.dataType,
|
||||
this.metadata,
|
||||
this.version = 1,
|
||||
});
|
||||
|
||||
/// Create a new cache item with expiration time
|
||||
factory CacheItem.create({
|
||||
required String key,
|
||||
required dynamic data,
|
||||
required Duration expirationDuration,
|
||||
Map<String, dynamic>? metadata,
|
||||
int version = 1,
|
||||
}) {
|
||||
final now = DateTime.now();
|
||||
return CacheItem(
|
||||
key: key,
|
||||
data: data,
|
||||
createdAt: now,
|
||||
expiresAt: now.add(expirationDuration),
|
||||
dataType: data.runtimeType.toString(),
|
||||
metadata: metadata,
|
||||
version: version,
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a cache item that never expires
|
||||
factory CacheItem.permanent({
|
||||
required String key,
|
||||
required dynamic data,
|
||||
Map<String, dynamic>? metadata,
|
||||
int version = 1,
|
||||
}) {
|
||||
final now = DateTime.now();
|
||||
return CacheItem(
|
||||
key: key,
|
||||
data: data,
|
||||
createdAt: now,
|
||||
expiresAt: DateTime(9999), // Far future date
|
||||
dataType: data.runtimeType.toString(),
|
||||
metadata: metadata,
|
||||
version: version,
|
||||
);
|
||||
}
|
||||
|
||||
/// Check if the cache item is expired
|
||||
bool get isExpired {
|
||||
return DateTime.now().isAfter(expiresAt);
|
||||
}
|
||||
|
||||
/// Check if the cache item is still valid
|
||||
bool get isValid {
|
||||
return !isExpired;
|
||||
}
|
||||
|
||||
/// Get the age of the cache item
|
||||
Duration get age {
|
||||
return DateTime.now().difference(createdAt);
|
||||
}
|
||||
|
||||
/// Get time remaining until expiration
|
||||
Duration get timeUntilExpiry {
|
||||
final now = DateTime.now();
|
||||
if (now.isAfter(expiresAt)) {
|
||||
return Duration.zero;
|
||||
}
|
||||
return expiresAt.difference(now);
|
||||
}
|
||||
|
||||
/// Check if cache item will expire within the given duration
|
||||
bool willExpireWithin(Duration duration) {
|
||||
final checkTime = DateTime.now().add(duration);
|
||||
return expiresAt.isBefore(checkTime);
|
||||
}
|
||||
|
||||
/// Create a refreshed copy with new expiration time
|
||||
CacheItem refresh(Duration newExpirationDuration) {
|
||||
final now = DateTime.now();
|
||||
return CacheItem(
|
||||
key: key,
|
||||
data: data,
|
||||
createdAt: createdAt, // Keep original creation time
|
||||
expiresAt: now.add(newExpirationDuration),
|
||||
dataType: dataType,
|
||||
metadata: metadata,
|
||||
version: version,
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a copy with updated data
|
||||
CacheItem updateData(dynamic newData, {Duration? newExpirationDuration}) {
|
||||
final now = DateTime.now();
|
||||
return CacheItem(
|
||||
key: key,
|
||||
data: newData,
|
||||
createdAt: now, // Update creation time for new data
|
||||
expiresAt: newExpirationDuration != null
|
||||
? now.add(newExpirationDuration)
|
||||
: expiresAt,
|
||||
dataType: dataType,
|
||||
metadata: metadata,
|
||||
version: version,
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a copy with updated metadata
|
||||
CacheItem updateMetadata(Map<String, dynamic> newMetadata) {
|
||||
return CacheItem(
|
||||
key: key,
|
||||
data: data,
|
||||
createdAt: createdAt,
|
||||
expiresAt: expiresAt,
|
||||
dataType: dataType,
|
||||
metadata: {...(metadata ?? {}), ...newMetadata},
|
||||
version: version,
|
||||
);
|
||||
}
|
||||
|
||||
/// Get metadata value
|
||||
V? getMetadata<V>(String key) {
|
||||
return metadata?[key] as V?;
|
||||
}
|
||||
|
||||
/// Convert to Map for JSON serialization
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'key': key,
|
||||
'data': data,
|
||||
'createdAt': createdAt.toIso8601String(),
|
||||
'expiresAt': expiresAt.toIso8601String(),
|
||||
'dataType': dataType,
|
||||
'metadata': metadata,
|
||||
'version': version,
|
||||
};
|
||||
}
|
||||
|
||||
/// Create from Map (useful for migration or external data)
|
||||
static CacheItem fromMap(Map<String, dynamic> map) {
|
||||
return CacheItem(
|
||||
key: map['key'] as String,
|
||||
data: map['data'],
|
||||
createdAt: DateTime.parse(map['createdAt'] as String),
|
||||
expiresAt: DateTime.parse(map['expiresAt'] as String),
|
||||
dataType: map['dataType'] as String,
|
||||
metadata: map['metadata']?.cast<String, dynamic>(),
|
||||
version: map['version'] as int? ?? 1,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CacheItem{key: $key, dataType: $dataType, createdAt: $createdAt, '
|
||||
'expiresAt: $expiresAt, isExpired: $isExpired, version: $version}';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is CacheItem &&
|
||||
other.key == key &&
|
||||
other.data == data &&
|
||||
other.createdAt == createdAt &&
|
||||
other.expiresAt == expiresAt &&
|
||||
other.dataType == dataType &&
|
||||
_mapEquals(other.metadata, metadata) &&
|
||||
other.version == version;
|
||||
}
|
||||
|
||||
bool _mapEquals(Map<String, dynamic>? a, Map<String, dynamic>? b) {
|
||||
if (a == null) return b == null;
|
||||
if (b == null) return false;
|
||||
if (a.length != b.length) return false;
|
||||
for (final key in a.keys) {
|
||||
if (!b.containsKey(key) || a[key] != b[key]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return Object.hash(
|
||||
key,
|
||||
data,
|
||||
createdAt,
|
||||
expiresAt,
|
||||
dataType,
|
||||
metadata?.hashCode ?? 0,
|
||||
version,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Cache statistics for monitoring cache performance
|
||||
class CacheStats {
|
||||
final int totalItems;
|
||||
final int validItems;
|
||||
final int expiredItems;
|
||||
final DateTime oldestItem;
|
||||
final DateTime newestItem;
|
||||
final Map<String, int> typeCount;
|
||||
|
||||
const CacheStats({
|
||||
required this.totalItems,
|
||||
required this.validItems,
|
||||
required this.expiredItems,
|
||||
required this.oldestItem,
|
||||
required this.newestItem,
|
||||
required this.typeCount,
|
||||
});
|
||||
|
||||
double get hitRate {
|
||||
if (totalItems == 0) return 0.0;
|
||||
return validItems / totalItems;
|
||||
}
|
||||
|
||||
double get expirationRate {
|
||||
if (totalItems == 0) return 0.0;
|
||||
return expiredItems / totalItems;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'totalItems': totalItems,
|
||||
'validItems': validItems,
|
||||
'expiredItems': expiredItems,
|
||||
'oldestItem': oldestItem.toIso8601String(),
|
||||
'newestItem': newestItem.toIso8601String(),
|
||||
'typeCount': typeCount,
|
||||
'hitRate': hitRate,
|
||||
'expirationRate': expirationRate,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CacheStats{total: $totalItems, valid: $validItems, expired: $expiredItems, '
|
||||
'hitRate: ${(hitRate * 100).toStringAsFixed(1)}%, '
|
||||
'types: ${typeCount.keys.join(', ')}}';
|
||||
}
|
||||
}
|
||||
59
lib/core/database/models/cache_item.g.dart
Normal file
59
lib/core/database/models/cache_item.g.dart
Normal file
@@ -0,0 +1,59 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'cache_item.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// TypeAdapterGenerator
|
||||
// **************************************************************************
|
||||
|
||||
class CacheItemAdapter extends TypeAdapter<CacheItem> {
|
||||
@override
|
||||
final int typeId = 1;
|
||||
|
||||
@override
|
||||
CacheItem read(BinaryReader reader) {
|
||||
final numOfFields = reader.readByte();
|
||||
final fields = <int, dynamic>{
|
||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||
};
|
||||
return CacheItem(
|
||||
key: fields[0] as String,
|
||||
data: fields[1] as dynamic,
|
||||
createdAt: fields[2] as DateTime,
|
||||
expiresAt: fields[3] as DateTime,
|
||||
dataType: fields[4] as String,
|
||||
metadata: (fields[5] as Map?)?.cast<String, dynamic>(),
|
||||
version: fields[6] as int,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, CacheItem obj) {
|
||||
writer
|
||||
..writeByte(7)
|
||||
..writeByte(0)
|
||||
..write(obj.key)
|
||||
..writeByte(1)
|
||||
..write(obj.data)
|
||||
..writeByte(2)
|
||||
..write(obj.createdAt)
|
||||
..writeByte(3)
|
||||
..write(obj.expiresAt)
|
||||
..writeByte(4)
|
||||
..write(obj.dataType)
|
||||
..writeByte(5)
|
||||
..write(obj.metadata)
|
||||
..writeByte(6)
|
||||
..write(obj.version);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => typeId.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is CacheItemAdapter &&
|
||||
runtimeType == other.runtimeType &&
|
||||
typeId == other.typeId;
|
||||
}
|
||||
379
lib/core/database/models/user_preferences.dart
Normal file
379
lib/core/database/models/user_preferences.dart
Normal file
@@ -0,0 +1,379 @@
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
part 'user_preferences.g.dart';
|
||||
|
||||
/// User preferences model for storing user-specific settings and data
|
||||
@HiveType(typeId: 2)
|
||||
class UserPreferences extends HiveObject {
|
||||
@HiveField(0)
|
||||
final String userId;
|
||||
|
||||
@HiveField(1)
|
||||
final String displayName;
|
||||
|
||||
@HiveField(2)
|
||||
final String? email;
|
||||
|
||||
@HiveField(3)
|
||||
final String? avatarUrl;
|
||||
|
||||
@HiveField(4)
|
||||
final Map<String, dynamic> preferences;
|
||||
|
||||
@HiveField(5)
|
||||
final List<String> favoriteItems;
|
||||
|
||||
@HiveField(6)
|
||||
final Map<String, DateTime> lastAccessed;
|
||||
|
||||
@HiveField(7)
|
||||
final DateTime createdAt;
|
||||
|
||||
@HiveField(8)
|
||||
final DateTime lastUpdated;
|
||||
|
||||
@HiveField(9)
|
||||
final int version;
|
||||
|
||||
UserPreferences({
|
||||
required this.userId,
|
||||
required this.displayName,
|
||||
this.email,
|
||||
this.avatarUrl,
|
||||
this.preferences = const {},
|
||||
this.favoriteItems = const [],
|
||||
this.lastAccessed = const {},
|
||||
required this.createdAt,
|
||||
required this.lastUpdated,
|
||||
this.version = 1,
|
||||
});
|
||||
|
||||
/// Create a new user preferences instance
|
||||
factory UserPreferences.create({
|
||||
required String userId,
|
||||
required String displayName,
|
||||
String? email,
|
||||
String? avatarUrl,
|
||||
Map<String, dynamic>? preferences,
|
||||
List<String>? favoriteItems,
|
||||
}) {
|
||||
final now = DateTime.now();
|
||||
return UserPreferences(
|
||||
userId: userId,
|
||||
displayName: displayName,
|
||||
email: email,
|
||||
avatarUrl: avatarUrl,
|
||||
preferences: preferences ?? {},
|
||||
favoriteItems: favoriteItems ?? [],
|
||||
lastAccessed: {},
|
||||
createdAt: now,
|
||||
lastUpdated: now,
|
||||
version: 1,
|
||||
);
|
||||
}
|
||||
|
||||
/// Create default user preferences for anonymous user
|
||||
factory UserPreferences.anonymous() {
|
||||
final now = DateTime.now();
|
||||
return UserPreferences(
|
||||
userId: 'anonymous',
|
||||
displayName: 'Anonymous User',
|
||||
preferences: _getDefaultPreferences(),
|
||||
favoriteItems: [],
|
||||
lastAccessed: {},
|
||||
createdAt: now,
|
||||
lastUpdated: now,
|
||||
version: 1,
|
||||
);
|
||||
}
|
||||
|
||||
/// Get default preferences
|
||||
static Map<String, dynamic> _getDefaultPreferences() {
|
||||
return {
|
||||
// UI Preferences
|
||||
'compactMode': false,
|
||||
'showThumbnails': true,
|
||||
'gridColumns': 2,
|
||||
'sortBy': 'name',
|
||||
'sortOrder': 'asc', // 'asc' or 'desc'
|
||||
|
||||
// Notification Preferences
|
||||
'pushNotifications': true,
|
||||
'emailNotifications': false,
|
||||
'notificationTypes': ['updates', 'recommendations'],
|
||||
|
||||
// Privacy Preferences
|
||||
'analyticsOptIn': false,
|
||||
'shareUsageData': false,
|
||||
'personalizedRecommendations': true,
|
||||
|
||||
// Content Preferences
|
||||
'autoPlay': false,
|
||||
'highQualityImages': true,
|
||||
'downloadQuality': 'medium', // 'low', 'medium', 'high'
|
||||
'cacheSize': 500, // MB
|
||||
|
||||
// Accessibility
|
||||
'textSize': 'normal', // 'small', 'normal', 'large'
|
||||
'highContrast': false,
|
||||
'reduceAnimations': false,
|
||||
};
|
||||
}
|
||||
|
||||
/// Create a copy with modified fields
|
||||
UserPreferences copyWith({
|
||||
String? userId,
|
||||
String? displayName,
|
||||
String? email,
|
||||
String? avatarUrl,
|
||||
Map<String, dynamic>? preferences,
|
||||
List<String>? favoriteItems,
|
||||
Map<String, DateTime>? lastAccessed,
|
||||
DateTime? createdAt,
|
||||
DateTime? lastUpdated,
|
||||
int? version,
|
||||
}) {
|
||||
return UserPreferences(
|
||||
userId: userId ?? this.userId,
|
||||
displayName: displayName ?? this.displayName,
|
||||
email: email ?? this.email,
|
||||
avatarUrl: avatarUrl ?? this.avatarUrl,
|
||||
preferences: preferences ?? this.preferences,
|
||||
favoriteItems: favoriteItems ?? this.favoriteItems,
|
||||
lastAccessed: lastAccessed ?? this.lastAccessed,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
lastUpdated: lastUpdated ?? DateTime.now(),
|
||||
version: version ?? this.version,
|
||||
);
|
||||
}
|
||||
|
||||
/// Get a preference value with type safety
|
||||
T getPreference<T>(String key, T defaultValue) {
|
||||
final value = preferences[key];
|
||||
if (value is T) {
|
||||
return value;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// Set a preference value
|
||||
UserPreferences setPreference(String key, dynamic value) {
|
||||
final updatedPreferences = Map<String, dynamic>.from(preferences);
|
||||
updatedPreferences[key] = value;
|
||||
|
||||
return copyWith(
|
||||
preferences: updatedPreferences,
|
||||
lastUpdated: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Remove a preference
|
||||
UserPreferences removePreference(String key) {
|
||||
final updatedPreferences = Map<String, dynamic>.from(preferences);
|
||||
updatedPreferences.remove(key);
|
||||
|
||||
return copyWith(
|
||||
preferences: updatedPreferences,
|
||||
lastUpdated: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Add item to favorites
|
||||
UserPreferences addFavorite(String itemId) {
|
||||
if (favoriteItems.contains(itemId)) return this;
|
||||
|
||||
final updatedFavorites = List<String>.from(favoriteItems);
|
||||
updatedFavorites.add(itemId);
|
||||
|
||||
return copyWith(
|
||||
favoriteItems: updatedFavorites,
|
||||
lastUpdated: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Remove item from favorites
|
||||
UserPreferences removeFavorite(String itemId) {
|
||||
if (!favoriteItems.contains(itemId)) return this;
|
||||
|
||||
final updatedFavorites = List<String>.from(favoriteItems);
|
||||
updatedFavorites.remove(itemId);
|
||||
|
||||
return copyWith(
|
||||
favoriteItems: updatedFavorites,
|
||||
lastUpdated: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Check if item is favorite
|
||||
bool isFavorite(String itemId) {
|
||||
return favoriteItems.contains(itemId);
|
||||
}
|
||||
|
||||
/// Update last accessed time for an item
|
||||
UserPreferences updateLastAccessed(String itemId) {
|
||||
final updatedLastAccessed = Map<String, DateTime>.from(lastAccessed);
|
||||
updatedLastAccessed[itemId] = DateTime.now();
|
||||
|
||||
return copyWith(
|
||||
lastAccessed: updatedLastAccessed,
|
||||
lastUpdated: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Get last accessed time for an item
|
||||
DateTime? getLastAccessed(String itemId) {
|
||||
return lastAccessed[itemId];
|
||||
}
|
||||
|
||||
/// Get recently accessed items (sorted by most recent)
|
||||
List<String> getRecentlyAccessed({int limit = 10}) {
|
||||
final entries = lastAccessed.entries.toList();
|
||||
entries.sort((a, b) => b.value.compareTo(a.value));
|
||||
return entries.take(limit).map((e) => e.key).toList();
|
||||
}
|
||||
|
||||
/// Clean old last accessed entries (older than specified days)
|
||||
UserPreferences cleanOldAccess({int maxAgeDays = 30}) {
|
||||
final cutoffDate = DateTime.now().subtract(Duration(days: maxAgeDays));
|
||||
final updatedLastAccessed = Map<String, DateTime>.from(lastAccessed);
|
||||
|
||||
updatedLastAccessed.removeWhere((key, value) => value.isBefore(cutoffDate));
|
||||
|
||||
return copyWith(
|
||||
lastAccessed: updatedLastAccessed,
|
||||
lastUpdated: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Get user statistics
|
||||
Map<String, dynamic> getStats() {
|
||||
return {
|
||||
'userId': userId,
|
||||
'displayName': displayName,
|
||||
'totalFavorites': favoriteItems.length,
|
||||
'totalAccessedItems': lastAccessed.length,
|
||||
'recentlyAccessed': getRecentlyAccessed(limit: 5),
|
||||
'accountAge': DateTime.now().difference(createdAt).inDays,
|
||||
'lastActive': lastUpdated,
|
||||
'preferences': preferences.keys.length,
|
||||
};
|
||||
}
|
||||
|
||||
/// Convert to Map for JSON serialization
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'userId': userId,
|
||||
'displayName': displayName,
|
||||
'email': email,
|
||||
'avatarUrl': avatarUrl,
|
||||
'preferences': preferences,
|
||||
'favoriteItems': favoriteItems,
|
||||
'lastAccessed': lastAccessed.map((k, v) => MapEntry(k, v.toIso8601String())),
|
||||
'createdAt': createdAt.toIso8601String(),
|
||||
'lastUpdated': lastUpdated.toIso8601String(),
|
||||
'version': version,
|
||||
};
|
||||
}
|
||||
|
||||
/// Create from Map for JSON deserialization
|
||||
factory UserPreferences.fromMap(Map<String, dynamic> map) {
|
||||
return UserPreferences(
|
||||
userId: map['userId'] as String,
|
||||
displayName: map['displayName'] as String,
|
||||
email: map['email'] as String?,
|
||||
avatarUrl: map['avatarUrl'] as String?,
|
||||
preferences: Map<String, dynamic>.from(map['preferences'] ?? {}),
|
||||
favoriteItems: List<String>.from(map['favoriteItems'] ?? []),
|
||||
lastAccessed: (map['lastAccessed'] as Map<String, dynamic>?)
|
||||
?.map((k, v) => MapEntry(k, DateTime.parse(v as String))) ?? {},
|
||||
createdAt: DateTime.parse(map['createdAt'] as String),
|
||||
lastUpdated: DateTime.parse(map['lastUpdated'] as String),
|
||||
version: map['version'] as int? ?? 1,
|
||||
);
|
||||
}
|
||||
|
||||
/// Check if preferences need migration
|
||||
bool needsMigration() {
|
||||
const currentVersion = 1;
|
||||
return version < currentVersion;
|
||||
}
|
||||
|
||||
/// Migrate preferences to current version
|
||||
UserPreferences migrate() {
|
||||
if (!needsMigration()) return this;
|
||||
|
||||
var migrated = this;
|
||||
|
||||
// Add migration logic here as needed
|
||||
// Example:
|
||||
// if (version < 2) {
|
||||
// migrated = _migrateToVersion2(migrated);
|
||||
// }
|
||||
|
||||
return migrated.copyWith(version: 1);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UserPreferences{userId: $userId, displayName: $displayName, '
|
||||
'favorites: ${favoriteItems.length}, preferences: ${preferences.keys.length}, '
|
||||
'lastUpdated: $lastUpdated}';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is UserPreferences &&
|
||||
other.userId == userId &&
|
||||
other.displayName == displayName &&
|
||||
other.email == email &&
|
||||
other.avatarUrl == avatarUrl &&
|
||||
_mapEquals(other.preferences, preferences) &&
|
||||
_listEquals(other.favoriteItems, favoriteItems) &&
|
||||
_dateMapEquals(other.lastAccessed, lastAccessed) &&
|
||||
other.createdAt == createdAt &&
|
||||
other.lastUpdated == lastUpdated &&
|
||||
other.version == version;
|
||||
}
|
||||
|
||||
bool _mapEquals(Map<String, dynamic> a, Map<String, dynamic> b) {
|
||||
if (a.length != b.length) return false;
|
||||
for (final key in a.keys) {
|
||||
if (!b.containsKey(key) || a[key] != b[key]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _listEquals(List<String> a, List<String> b) {
|
||||
if (a.length != b.length) return false;
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
if (a[i] != b[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _dateMapEquals(Map<String, DateTime> a, Map<String, DateTime> b) {
|
||||
if (a.length != b.length) return false;
|
||||
for (final key in a.keys) {
|
||||
if (!b.containsKey(key) || a[key] != b[key]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return Object.hash(
|
||||
userId,
|
||||
displayName,
|
||||
email,
|
||||
avatarUrl,
|
||||
preferences.hashCode,
|
||||
favoriteItems.hashCode,
|
||||
lastAccessed.hashCode,
|
||||
createdAt,
|
||||
lastUpdated,
|
||||
version,
|
||||
);
|
||||
}
|
||||
}
|
||||
68
lib/core/database/models/user_preferences.g.dart
Normal file
68
lib/core/database/models/user_preferences.g.dart
Normal file
@@ -0,0 +1,68 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'user_preferences.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// TypeAdapterGenerator
|
||||
// **************************************************************************
|
||||
|
||||
class UserPreferencesAdapter extends TypeAdapter<UserPreferences> {
|
||||
@override
|
||||
final int typeId = 2;
|
||||
|
||||
@override
|
||||
UserPreferences read(BinaryReader reader) {
|
||||
final numOfFields = reader.readByte();
|
||||
final fields = <int, dynamic>{
|
||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||
};
|
||||
return UserPreferences(
|
||||
userId: fields[0] as String,
|
||||
displayName: fields[1] as String,
|
||||
email: fields[2] as String?,
|
||||
avatarUrl: fields[3] as String?,
|
||||
preferences: (fields[4] as Map).cast<String, dynamic>(),
|
||||
favoriteItems: (fields[5] as List).cast<String>(),
|
||||
lastAccessed: (fields[6] as Map).cast<String, DateTime>(),
|
||||
createdAt: fields[7] as DateTime,
|
||||
lastUpdated: fields[8] as DateTime,
|
||||
version: fields[9] as int,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, UserPreferences obj) {
|
||||
writer
|
||||
..writeByte(10)
|
||||
..writeByte(0)
|
||||
..write(obj.userId)
|
||||
..writeByte(1)
|
||||
..write(obj.displayName)
|
||||
..writeByte(2)
|
||||
..write(obj.email)
|
||||
..writeByte(3)
|
||||
..write(obj.avatarUrl)
|
||||
..writeByte(4)
|
||||
..write(obj.preferences)
|
||||
..writeByte(5)
|
||||
..write(obj.favoriteItems)
|
||||
..writeByte(6)
|
||||
..write(obj.lastAccessed)
|
||||
..writeByte(7)
|
||||
..write(obj.createdAt)
|
||||
..writeByte(8)
|
||||
..write(obj.lastUpdated)
|
||||
..writeByte(9)
|
||||
..write(obj.version);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => typeId.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is UserPreferencesAdapter &&
|
||||
runtimeType == other.runtimeType &&
|
||||
typeId == other.typeId;
|
||||
}
|
||||
Reference in New Issue
Block a user