448 lines
13 KiB
Dart
448 lines
13 KiB
Dart
/// 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,
|
|
});
|
|
}
|