This commit is contained in:
Phuoc Nguyen
2025-10-10 16:38:07 +07:00
parent e5b247d622
commit b94c158004
177 changed files with 25080 additions and 152 deletions

View File

@@ -0,0 +1,37 @@
import 'package:hive_ce/hive.dart';
import '../models/category_model.dart';
/// Category local data source using Hive
abstract class CategoryLocalDataSource {
Future<List<CategoryModel>> getAllCategories();
Future<CategoryModel?> getCategoryById(String id);
Future<void> cacheCategories(List<CategoryModel> categories);
Future<void> clearCategories();
}
class CategoryLocalDataSourceImpl implements CategoryLocalDataSource {
final Box<CategoryModel> box;
CategoryLocalDataSourceImpl(this.box);
@override
Future<List<CategoryModel>> getAllCategories() async {
return box.values.toList();
}
@override
Future<CategoryModel?> getCategoryById(String id) async {
return box.get(id);
}
@override
Future<void> cacheCategories(List<CategoryModel> categories) async {
final categoryMap = {for (var c in categories) c.id: c};
await box.putAll(categoryMap);
}
@override
Future<void> clearCategories() async {
await box.clear();
}
}

View File

@@ -0,0 +1,112 @@
import 'package:hive_ce/hive.dart';
import '../../domain/entities/category.dart';
import '../../../../core/constants/storage_constants.dart';
part 'category_model.g.dart';
@HiveType(typeId: StorageConstants.categoryTypeId)
class CategoryModel extends HiveObject {
@HiveField(0)
final String id;
@HiveField(1)
final String name;
@HiveField(2)
final String? description;
@HiveField(3)
final String? iconPath;
@HiveField(4)
final String? color;
@HiveField(5)
final int productCount;
@HiveField(6)
final DateTime createdAt;
CategoryModel({
required this.id,
required this.name,
this.description,
this.iconPath,
this.color,
required this.productCount,
required this.createdAt,
});
/// Convert to domain entity
Category toEntity() {
return Category(
id: id,
name: name,
description: description,
iconPath: iconPath,
color: color,
productCount: productCount,
createdAt: createdAt,
);
}
/// Create from domain entity
factory CategoryModel.fromEntity(Category category) {
return CategoryModel(
id: category.id,
name: category.name,
description: category.description,
iconPath: category.iconPath,
color: category.color,
productCount: category.productCount,
createdAt: category.createdAt,
);
}
/// Create from JSON
factory CategoryModel.fromJson(Map<String, dynamic> json) {
return CategoryModel(
id: json['id'] as String,
name: json['name'] as String,
description: json['description'] as String?,
iconPath: json['iconPath'] as String?,
color: json['color'] as String?,
productCount: json['productCount'] as int,
createdAt: DateTime.parse(json['createdAt'] as String),
);
}
/// Convert to JSON
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'description': description,
'iconPath': iconPath,
'color': color,
'productCount': productCount,
'createdAt': createdAt.toIso8601String(),
};
}
/// Create a copy with updated fields
CategoryModel copyWith({
String? id,
String? name,
String? description,
String? iconPath,
String? color,
int? productCount,
DateTime? createdAt,
}) {
return CategoryModel(
id: id ?? this.id,
name: name ?? this.name,
description: description ?? this.description,
iconPath: iconPath ?? this.iconPath,
color: color ?? this.color,
productCount: productCount ?? this.productCount,
createdAt: createdAt ?? this.createdAt,
);
}
}

View File

@@ -0,0 +1,59 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'category_model.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class CategoryModelAdapter extends TypeAdapter<CategoryModel> {
@override
final typeId = 1;
@override
CategoryModel read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return CategoryModel(
id: fields[0] as String,
name: fields[1] as String,
description: fields[2] as String?,
iconPath: fields[3] as String?,
color: fields[4] as String?,
productCount: (fields[5] as num).toInt(),
createdAt: fields[6] as DateTime,
);
}
@override
void write(BinaryWriter writer, CategoryModel obj) {
writer
..writeByte(7)
..writeByte(0)
..write(obj.id)
..writeByte(1)
..write(obj.name)
..writeByte(2)
..write(obj.description)
..writeByte(3)
..write(obj.iconPath)
..writeByte(4)
..write(obj.color)
..writeByte(5)
..write(obj.productCount)
..writeByte(6)
..write(obj.createdAt);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is CategoryModelAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}

View File

@@ -0,0 +1,49 @@
import 'package:dartz/dartz.dart';
import '../../domain/entities/category.dart';
import '../../domain/repositories/category_repository.dart';
import '../datasources/category_local_datasource.dart';
import '../../../../core/errors/failures.dart';
import '../../../../core/errors/exceptions.dart';
class CategoryRepositoryImpl implements CategoryRepository {
final CategoryLocalDataSource localDataSource;
CategoryRepositoryImpl({
required this.localDataSource,
});
@override
Future<Either<Failure, List<Category>>> getAllCategories() async {
try {
final categories = await localDataSource.getAllCategories();
return Right(categories.map((model) => model.toEntity()).toList());
} on CacheException catch (e) {
return Left(CacheFailure(e.message));
}
}
@override
Future<Either<Failure, Category>> getCategoryById(String id) async {
try {
final category = await localDataSource.getCategoryById(id);
if (category == null) {
return Left(NotFoundFailure('Category not found'));
}
return Right(category.toEntity());
} on CacheException catch (e) {
return Left(CacheFailure(e.message));
}
}
@override
Future<Either<Failure, List<Category>>> syncCategories() async {
try {
// For now, return cached categories
// In the future, implement remote sync
final categories = await localDataSource.getAllCategories();
return Right(categories.map((model) => model.toEntity()).toList());
} on CacheException catch (e) {
return Left(CacheFailure(e.message));
}
}
}