This commit is contained in:
2025-09-26 18:48:14 +07:00
parent 382a0e7909
commit 30ed6b39b5
85 changed files with 20722 additions and 112 deletions

View 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,
);
}
}

View 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;
}

View 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(', ')}}';
}
}

View 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;
}

View 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,
);
}
}

View 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;
}