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,274 @@
/// Responsive layout utilities for optimal performance across devices
///
/// Features:
/// - Breakpoint-based layouts
/// - Adaptive grid columns
/// - Performance-optimized responsive widgets
/// - Device-specific optimizations
import 'package:flutter/material.dart';
import '../constants/performance_constants.dart';
/// Responsive helper for device-specific optimizations
class ResponsiveHelper {
/// Check if device is mobile
static bool isMobile(BuildContext context) {
return MediaQuery.of(context).size.width < PerformanceConstants.mobileBreakpoint;
}
/// Check if device is tablet
static bool isTablet(BuildContext context) {
final width = MediaQuery.of(context).size.width;
return width >= PerformanceConstants.mobileBreakpoint &&
width < PerformanceConstants.desktopBreakpoint;
}
/// Check if device is desktop
static bool isDesktop(BuildContext context) {
return MediaQuery.of(context).size.width >= PerformanceConstants.desktopBreakpoint;
}
/// Get appropriate grid column count
static int getGridColumns(BuildContext context) {
final width = MediaQuery.of(context).size.width;
return PerformanceConstants.getGridColumnCount(width);
}
/// Get appropriate cache extent
static double getCacheExtent(BuildContext context) {
final height = MediaQuery.of(context).size.height;
return PerformanceConstants.getCacheExtent(height);
}
/// Check if high performance mode should be enabled
static bool shouldUseHighPerformance(BuildContext context) {
final width = MediaQuery.of(context).size.width;
return PerformanceConstants.shouldUseHighPerformanceMode(width);
}
/// Get value based on screen size
static T getValue<T>(
BuildContext context, {
required T mobile,
T? tablet,
T? desktop,
}) {
if (isDesktop(context) && desktop != null) return desktop;
if (isTablet(context) && tablet != null) return tablet;
return mobile;
}
/// Get responsive padding
static EdgeInsets getResponsivePadding(BuildContext context) {
if (isDesktop(context)) {
return const EdgeInsets.all(24);
} else if (isTablet(context)) {
return const EdgeInsets.all(16);
} else {
return const EdgeInsets.all(12);
}
}
/// Get responsive spacing
static double getSpacing(BuildContext context) {
if (isDesktop(context)) return 16;
if (isTablet(context)) return 12;
return 8;
}
}
/// Responsive layout builder with performance optimization
class ResponsiveLayout extends StatelessWidget {
final Widget mobile;
final Widget? tablet;
final Widget? desktop;
const ResponsiveLayout({
super.key,
required this.mobile,
this.tablet,
this.desktop,
});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth >= PerformanceConstants.desktopBreakpoint) {
return desktop ?? tablet ?? mobile;
} else if (constraints.maxWidth >= PerformanceConstants.mobileBreakpoint) {
return tablet ?? mobile;
} else {
return mobile;
}
},
);
}
}
/// Responsive value builder
class ResponsiveValue<T> extends StatelessWidget {
final T mobile;
final T? tablet;
final T? desktop;
final Widget Function(BuildContext context, T value) builder;
const ResponsiveValue({
super.key,
required this.mobile,
this.tablet,
this.desktop,
required this.builder,
});
@override
Widget build(BuildContext context) {
final value = ResponsiveHelper.getValue(
context,
mobile: mobile,
tablet: tablet,
desktop: desktop,
);
return builder(context, value);
}
}
/// Adaptive grid configuration
class AdaptiveGridConfig {
final int crossAxisCount;
final double childAspectRatio;
final double spacing;
final double cacheExtent;
const AdaptiveGridConfig({
required this.crossAxisCount,
required this.childAspectRatio,
required this.spacing,
required this.cacheExtent,
});
factory AdaptiveGridConfig.fromContext(
BuildContext context, {
GridType type = GridType.products,
}) {
final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height;
return AdaptiveGridConfig(
crossAxisCount: PerformanceConstants.getGridColumnCount(width),
childAspectRatio: type == GridType.products
? PerformanceConstants.productCardAspectRatio
: PerformanceConstants.categoryCardAspectRatio,
spacing: PerformanceConstants.gridSpacing,
cacheExtent: PerformanceConstants.getCacheExtent(height),
);
}
}
enum GridType {
products,
categories,
}
/// Responsive grid view that adapts to screen size
class AdaptiveGridView<T> extends StatelessWidget {
final List<T> items;
final Widget Function(BuildContext context, T item, int index) itemBuilder;
final GridType type;
final ScrollController? scrollController;
final EdgeInsets? padding;
const AdaptiveGridView({
super.key,
required this.items,
required this.itemBuilder,
this.type = GridType.products,
this.scrollController,
this.padding,
});
@override
Widget build(BuildContext context) {
final config = AdaptiveGridConfig.fromContext(context, type: type);
return GridView.builder(
controller: scrollController,
padding: padding ?? ResponsiveHelper.getResponsivePadding(context),
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics(),
),
cacheExtent: config.cacheExtent,
itemCount: items.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: config.crossAxisCount,
crossAxisSpacing: config.spacing,
mainAxisSpacing: config.spacing,
childAspectRatio: config.childAspectRatio,
),
itemBuilder: (context, index) {
final item = items[index];
return RepaintBoundary(
key: ValueKey('adaptive_grid_item_$index'),
child: itemBuilder(context, item, index),
);
},
);
}
}
/// Responsive container with adaptive sizing
class ResponsiveContainer extends StatelessWidget {
final Widget child;
final double? mobileWidth;
final double? tabletWidth;
final double? desktopWidth;
const ResponsiveContainer({
super.key,
required this.child,
this.mobileWidth,
this.tabletWidth,
this.desktopWidth,
});
@override
Widget build(BuildContext context) {
final width = ResponsiveHelper.getValue(
context,
mobile: mobileWidth,
tablet: tabletWidth,
desktop: desktopWidth,
);
return Container(
width: width,
child: child,
);
}
}
/// Extension for easier responsive values
extension ResponsiveContextExtension on BuildContext {
bool get isMobile => ResponsiveHelper.isMobile(this);
bool get isTablet => ResponsiveHelper.isTablet(this);
bool get isDesktop => ResponsiveHelper.isDesktop(this);
int get gridColumns => ResponsiveHelper.getGridColumns(this);
double get cacheExtent => ResponsiveHelper.getCacheExtent(this);
double get spacing => ResponsiveHelper.getSpacing(this);
EdgeInsets get responsivePadding => ResponsiveHelper.getResponsivePadding(this);
T responsive<T>({
required T mobile,
T? tablet,
T? desktop,
}) {
return ResponsiveHelper.getValue(
this,
mobile: mobile,
tablet: tablet,
desktop: desktop,
);
}
}