asdasdasd
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
import 'dart:convert';
|
||||
import 'package:hive_ce/hive.dart';
|
||||
import '../models/product_model.dart';
|
||||
|
||||
/// Abstract interface for products local data source
|
||||
abstract class ProductsLocalDataSource {
|
||||
/// Get cached products for a specific warehouse and operation type
|
||||
///
|
||||
/// [warehouseId] - The ID of the warehouse
|
||||
/// [type] - The operation type ('import' or 'export')
|
||||
///
|
||||
/// Returns List<ProductModel> from cache or empty list if not found
|
||||
Future<List<ProductModel>> getCachedProducts(int warehouseId, String type);
|
||||
|
||||
/// Cache products for a specific warehouse and operation type
|
||||
///
|
||||
/// [warehouseId] - The ID of the warehouse
|
||||
/// [type] - The operation type ('import' or 'export')
|
||||
/// [products] - List of products to cache
|
||||
Future<void> cacheProducts(
|
||||
int warehouseId,
|
||||
String type,
|
||||
List<ProductModel> products,
|
||||
);
|
||||
|
||||
/// Clear all cached products
|
||||
Future<void> clearCache();
|
||||
|
||||
/// Clear cached products for a specific warehouse and operation type
|
||||
Future<void> clearCachedProducts(int warehouseId, String type);
|
||||
}
|
||||
|
||||
/// Implementation of ProductsLocalDataSource using Hive
|
||||
class ProductsLocalDataSourceImpl implements ProductsLocalDataSource {
|
||||
static const String _boxName = 'products_cache';
|
||||
Box<String>? _box;
|
||||
|
||||
/// Initialize the Hive box
|
||||
Future<void> init() async {
|
||||
if (_box == null || !_box!.isOpen) {
|
||||
_box = await Hive.openBox<String>(_boxName);
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate cache key for warehouse and operation type
|
||||
String _getCacheKey(int warehouseId, String type) {
|
||||
return 'products_${warehouseId}_$type';
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<ProductModel>> getCachedProducts(
|
||||
int warehouseId,
|
||||
String type,
|
||||
) async {
|
||||
await init();
|
||||
|
||||
final key = _getCacheKey(warehouseId, type);
|
||||
final cachedData = _box?.get(key);
|
||||
|
||||
if (cachedData == null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
// Decode JSON string to list
|
||||
final jsonList = jsonDecode(cachedData) as List;
|
||||
|
||||
// Convert JSON list to ProductModel list
|
||||
return jsonList
|
||||
.map((json) => ProductModel.fromJson(json as Map<String, dynamic>))
|
||||
.toList();
|
||||
} catch (e) {
|
||||
// If parsing fails, return empty list
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> cacheProducts(
|
||||
int warehouseId,
|
||||
String type,
|
||||
List<ProductModel> products,
|
||||
) async {
|
||||
await init();
|
||||
|
||||
final key = _getCacheKey(warehouseId, type);
|
||||
|
||||
// Convert products to JSON list
|
||||
final jsonList = products.map((product) => product.toJson()).toList();
|
||||
|
||||
// Encode to JSON string and save
|
||||
final jsonString = jsonEncode(jsonList);
|
||||
await _box?.put(key, jsonString);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> clearCache() async {
|
||||
await init();
|
||||
await _box?.clear();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> clearCachedProducts(int warehouseId, String type) async {
|
||||
await init();
|
||||
|
||||
final key = _getCacheKey(warehouseId, type);
|
||||
await _box?.delete(key);
|
||||
}
|
||||
}
|
||||
@@ -4,32 +4,69 @@ import '../../../../core/errors/failures.dart';
|
||||
import '../../domain/entities/product_entity.dart';
|
||||
import '../../domain/entities/product_stage_entity.dart';
|
||||
import '../../domain/repositories/products_repository.dart';
|
||||
import '../datasources/products_local_datasource.dart';
|
||||
import '../datasources/products_remote_datasource.dart';
|
||||
import '../models/create_product_warehouse_request.dart';
|
||||
import '../models/product_detail_request_model.dart';
|
||||
|
||||
/// Implementation of ProductsRepository
|
||||
/// Handles data operations and error conversion
|
||||
/// Uses local-first approach: loads from cache first, only fetches from API on explicit refresh
|
||||
class ProductsRepositoryImpl implements ProductsRepository {
|
||||
final ProductsRemoteDataSource remoteDataSource;
|
||||
final ProductsLocalDataSource localDataSource;
|
||||
|
||||
ProductsRepositoryImpl(this.remoteDataSource);
|
||||
ProductsRepositoryImpl({
|
||||
required this.remoteDataSource,
|
||||
required this.localDataSource,
|
||||
});
|
||||
|
||||
@override
|
||||
Future<Either<Failure, List<ProductEntity>>> getProducts(
|
||||
int warehouseId,
|
||||
String type,
|
||||
) async {
|
||||
String type, {
|
||||
bool forceRefresh = false,
|
||||
}) async {
|
||||
try {
|
||||
// Fetch products from remote data source
|
||||
// If not forcing refresh, try to get from cache first
|
||||
if (!forceRefresh) {
|
||||
final cachedProducts =
|
||||
await localDataSource.getCachedProducts(warehouseId, type);
|
||||
|
||||
// If we have cached data, return it immediately
|
||||
if (cachedProducts.isNotEmpty) {
|
||||
return Right(cachedProducts.map((model) => model.toEntity()).toList());
|
||||
}
|
||||
}
|
||||
|
||||
// If forcing refresh or no cached data, fetch from remote
|
||||
final products = await remoteDataSource.getProducts(warehouseId, type);
|
||||
|
||||
// Cache the fetched products for future use
|
||||
await localDataSource.cacheProducts(warehouseId, type, products);
|
||||
|
||||
// Convert models to entities and return success
|
||||
return Right(products.map((model) => model.toEntity()).toList());
|
||||
} on ServerException catch (e) {
|
||||
// If remote fetch fails, try to return cached data as fallback
|
||||
if (forceRefresh) {
|
||||
final cachedProducts =
|
||||
await localDataSource.getCachedProducts(warehouseId, type);
|
||||
if (cachedProducts.isNotEmpty) {
|
||||
// Return cached data with a note that it might be outdated
|
||||
return Right(cachedProducts.map((model) => model.toEntity()).toList());
|
||||
}
|
||||
}
|
||||
// Convert ServerException to ServerFailure
|
||||
return Left(ServerFailure(e.message));
|
||||
} on NetworkException catch (e) {
|
||||
// If network fails, try to return cached data as fallback
|
||||
final cachedProducts =
|
||||
await localDataSource.getCachedProducts(warehouseId, type);
|
||||
if (cachedProducts.isNotEmpty) {
|
||||
// Return cached data when network is unavailable
|
||||
return Right(cachedProducts.map((model) => model.toEntity()).toList());
|
||||
}
|
||||
// Convert NetworkException to NetworkFailure
|
||||
return Left(NetworkFailure(e.message));
|
||||
} catch (e) {
|
||||
|
||||
Reference in New Issue
Block a user