runable
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
112
lib/features/categories/data/models/category_model.dart
Normal file
112
lib/features/categories/data/models/category_model.dart
Normal 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
59
lib/features/categories/data/models/category_model.g.dart
Normal file
59
lib/features/categories/data/models/category_model.g.dart
Normal 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;
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user