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,447 @@
/// Performance optimization usage examples
///
/// This file demonstrates how to use all performance optimizations
/// in the retail POS app.
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../config/image_cache_config.dart';
import '../constants/performance_constants.dart';
import '../utils/debouncer.dart';
import '../utils/performance_monitor.dart';
import '../utils/provider_optimization.dart';
import '../utils/responsive_helper.dart';
import '../widgets/optimized_cached_image.dart';
import '../widgets/optimized_grid_view.dart';
import '../widgets/optimized_list_view.dart';
// ============================================================================
// EXAMPLE 1: Optimized Product Grid
// ============================================================================
class ProductGridExample extends ConsumerWidget {
const ProductGridExample({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
// Watch only the products list (granular rebuild)
final productsAsync = ref.watch(exampleProductsProvider);
return productsAsync.when(
data: (products) {
if (products.isEmpty) {
return const GridEmptyState(
message: 'No products found',
icon: Icons.inventory_2_outlined,
);
}
// Use optimized grid with automatic performance enhancements
return ProductGridView<ExampleProduct>(
products: products,
itemBuilder: (context, product, index) {
// Wrapped in RepaintBoundary automatically
return const ExampleProductCard();
},
onScrollEnd: () {
// Load more products when scrolling near end
// ref.read(exampleProductsProvider.notifier).loadMore();
},
);
},
loading: () => const GridLoadingState(itemCount: 6),
error: (error, stack) => GridEmptyState(
message: 'Failed to load products',
icon: Icons.error_outline,
onRetry: () {
ref.invalidate(exampleProductsProvider);
},
),
);
}
}
// ============================================================================
// EXAMPLE 2: Optimized Product Card with Cached Image
// ============================================================================
class ExampleProductCard extends StatelessWidget {
const ExampleProductCard({super.key});
@override
Widget build(BuildContext context) {
// Use const constructor for better performance
return Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Optimized cached image with automatic sizing
Expanded(
flex: 3,
child: ClipRRect(
borderRadius: const BorderRadius.vertical(
top: Radius.circular(12),
),
child: ProductGridImage(
imageUrl: 'https://example.com/product.jpg',
size: 150,
),
),
),
// Product details
const Expanded(
flex: 2,
child: Padding(
padding: EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Product Name',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
SizedBox(height: 4),
Text(
'\$99.99',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.green,
),
),
],
),
),
),
],
),
);
}
}
// ============================================================================
// EXAMPLE 3: Search with Debouncing
// ============================================================================
class ProductSearchExample extends ConsumerStatefulWidget {
const ProductSearchExample({super.key});
@override
ConsumerState<ProductSearchExample> createState() =>
_ProductSearchExampleState();
}
class _ProductSearchExampleState extends ConsumerState<ProductSearchExample> {
final _searchController = TextEditingController();
final _searchDebouncer = SearchDebouncer(); // 300ms debounce
@override
void dispose() {
_searchController.dispose();
_searchDebouncer.dispose();
super.dispose();
}
void _onSearchChanged(String query) {
// Debounce search to avoid excessive API calls
_searchDebouncer.run(() {
// Update search provider
// ref.read(searchQueryProvider.notifier).state = query;
});
}
@override
Widget build(BuildContext context) {
return TextField(
controller: _searchController,
onChanged: _onSearchChanged,
decoration: const InputDecoration(
hintText: 'Search products...',
prefixIcon: Icon(Icons.search),
border: OutlineInputBorder(),
),
);
}
}
// ============================================================================
// EXAMPLE 4: Optimized Cart List with Performance Tracking
// ============================================================================
class CartListExample extends ConsumerWidget {
const CartListExample({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
// Watch only cart items (not entire cart state)
final cartItems = ref.watchField(
exampleCartProvider,
(cart) => cart.items,
);
if (cartItems.isEmpty) {
return const ListEmptyState(
message: 'Your cart is empty',
icon: Icons.shopping_cart_outlined,
);
}
return CartListView<ExampleCartItem>(
items: cartItems,
itemBuilder: (context, item, index) {
return const ExampleCartItemCard();
},
);
}
}
class ExampleCartItemCard extends StatelessWidget {
const ExampleCartItemCard({super.key});
@override
Widget build(BuildContext context) {
return ListTile(
leading: const CartItemThumbnail(
imageUrl: 'https://example.com/product.jpg',
size: 60,
),
title: const Text('Product Name'),
subtitle: const Text('\$99.99'),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.remove_circle_outline),
onPressed: () {
// Decrease quantity
},
),
const Text('1'),
IconButton(
icon: const Icon(Icons.add_circle_outline),
onPressed: () {
// Increase quantity
},
),
],
),
);
}
}
// ============================================================================
// EXAMPLE 5: Responsive Grid with Adaptive Layout
// ============================================================================
class ResponsiveGridExample extends StatelessWidget {
const ResponsiveGridExample({super.key});
@override
Widget build(BuildContext context) {
// Get responsive values
final columns = context.gridColumns;
final spacing = context.spacing;
final padding = context.responsivePadding;
return Padding(
padding: padding,
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: columns,
crossAxisSpacing: spacing,
mainAxisSpacing: spacing,
childAspectRatio: PerformanceConstants.productCardAspectRatio,
),
itemBuilder: (context, index) {
return const RepaintBoundary(
child: ExampleProductCard(),
);
},
),
);
}
}
// ============================================================================
// EXAMPLE 6: Database Operations with Performance Tracking
// ============================================================================
class DatabaseExample {
Future<void> loadProductsWithTracking() async {
// Track async operation performance
final products = await PerformanceMonitor().trackAsync(
'loadProducts',
() async {
// Simulated database query
await Future.delayed(const Duration(milliseconds: 100));
return <ExampleProduct>[];
},
);
// Or use extension
final categories = await _loadCategories().trackPerformance('loadCategories');
}
Future<List<String>> _loadCategories() async {
await Future.delayed(const Duration(milliseconds: 50));
return ['Electronics', 'Clothing', 'Food'];
}
}
// ============================================================================
// EXAMPLE 7: Provider with Granular Rebuilds
// ============================================================================
// Provider example (would use riverpod_annotation in real app)
final exampleProductsProvider = Provider<List<ExampleProduct>>((ref) => []);
final exampleCartProvider = Provider<ExampleCart>((ref) => ExampleCart.empty());
// Optimized consumer that only rebuilds when name changes
class OptimizedConsumerExample extends ConsumerWidget {
const OptimizedConsumerExample({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
// Only rebuilds when product count changes
final productCount = ref.watchField(
exampleProductsProvider,
(products) => products.length,
);
return Text('Products: $productCount');
}
}
// ============================================================================
// EXAMPLE 8: Image Cache Management
// ============================================================================
class ImageCacheExample {
Future<void> clearCaches() async {
// Clear all image caches
await ImageOptimization.clearAllCaches();
}
Future<void> clearProductImages() async {
// Clear only product images
await ProductImageCacheManager().emptyCache();
}
Future<void> clearCategoryImages() async {
// Clear only category images
await CategoryImageCacheManager().emptyCache();
}
Future<int> getCacheSize() async {
// Get total cache size
return await ImageOptimization.getTotalCacheSize();
}
}
// ============================================================================
// EXAMPLE 9: Performance Monitoring
// ============================================================================
class PerformanceMonitoringExample extends StatefulWidget {
const PerformanceMonitoringExample({super.key});
@override
State<PerformanceMonitoringExample> createState() =>
_PerformanceMonitoringExampleState();
}
class _PerformanceMonitoringExampleState
extends State<PerformanceMonitoringExample> {
@override
Widget build(BuildContext context) {
return RebuildTracker(
name: 'PerformanceExample',
child: const Column(
children: [
Text('This widget rebuild count is tracked'),
],
),
);
}
Future<void> loadData() async {
// Track performance
await PerformanceMonitor().trackAsync(
'loadData',
() async {
await Future.delayed(const Duration(milliseconds: 200));
},
);
}
void calculateTotal() {
// Track synchronous operation
final total = PerformanceMonitor().track(
'calculateTotal',
() {
return 99.99;
},
);
}
@override
void dispose() {
// Print performance summary before disposing
PerformanceMonitor().printSummary();
RebuildTracker.printRebuildStats();
super.dispose();
}
}
// ============================================================================
// Models (for examples)
// ============================================================================
class ExampleProduct {
final String id;
final String name;
final double price;
final String? imageUrl;
const ExampleProduct({
required this.id,
required this.name,
required this.price,
this.imageUrl,
});
}
class ExampleCart {
final List<ExampleCartItem> items;
const ExampleCart({required this.items});
factory ExampleCart.empty() => const ExampleCart(items: []);
}
class ExampleCartItem {
final String productId;
final String name;
final double price;
final int quantity;
final String? imageUrl;
const ExampleCartItem({
required this.productId,
required this.name,
required this.price,
required this.quantity,
this.imageUrl,
});
}