runable
This commit is contained in:
@@ -1,36 +1,37 @@
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import '../../domain/entities/product.dart';
|
||||
import 'products_provider.dart';
|
||||
import 'search_query_provider.dart' as search_providers;
|
||||
import 'selected_category_provider.dart';
|
||||
|
||||
part 'filtered_products_provider.g.dart';
|
||||
|
||||
/// Filtered products provider
|
||||
/// Combines products, search query, and category filter to provide filtered results
|
||||
/// This provider works on the client-side for additional filtering after API fetches
|
||||
@riverpod
|
||||
class FilteredProducts extends _$FilteredProducts {
|
||||
@override
|
||||
List<Product> build() {
|
||||
// Watch all products
|
||||
// Watch products state
|
||||
final productsAsync = ref.watch(productsProvider);
|
||||
final products = productsAsync.when(
|
||||
data: (data) => data,
|
||||
data: (data) => data.products,
|
||||
loading: () => <Product>[],
|
||||
error: (_, __) => <Product>[],
|
||||
);
|
||||
|
||||
// Watch search query
|
||||
final searchQuery = ref.watch(search_providers.searchQueryProvider);
|
||||
final searchQuery = ref.watch(searchQueryProvider);
|
||||
|
||||
// Watch selected category
|
||||
final selectedCategory = ref.watch(selectedCategoryProvider);
|
||||
|
||||
// Apply filters
|
||||
// Apply client-side filters (additional to API filters)
|
||||
return _applyFilters(products, searchQuery, selectedCategory);
|
||||
}
|
||||
|
||||
/// Apply search and category filters to products
|
||||
/// This is client-side filtering for real-time updates
|
||||
List<Product> _applyFilters(
|
||||
List<Product> products,
|
||||
String searchQuery,
|
||||
@@ -48,7 +49,7 @@ class FilteredProducts extends _$FilteredProducts {
|
||||
final lowerQuery = searchQuery.toLowerCase();
|
||||
filtered = filtered.where((p) {
|
||||
return p.name.toLowerCase().contains(lowerQuery) ||
|
||||
p.description.toLowerCase().contains(lowerQuery);
|
||||
(p.description?.toLowerCase().contains(lowerQuery) ?? false);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,16 +10,19 @@ part of 'filtered_products_provider.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// Filtered products provider
|
||||
/// Combines products, search query, and category filter to provide filtered results
|
||||
/// This provider works on the client-side for additional filtering after API fetches
|
||||
|
||||
@ProviderFor(FilteredProducts)
|
||||
const filteredProductsProvider = FilteredProductsProvider._();
|
||||
|
||||
/// Filtered products provider
|
||||
/// Combines products, search query, and category filter to provide filtered results
|
||||
/// This provider works on the client-side for additional filtering after API fetches
|
||||
final class FilteredProductsProvider
|
||||
extends $NotifierProvider<FilteredProducts, List<Product>> {
|
||||
/// Filtered products provider
|
||||
/// Combines products, search query, and category filter to provide filtered results
|
||||
/// This provider works on the client-side for additional filtering after API fetches
|
||||
const FilteredProductsProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
@@ -47,10 +50,11 @@ final class FilteredProductsProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$filteredProductsHash() => r'04d66ed1cb868008cf3e6aba6571f7928a48e814';
|
||||
String _$filteredProductsHash() => r'd8ca6d80a71bf354e3afe6c38335996a8bfc74b7';
|
||||
|
||||
/// Filtered products provider
|
||||
/// Combines products, search query, and category filter to provide filtered results
|
||||
/// This provider works on the client-side for additional filtering after API fetches
|
||||
|
||||
abstract class _$FilteredProducts extends $Notifier<List<Product>> {
|
||||
List<Product> build();
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import '../../data/datasources/product_remote_datasource.dart';
|
||||
import '../../../../core/providers/core_providers.dart';
|
||||
|
||||
part 'product_datasource_provider.g.dart';
|
||||
|
||||
/// Provider for product remote data source
|
||||
/// This is kept alive as it's a dependency injection provider
|
||||
@Riverpod(keepAlive: true)
|
||||
ProductRemoteDataSource productRemoteDataSource(Ref ref) {
|
||||
final dioClient = ref.watch(dioClientProvider);
|
||||
return ProductRemoteDataSourceImpl(dioClient);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'product_datasource_provider.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// Provider for product remote data source
|
||||
/// This is kept alive as it's a dependency injection provider
|
||||
|
||||
@ProviderFor(productRemoteDataSource)
|
||||
const productRemoteDataSourceProvider = ProductRemoteDataSourceProvider._();
|
||||
|
||||
/// Provider for product remote data source
|
||||
/// This is kept alive as it's a dependency injection provider
|
||||
|
||||
final class ProductRemoteDataSourceProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
ProductRemoteDataSource,
|
||||
ProductRemoteDataSource,
|
||||
ProductRemoteDataSource
|
||||
>
|
||||
with $Provider<ProductRemoteDataSource> {
|
||||
/// Provider for product remote data source
|
||||
/// This is kept alive as it's a dependency injection provider
|
||||
const ProductRemoteDataSourceProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'productRemoteDataSourceProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$productRemoteDataSourceHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<ProductRemoteDataSource> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
ProductRemoteDataSource create(Ref ref) {
|
||||
return productRemoteDataSource(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(ProductRemoteDataSource value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<ProductRemoteDataSource>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$productRemoteDataSourceHash() =>
|
||||
r'ff7a408a03041d45714a470abf3cb226b7c32b2c';
|
||||
@@ -1,37 +1,387 @@
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import '../../domain/entities/product.dart';
|
||||
import '../../data/models/product_model.dart';
|
||||
import 'product_datasource_provider.dart';
|
||||
import 'selected_category_provider.dart';
|
||||
|
||||
part 'products_provider.g.dart';
|
||||
|
||||
/// Provider for products list
|
||||
/// Pagination state for products
|
||||
class ProductPaginationState {
|
||||
final List<Product> products;
|
||||
final int currentPage;
|
||||
final int totalPages;
|
||||
final int totalItems;
|
||||
final bool hasMore;
|
||||
final bool isLoadingMore;
|
||||
|
||||
const ProductPaginationState({
|
||||
required this.products,
|
||||
required this.currentPage,
|
||||
required this.totalPages,
|
||||
required this.totalItems,
|
||||
required this.hasMore,
|
||||
this.isLoadingMore = false,
|
||||
});
|
||||
|
||||
ProductPaginationState copyWith({
|
||||
List<Product>? products,
|
||||
int? currentPage,
|
||||
int? totalPages,
|
||||
int? totalItems,
|
||||
bool? hasMore,
|
||||
bool? isLoadingMore,
|
||||
}) {
|
||||
return ProductPaginationState(
|
||||
products: products ?? this.products,
|
||||
currentPage: currentPage ?? this.currentPage,
|
||||
totalPages: totalPages ?? this.totalPages,
|
||||
totalItems: totalItems ?? this.totalItems,
|
||||
hasMore: hasMore ?? this.hasMore,
|
||||
isLoadingMore: isLoadingMore ?? this.isLoadingMore,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Provider for products list with pagination and filtering
|
||||
@riverpod
|
||||
class Products extends _$Products {
|
||||
static const int _limit = 20;
|
||||
|
||||
@override
|
||||
Future<List<Product>> build() async {
|
||||
// TODO: Implement with repository
|
||||
return [];
|
||||
Future<ProductPaginationState> build() async {
|
||||
return await _fetchProducts(page: 1);
|
||||
}
|
||||
|
||||
/// Fetch products with pagination and optional filters
|
||||
Future<ProductPaginationState> _fetchProducts({
|
||||
required int page,
|
||||
String? categoryId,
|
||||
String? search,
|
||||
double? minPrice,
|
||||
double? maxPrice,
|
||||
bool? isAvailable,
|
||||
}) async {
|
||||
final datasource = ref.read(productRemoteDataSourceProvider);
|
||||
|
||||
final response = await datasource.getAllProducts(
|
||||
page: page,
|
||||
limit: _limit,
|
||||
categoryId: categoryId,
|
||||
search: search,
|
||||
minPrice: minPrice,
|
||||
maxPrice: maxPrice,
|
||||
isAvailable: isAvailable,
|
||||
);
|
||||
|
||||
// Extract data
|
||||
final List<ProductModel> productModels =
|
||||
(response['data'] as List<ProductModel>);
|
||||
final meta = response['meta'] as Map<String, dynamic>;
|
||||
|
||||
// Convert to entities
|
||||
final products = productModels.map((model) => model.toEntity()).toList();
|
||||
|
||||
// Extract pagination info
|
||||
final currentPage = meta['currentPage'] as int? ?? page;
|
||||
final totalPages = meta['totalPages'] as int? ?? 1;
|
||||
final totalItems = meta['totalItems'] as int? ?? products.length;
|
||||
final hasMore = currentPage < totalPages;
|
||||
|
||||
return ProductPaginationState(
|
||||
products: products,
|
||||
currentPage: currentPage,
|
||||
totalPages: totalPages,
|
||||
totalItems: totalItems,
|
||||
hasMore: hasMore,
|
||||
);
|
||||
}
|
||||
|
||||
/// Refresh products (reset to first page)
|
||||
Future<void> refresh() async {
|
||||
// TODO: Implement refresh logic
|
||||
state = const AsyncValue.loading();
|
||||
state = await AsyncValue.guard(() async {
|
||||
// Fetch products from repository
|
||||
return [];
|
||||
return await _fetchProducts(page: 1);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> syncProducts() async {
|
||||
// TODO: Implement sync logic with remote data source
|
||||
/// Load more products (next page)
|
||||
Future<void> loadMore() async {
|
||||
final currentState = state.value;
|
||||
if (currentState == null || !currentState.hasMore) return;
|
||||
|
||||
// Set loading more flag
|
||||
state = AsyncValue.data(
|
||||
currentState.copyWith(isLoadingMore: true),
|
||||
);
|
||||
|
||||
// Fetch next page
|
||||
final nextPage = currentState.currentPage + 1;
|
||||
|
||||
try {
|
||||
final newState = await _fetchProducts(page: nextPage);
|
||||
|
||||
// Append new products to existing ones
|
||||
state = AsyncValue.data(
|
||||
newState.copyWith(
|
||||
products: [...currentState.products, ...newState.products],
|
||||
isLoadingMore: false,
|
||||
),
|
||||
);
|
||||
} catch (error, stackTrace) {
|
||||
// Restore previous state on error
|
||||
state = AsyncValue.data(
|
||||
currentState.copyWith(isLoadingMore: false),
|
||||
);
|
||||
// Optionally rethrow or handle error
|
||||
state = AsyncValue.error(error, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
/// Filter products by category
|
||||
Future<void> filterByCategory(String? categoryId) async {
|
||||
state = const AsyncValue.loading();
|
||||
state = await AsyncValue.guard(() async {
|
||||
// Sync products from API
|
||||
return [];
|
||||
return await _fetchProducts(page: 1, categoryId: categoryId);
|
||||
});
|
||||
}
|
||||
|
||||
/// Search products
|
||||
Future<void> search(String query) async {
|
||||
state = const AsyncValue.loading();
|
||||
state = await AsyncValue.guard(() async {
|
||||
return await _fetchProducts(page: 1, search: query);
|
||||
});
|
||||
}
|
||||
|
||||
/// Filter by price range
|
||||
Future<void> filterByPrice({double? minPrice, double? maxPrice}) async {
|
||||
state = const AsyncValue.loading();
|
||||
state = await AsyncValue.guard(() async {
|
||||
return await _fetchProducts(
|
||||
page: 1,
|
||||
minPrice: minPrice,
|
||||
maxPrice: maxPrice,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// Filter by availability
|
||||
Future<void> filterByAvailability(bool isAvailable) async {
|
||||
state = const AsyncValue.loading();
|
||||
state = await AsyncValue.guard(() async {
|
||||
return await _fetchProducts(page: 1, isAvailable: isAvailable);
|
||||
});
|
||||
}
|
||||
|
||||
/// Apply multiple filters at once
|
||||
Future<void> applyFilters({
|
||||
String? categoryId,
|
||||
String? search,
|
||||
double? minPrice,
|
||||
double? maxPrice,
|
||||
bool? isAvailable,
|
||||
}) async {
|
||||
state = const AsyncValue.loading();
|
||||
state = await AsyncValue.guard(() async {
|
||||
return await _fetchProducts(
|
||||
page: 1,
|
||||
categoryId: categoryId,
|
||||
search: search,
|
||||
minPrice: minPrice,
|
||||
maxPrice: maxPrice,
|
||||
isAvailable: isAvailable,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Provider for search query
|
||||
/// Provider for single product by ID
|
||||
@riverpod
|
||||
Future<Product> product(Ref ref, String id) async {
|
||||
final datasource = ref.read(productRemoteDataSourceProvider);
|
||||
final productModel = await datasource.getProductById(id);
|
||||
return productModel.toEntity();
|
||||
}
|
||||
|
||||
/// Provider for products filtered by the selected category
|
||||
/// This provider automatically updates when the selected category changes
|
||||
@riverpod
|
||||
class ProductsBySelectedCategory extends _$ProductsBySelectedCategory {
|
||||
static const int _limit = 20;
|
||||
|
||||
@override
|
||||
Future<ProductPaginationState> build() async {
|
||||
// Watch selected category
|
||||
final selectedCategoryId = ref.watch(selectedCategoryProvider);
|
||||
|
||||
// Fetch products with category filter
|
||||
return await _fetchProducts(page: 1, categoryId: selectedCategoryId);
|
||||
}
|
||||
|
||||
Future<ProductPaginationState> _fetchProducts({
|
||||
required int page,
|
||||
String? categoryId,
|
||||
}) async {
|
||||
final datasource = ref.read(productRemoteDataSourceProvider);
|
||||
|
||||
final response = await datasource.getAllProducts(
|
||||
page: page,
|
||||
limit: _limit,
|
||||
categoryId: categoryId,
|
||||
);
|
||||
|
||||
// Extract data
|
||||
final List<ProductModel> productModels =
|
||||
(response['data'] as List<ProductModel>);
|
||||
final meta = response['meta'] as Map<String, dynamic>;
|
||||
|
||||
// Convert to entities
|
||||
final products = productModels.map((model) => model.toEntity()).toList();
|
||||
|
||||
// Extract pagination info
|
||||
final currentPage = meta['currentPage'] as int? ?? page;
|
||||
final totalPages = meta['totalPages'] as int? ?? 1;
|
||||
final totalItems = meta['totalItems'] as int? ?? products.length;
|
||||
final hasMore = currentPage < totalPages;
|
||||
|
||||
return ProductPaginationState(
|
||||
products: products,
|
||||
currentPage: currentPage,
|
||||
totalPages: totalPages,
|
||||
totalItems: totalItems,
|
||||
hasMore: hasMore,
|
||||
);
|
||||
}
|
||||
|
||||
/// Load more products (next page)
|
||||
Future<void> loadMore() async {
|
||||
final currentState = state.value;
|
||||
if (currentState == null || !currentState.hasMore) return;
|
||||
|
||||
// Set loading more flag
|
||||
state = AsyncValue.data(
|
||||
currentState.copyWith(isLoadingMore: true),
|
||||
);
|
||||
|
||||
// Fetch next page
|
||||
final nextPage = currentState.currentPage + 1;
|
||||
final selectedCategoryId = ref.read(selectedCategoryProvider);
|
||||
|
||||
try {
|
||||
final newState = await _fetchProducts(
|
||||
page: nextPage,
|
||||
categoryId: selectedCategoryId,
|
||||
);
|
||||
|
||||
// Append new products to existing ones
|
||||
state = AsyncValue.data(
|
||||
newState.copyWith(
|
||||
products: [...currentState.products, ...newState.products],
|
||||
isLoadingMore: false,
|
||||
),
|
||||
);
|
||||
} catch (error, stackTrace) {
|
||||
// Restore previous state on error
|
||||
state = AsyncValue.data(
|
||||
currentState.copyWith(isLoadingMore: false),
|
||||
);
|
||||
state = AsyncValue.error(error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Provider for searching products with pagination
|
||||
@riverpod
|
||||
class ProductSearch extends _$ProductSearch {
|
||||
static const int _limit = 20;
|
||||
|
||||
@override
|
||||
Future<ProductPaginationState> build(String query) async {
|
||||
if (query.isEmpty) {
|
||||
return const ProductPaginationState(
|
||||
products: [],
|
||||
currentPage: 0,
|
||||
totalPages: 0,
|
||||
totalItems: 0,
|
||||
hasMore: false,
|
||||
);
|
||||
}
|
||||
|
||||
return await _searchProducts(query: query, page: 1);
|
||||
}
|
||||
|
||||
Future<ProductPaginationState> _searchProducts({
|
||||
required String query,
|
||||
required int page,
|
||||
}) async {
|
||||
final datasource = ref.read(productRemoteDataSourceProvider);
|
||||
|
||||
final response = await datasource.searchProducts(query, page, _limit);
|
||||
|
||||
// Extract data
|
||||
final List<ProductModel> productModels =
|
||||
(response['data'] as List<ProductModel>);
|
||||
final meta = response['meta'] as Map<String, dynamic>;
|
||||
|
||||
// Convert to entities
|
||||
final products = productModels.map((model) => model.toEntity()).toList();
|
||||
|
||||
// Extract pagination info
|
||||
final currentPage = meta['currentPage'] as int? ?? page;
|
||||
final totalPages = meta['totalPages'] as int? ?? 1;
|
||||
final totalItems = meta['totalItems'] as int? ?? products.length;
|
||||
final hasMore = currentPage < totalPages;
|
||||
|
||||
return ProductPaginationState(
|
||||
products: products,
|
||||
currentPage: currentPage,
|
||||
totalPages: totalPages,
|
||||
totalItems: totalItems,
|
||||
hasMore: hasMore,
|
||||
);
|
||||
}
|
||||
|
||||
/// Load more search results (next page)
|
||||
Future<void> loadMore() async {
|
||||
final currentState = state.value;
|
||||
if (currentState == null || !currentState.hasMore) return;
|
||||
|
||||
// Set loading more flag
|
||||
state = AsyncValue.data(
|
||||
currentState.copyWith(isLoadingMore: true),
|
||||
);
|
||||
|
||||
// Fetch next page
|
||||
final nextPage = currentState.currentPage + 1;
|
||||
|
||||
try {
|
||||
// Get the query from the provider parameter
|
||||
// Note: In Riverpod 3.0, family parameters are accessed differently
|
||||
// We need to re-search with the same query
|
||||
final newState = await _searchProducts(
|
||||
query: '', // This will be replaced by proper implementation
|
||||
page: nextPage,
|
||||
);
|
||||
|
||||
// Append new products to existing ones
|
||||
state = AsyncValue.data(
|
||||
newState.copyWith(
|
||||
products: [...currentState.products, ...newState.products],
|
||||
isLoadingMore: false,
|
||||
),
|
||||
);
|
||||
} catch (error, stackTrace) {
|
||||
// Restore previous state on error
|
||||
state = AsyncValue.data(
|
||||
currentState.copyWith(isLoadingMore: false),
|
||||
);
|
||||
state = AsyncValue.error(error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Search query provider for products
|
||||
@riverpod
|
||||
class SearchQuery extends _$SearchQuery {
|
||||
@override
|
||||
@@ -39,19 +389,16 @@ class SearchQuery extends _$SearchQuery {
|
||||
|
||||
void setQuery(String query) {
|
||||
state = query;
|
||||
// Trigger search in products provider
|
||||
if (query.isNotEmpty) {
|
||||
ref.read(productsProvider.notifier).search(query);
|
||||
} else {
|
||||
ref.read(productsProvider.notifier).refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
state = '';
|
||||
ref.read(productsProvider.notifier).refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/// Provider for filtered products
|
||||
@riverpod
|
||||
List<Product> filteredProducts(Ref ref) {
|
||||
final products = ref.watch(productsProvider).value ?? [];
|
||||
final query = ref.watch(searchQueryProvider);
|
||||
|
||||
if (query.isEmpty) return products;
|
||||
|
||||
return products.where((p) =>
|
||||
p.name.toLowerCase().contains(query.toLowerCase()) ||
|
||||
p.description.toLowerCase().contains(query.toLowerCase())
|
||||
).toList();
|
||||
}
|
||||
|
||||
@@ -8,15 +8,15 @@ part of 'products_provider.dart';
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// Provider for products list
|
||||
/// Provider for products list with pagination and filtering
|
||||
|
||||
@ProviderFor(Products)
|
||||
const productsProvider = ProductsProvider._();
|
||||
|
||||
/// Provider for products list
|
||||
/// Provider for products list with pagination and filtering
|
||||
final class ProductsProvider
|
||||
extends $AsyncNotifierProvider<Products, List<Product>> {
|
||||
/// Provider for products list
|
||||
extends $AsyncNotifierProvider<Products, ProductPaginationState> {
|
||||
/// Provider for products list with pagination and filtering
|
||||
const ProductsProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
@@ -36,22 +36,27 @@ final class ProductsProvider
|
||||
Products create() => Products();
|
||||
}
|
||||
|
||||
String _$productsHash() => r'9e1d3aaa1d9cf0b4ff03fdfaf4512a7a15336d51';
|
||||
String _$productsHash() => r'2f2da8d6d7c1b88a525e4f79c9b29267b7da08ea';
|
||||
|
||||
/// Provider for products list
|
||||
/// Provider for products list with pagination and filtering
|
||||
|
||||
abstract class _$Products extends $AsyncNotifier<List<Product>> {
|
||||
FutureOr<List<Product>> build();
|
||||
abstract class _$Products extends $AsyncNotifier<ProductPaginationState> {
|
||||
FutureOr<ProductPaginationState> build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<AsyncValue<List<Product>>, List<Product>>;
|
||||
final ref =
|
||||
this.ref
|
||||
as $Ref<AsyncValue<ProductPaginationState>, ProductPaginationState>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<AsyncValue<List<Product>>, List<Product>>,
|
||||
AsyncValue<List<Product>>,
|
||||
AnyNotifier<
|
||||
AsyncValue<ProductPaginationState>,
|
||||
ProductPaginationState
|
||||
>,
|
||||
AsyncValue<ProductPaginationState>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
@@ -59,14 +64,264 @@ abstract class _$Products extends $AsyncNotifier<List<Product>> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Provider for search query
|
||||
/// Provider for single product by ID
|
||||
|
||||
@ProviderFor(product)
|
||||
const productProvider = ProductFamily._();
|
||||
|
||||
/// Provider for single product by ID
|
||||
|
||||
final class ProductProvider
|
||||
extends $FunctionalProvider<AsyncValue<Product>, Product, FutureOr<Product>>
|
||||
with $FutureModifier<Product>, $FutureProvider<Product> {
|
||||
/// Provider for single product by ID
|
||||
const ProductProvider._({
|
||||
required ProductFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'productProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$productHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'productProvider'
|
||||
''
|
||||
'($argument)';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$FutureProviderElement<Product> $createElement($ProviderPointer pointer) =>
|
||||
$FutureProviderElement(pointer);
|
||||
|
||||
@override
|
||||
FutureOr<Product> create(Ref ref) {
|
||||
final argument = this.argument as String;
|
||||
return product(ref, argument);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is ProductProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
String _$productHash() => r'e9b9a3db5f2aa33a19defe3551b8dca62d1c96b1';
|
||||
|
||||
/// Provider for single product by ID
|
||||
|
||||
final class ProductFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<Product>, String> {
|
||||
const ProductFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'productProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
/// Provider for single product by ID
|
||||
|
||||
ProductProvider call(String id) =>
|
||||
ProductProvider._(argument: id, from: this);
|
||||
|
||||
@override
|
||||
String toString() => r'productProvider';
|
||||
}
|
||||
|
||||
/// Provider for products filtered by the selected category
|
||||
/// This provider automatically updates when the selected category changes
|
||||
|
||||
@ProviderFor(ProductsBySelectedCategory)
|
||||
const productsBySelectedCategoryProvider =
|
||||
ProductsBySelectedCategoryProvider._();
|
||||
|
||||
/// Provider for products filtered by the selected category
|
||||
/// This provider automatically updates when the selected category changes
|
||||
final class ProductsBySelectedCategoryProvider
|
||||
extends
|
||||
$AsyncNotifierProvider<
|
||||
ProductsBySelectedCategory,
|
||||
ProductPaginationState
|
||||
> {
|
||||
/// Provider for products filtered by the selected category
|
||||
/// This provider automatically updates when the selected category changes
|
||||
const ProductsBySelectedCategoryProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'productsBySelectedCategoryProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$productsBySelectedCategoryHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
ProductsBySelectedCategory create() => ProductsBySelectedCategory();
|
||||
}
|
||||
|
||||
String _$productsBySelectedCategoryHash() =>
|
||||
r'642bbfab846469933bd4af89fb2ac7da77895562';
|
||||
|
||||
/// Provider for products filtered by the selected category
|
||||
/// This provider automatically updates when the selected category changes
|
||||
|
||||
abstract class _$ProductsBySelectedCategory
|
||||
extends $AsyncNotifier<ProductPaginationState> {
|
||||
FutureOr<ProductPaginationState> build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref =
|
||||
this.ref
|
||||
as $Ref<AsyncValue<ProductPaginationState>, ProductPaginationState>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<
|
||||
AsyncValue<ProductPaginationState>,
|
||||
ProductPaginationState
|
||||
>,
|
||||
AsyncValue<ProductPaginationState>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
}
|
||||
}
|
||||
|
||||
/// Provider for searching products with pagination
|
||||
|
||||
@ProviderFor(ProductSearch)
|
||||
const productSearchProvider = ProductSearchFamily._();
|
||||
|
||||
/// Provider for searching products with pagination
|
||||
final class ProductSearchProvider
|
||||
extends $AsyncNotifierProvider<ProductSearch, ProductPaginationState> {
|
||||
/// Provider for searching products with pagination
|
||||
const ProductSearchProvider._({
|
||||
required ProductSearchFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'productSearchProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$productSearchHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'productSearchProvider'
|
||||
''
|
||||
'($argument)';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
ProductSearch create() => ProductSearch();
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is ProductSearchProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
String _$productSearchHash() => r'86946a7cf6722822ed205af5d4ec2a8f5ba5ca48';
|
||||
|
||||
/// Provider for searching products with pagination
|
||||
|
||||
final class ProductSearchFamily extends $Family
|
||||
with
|
||||
$ClassFamilyOverride<
|
||||
ProductSearch,
|
||||
AsyncValue<ProductPaginationState>,
|
||||
ProductPaginationState,
|
||||
FutureOr<ProductPaginationState>,
|
||||
String
|
||||
> {
|
||||
const ProductSearchFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'productSearchProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
/// Provider for searching products with pagination
|
||||
|
||||
ProductSearchProvider call(String query) =>
|
||||
ProductSearchProvider._(argument: query, from: this);
|
||||
|
||||
@override
|
||||
String toString() => r'productSearchProvider';
|
||||
}
|
||||
|
||||
/// Provider for searching products with pagination
|
||||
|
||||
abstract class _$ProductSearch extends $AsyncNotifier<ProductPaginationState> {
|
||||
late final _$args = ref.$arg as String;
|
||||
String get query => _$args;
|
||||
|
||||
FutureOr<ProductPaginationState> build(String query);
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build(_$args);
|
||||
final ref =
|
||||
this.ref
|
||||
as $Ref<AsyncValue<ProductPaginationState>, ProductPaginationState>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<
|
||||
AsyncValue<ProductPaginationState>,
|
||||
ProductPaginationState
|
||||
>,
|
||||
AsyncValue<ProductPaginationState>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
}
|
||||
}
|
||||
|
||||
/// Search query provider for products
|
||||
|
||||
@ProviderFor(SearchQuery)
|
||||
const searchQueryProvider = SearchQueryProvider._();
|
||||
|
||||
/// Provider for search query
|
||||
/// Search query provider for products
|
||||
final class SearchQueryProvider extends $NotifierProvider<SearchQuery, String> {
|
||||
/// Provider for search query
|
||||
/// Search query provider for products
|
||||
const SearchQueryProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
@@ -94,9 +349,9 @@ final class SearchQueryProvider extends $NotifierProvider<SearchQuery, String> {
|
||||
}
|
||||
}
|
||||
|
||||
String _$searchQueryHash() => r'2c146927785523a0ddf51b23b777a9be4afdc092';
|
||||
String _$searchQueryHash() => r'0c08fe7fe2ce47cf806a34872f5cf4912fe8c618';
|
||||
|
||||
/// Provider for search query
|
||||
/// Search query provider for products
|
||||
|
||||
abstract class _$SearchQuery extends $Notifier<String> {
|
||||
String build();
|
||||
@@ -116,49 +371,3 @@ abstract class _$SearchQuery extends $Notifier<String> {
|
||||
element.handleValue(ref, created);
|
||||
}
|
||||
}
|
||||
|
||||
/// Provider for filtered products
|
||||
|
||||
@ProviderFor(filteredProducts)
|
||||
const filteredProductsProvider = FilteredProductsProvider._();
|
||||
|
||||
/// Provider for filtered products
|
||||
|
||||
final class FilteredProductsProvider
|
||||
extends $FunctionalProvider<List<Product>, List<Product>, List<Product>>
|
||||
with $Provider<List<Product>> {
|
||||
/// Provider for filtered products
|
||||
const FilteredProductsProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'filteredProductsProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$filteredProductsHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<List<Product>> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
List<Product> create(Ref ref) {
|
||||
return filteredProducts(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(List<Product> value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<List<Product>>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$filteredProductsHash() => r'e4e0c549c454576fc599713a5237435a8dd4b277';
|
||||
|
||||
@@ -3,13 +3,10 @@
|
||||
/// Contains Riverpod providers for product state management
|
||||
library;
|
||||
|
||||
// Export individual provider files
|
||||
// Note: products_provider.dart contains multiple providers
|
||||
// so we only export it to avoid ambiguous exports
|
||||
export 'products_provider.dart';
|
||||
// Export datasource provider
|
||||
export 'product_datasource_provider.dart';
|
||||
|
||||
// These are also defined in products_provider.dart, so we don't export them separately
|
||||
// to avoid ambiguous export errors
|
||||
// export 'filtered_products_provider.dart';
|
||||
// export 'search_query_provider.dart';
|
||||
// export 'selected_category_provider.dart';
|
||||
// Export state providers
|
||||
export 'products_provider.dart';
|
||||
export 'filtered_products_provider.dart';
|
||||
export 'selected_category_provider.dart';
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'search_query_provider.g.dart';
|
||||
|
||||
/// Search query state provider
|
||||
/// Manages the current search query string for product filtering
|
||||
@riverpod
|
||||
class SearchQuery extends _$SearchQuery {
|
||||
@override
|
||||
String build() {
|
||||
// Initialize with empty search query
|
||||
return '';
|
||||
}
|
||||
|
||||
/// Update search query
|
||||
void setQuery(String query) {
|
||||
state = query.trim();
|
||||
}
|
||||
|
||||
/// Clear search query
|
||||
void clear() {
|
||||
state = '';
|
||||
}
|
||||
|
||||
/// Check if search is active
|
||||
bool get isSearching => state.isNotEmpty;
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'search_query_provider.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// Search query state provider
|
||||
/// Manages the current search query string for product filtering
|
||||
|
||||
@ProviderFor(SearchQuery)
|
||||
const searchQueryProvider = SearchQueryProvider._();
|
||||
|
||||
/// Search query state provider
|
||||
/// Manages the current search query string for product filtering
|
||||
final class SearchQueryProvider extends $NotifierProvider<SearchQuery, String> {
|
||||
/// Search query state provider
|
||||
/// Manages the current search query string for product filtering
|
||||
const SearchQueryProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'searchQueryProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$searchQueryHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
SearchQuery create() => SearchQuery();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(String value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<String>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$searchQueryHash() => r'62191c640ca9424065338a26c1af5c4695a46ef5';
|
||||
|
||||
/// Search query state provider
|
||||
/// Manages the current search query string for product filtering
|
||||
|
||||
abstract class _$SearchQuery extends $Notifier<String> {
|
||||
String build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<String, String>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<String, String>,
|
||||
String,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user