Dart-only? We’ve separated the purely Dart-related helpers into
dart_helper_utils
. If you need those features in a non-Flutter environment (like a CLI app), feel free to use that package directly. Don’t worry—flutter_helper_utils
exports it internally, so you can still access all of the Dart helpers without changing your existing imports.
Add the dependency in your pubspec.yaml
:
dependencies:
flutter_helper_utils: <latest_version>
Then import it into your Dart code:
import 'package:flutter_helper_utils/flutter_helper_utils.dart';
You’ll also automatically get the dart_helper_utils
exports, so everything’s in one place.
A modern Web-compatible replacement for dart:io
's Platform
class that works seamlessly across all platforms, including web. The PlatformEnv
class provides:
// Simple platform checks
if (PlatformEnv.isIOS) {
// iOS-specific code
}
// Get detailed platform info
final report = PlatformEnv.report();
print('Operating System: ${report['operatingSystem']}');
// Access system properties
final processors = PlatformEnv.numberOfProcessors;
final pathSeparator = PlatformEnv.pathSeparator;
Enhanced ValueNotifier functionality with type-safe notifiers and convenient extensions:
- Create notifiers instantly from any value
- Type-safe specialized notifiers
- Simplified builder syntax
- Advanced collection handling
// Quick notifier creation
final counter = 0.notifier; // Creates IntNotifier
final isLoading = false.notifier; // Creates BoolNotifier
final items = <String>[].notifier; // Creates ListNotifier<String>
// Easy builder syntax
counter.builder((value) => Text('Count: $value'));
// Type-safe operations
counter.increment(); // Built-in methods for specific types
isLoading.toggle(); // Toggles boolean value
// Collection operations with automatic notifications
items.add('New Item'); // Notifies listeners automatically
A powerful, type-safe list view widget with built-in support for headers, footers, separators, and pagination:
- Type safety for list items
- Optional headers and footers
- Custom separators
- Built-in pagination support
- Optimized performance
TypedListView<Product>(
items: products,
itemBuilder: (context, product) => ProductCard(product: product),
headerBuilder: (context) => CategoryHeader(),
footerBuilder: (context) => LoadMoreButton(),
separatorBuilder: (context) => Divider(),
paginationWidget: CircularProgressIndicator(),
padding: EdgeInsets.all(16),
onScrollEnd: () => loadMoreProducts(),
);
Create responsive layouts for different screen sizes and platforms (mobile, tablet, desktop).
- Efficient: Rebuilds only when the platform type changes.
- Easy-to-use context extensions: Access platform/orientation information directly.
- Customizable: Define your own breakpoints and helper extensions.
- Layout builders: Convenient widgets for building adaptive UI.
PlatformTypeProvider( // Wrap your app
child: MyApp(),
); // optionally receive custom breakpoints.
@override
Widget build(BuildContext context) {
final breakpoint = context.breakpoint; // rebuilds on change.
return breakpoint.isMobile ? const MobileLayout() : const TabletLayout();
}
See the detailed documentation for adaptive ui to explore more.
// Get theme instance
final theme = context.themeData;
// Direct TextStyle access
Text('Some Text', style: theme.bodyMedium)
Text('Some Text', style: theme.titleLarge)
Text('Some Text', style: theme.labelSmall)
// Copy TextStyles with modifications
Text('Some Text', style: theme.labelSmallCopy(color: theme.primary))
// Direct ColorScheme access
final primary = theme.primary; // Instead of theme.colorScheme.primary
final onSurface = theme.onSurface; // Instead of theme.colorScheme.onSurface
final isLight = theme.isLight; // Check if light theme
A comprehensive suite of tools for color manipulation, conversion, and accessibility.
// Fluent API for modifying colors
final modifiedColor = Colors.blue
.setOpacity(0.8) // Set opacity from 0.0-1.0
.setRed(100) // Set red channel from 0-255
.lighten(0.1); // Lighten the result by 10%
// Convert any dynamic value to a Color
final fromJson = tryToColor(json['user_color']) ?? Colors.grey;
// Get a hex string
final hex = Colors.teal.toHex(includeAlpha: true); // #FF008080
// Check contrast for accessibility
final ratio = Colors.white.contrast(Colors.black); // 21.0
final isDark = myColor.isDark();
Generate beautiful, theory-based color schemes directly from any color.
// Triadic: 3 vibrant, evenly spaced colors
final triadicScheme = Colors.red.triadic();
// Analogous: 5 harmonious, adjacent colors
final analogousPalette = Colors.teal.analogous(count: 5, angle: 20);
// Monochromatic: 7 shades of the same color
final monoShades = Colors.indigo.monochromatic(count: 7);
// Split-Complementary: A high-contrast but balanced scheme
final splitComp = Colors.purple.splitComplementary();
Design inclusive apps with powerful accessibility tools.
// Check if text meets WCAG AA standard
final isAccessible = background.meetsWCAG(
textColor,
level: WCAGLevel.aa,
context: WCAGContext.normalText,
);
// Get suggested accessible colors for a background
final suggestions = Colors.deepPurple.suggestAccessibleColors();
final accessibleTextColor = suggestions.normalText;
final accessibleIconColor = suggestions.uiComponent;
// Simulate how a color appears with Protanopia (red-blindness)
final simulatedColor = Colors.red.simulateColorBlindness(ColorBlindnessType.protanopia);
// Check if two critical colors (e.g., for error/success states) are distinguishable
final areColorsSafe = errorRed.isDistinguishableFor(
successGreen,
ColorBlindnessType.deuteranopia, // Green-blind
);
Rich set of scroll controller extensions for enhanced scrolling functionality:
// Smooth scrolling animations
controller.animateToPosition(500.0);
controller.animateToBottom();
controller.smoothScrollTo(250.0);
// Percentage-based scrolling
controller.scrollToPercentage(0.5); // Scroll to 50%
// Position checks
if (controller.isAtTop) {
// At the top of the scroll view
}
if (controller.isNearBottom(threshold: 50)) {
// Near the bottom with custom threshold
}
// Get scroll progress
final progress = controller.scrollProgress; // 0.0 to 1.0
Simplified Future handling and AsyncSnapshot state management:
// Future extensions
myFuture.builder(
onLoading: () => LoadingSpinner(),
onSuccess: (data) => SuccessView(data),
onError: (error) => ErrorView(error),
);
// AsyncSnapshot extensions
snapshot.dataWhen(
loading: () => LoadingSpinner(),
error: (error) => ErrorView(error),
success: (data) => SuccessView(data),
);
// Navigation
context.pushPage(NewScreen());
context.pReplacement(ReplacementScreen());
context.popPage();
context.dismissActivePopup();
// Theme access
final theme = context.themeData;
final isDarkMode = context.isDark;
final primaryColor = theme.primaryColor;
// Media queries
final width = context.screenWidth;
final height = context.screenHeight;
final padding = context.padding;
final orientation = context.deviceOrientation;
// Focus handling
context.unFocus(); // Hide keyboard
context.requestFocus; // Request focus
// Scaffold interactions
context.showSnackBar(SnackBar(content: Text('Hello!')));
context.showMaterialBanner(MaterialBanner(...));
Type-safe number extensions for common UI operations:
// Create EdgeInsets
final padding = 16.edgeInsetsAll;
final horizontal = 8.edgeInsetsHorizontal;
// Create Padding widgets
final paddedWidget = 16.paddingAll(child: MyWidget());
// Border radius
final radius = 8.allCircular;
final topRadius = 12.onlyTopRounded;
final diagonal = 10.diagonalBLTR;
// Matrix transformations
final matrix = 45.rotationZ;
// Size creation
final size = 100.size;
final box = 50.squareBox;
// Constraints
final constraints = 200.boxConstraints;
A type-safe, high-performance list view widget with built-in support for headers, footers, separators, and pagination:
// Basic usage
TypedListView<Product>(
items: products,
itemBuilder: (context, product) => ProductCard(product),
);
// Advanced usage with all features
TypedListView<Product>(
items: products,
itemBuilder: (context, product) => ProductCard(product),
headerBuilder: (context) => CategoryHeader(),
footerBuilder: (context) => LoadMoreButton(),
separatorBuilder: (context) => const Divider(),
paginationWidget: const CircularProgressIndicator(),
padding: 16.edgeInsetsAll,
onScrollEnd: () => loadMoreProducts(),
);
Apply gradient effects to any widget with ease:
GradientWidget(
gradient: const LinearGradient(
colors: [Colors.blue, Colors.purple],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
child: const Text('Gradient Text'),
);
Detect and handle multi-tap gestures with configurable tap count:
MultiTapDetector(
tapCount: 2, // Double tap
onTap: () => print('Double tapped!'),
child: Container(
height: 100,
color: Colors.blue,
child: const Center(
child: Text('Double tap me!'),
),
),
);
Selectively disable visual feedback effects (splash, highlight, hover) for specific parts of your app:
// Disable all effects
ThemeWithoutEffects(
child: MyWidget(),
);
// Customize which effects to disable
ThemeWithoutEffects.custom(
disableSplash: true,
disableHighlight: true,
disableHover: false,
child: MyWidget(),
);
Enable adaptive UI features and platform-specific behavior:
PlatformTypeProvider(
// Optional custom breakpoints
breakpoints: const PlatformBreakpoints(
mobileMax: 600,
tabletMax: 1000,
),
child: MaterialApp(
home: Builder(
builder: (context) {
// Access platform info
final info = context.platformSizeInfo;
// Build responsive layout
return info.when(
mobile: () => MobileLayout(),
tablet: () => TabletLayout(),
desktop: () => DesktopLayout(),
);
},
),
),
);
Efficiently manage and respond to changes in multiple Listenable objects:
// Multiple controllers/notifiers
final controllers = [
textController,
scrollController,
valueNotifier,
];
ListenablesBuilder(
listenables: controllers,
builder: (context) {
return Column(
children: [
Text(textController.text),
Text('Scroll offset: ${scrollController.offset}'),
Text('Value: ${valueNotifier.value}'),
],
);
},
// Optional: Control when to rebuild
buildWhen: (previous, current) {
return previous != current; // default.
},
// Optional: Debounce rapid changes
threshold: const Duration(milliseconds: 100),
);
Enhanced file handling with robust MIME type detection and processing:
// Check file types
'image.png'.isImage; // true
'document.pdf'.isPDF; // true
'video.mp4'.isVideo; // true
// Get MIME type
final mimeType = 'file.jpg'.mimeType(); // 'image/jpeg'
Comprehensive platform detection across web and native platforms:
// Basic platform checks
context.isMobile; // true on iOS/Android
context.isDesktop; // true on Windows/macOS/Linux
context.isWeb; // true on web platforms
// Specific platform + web checks
context.isMobileWeb; // true on mobile browsers
context.isDesktopWeb; // true on desktop browsers
context.isIOSWeb; // true on iOS Safari
Utilities for theme manipulation and management:
// Remove specific effects
final cleanTheme = themeData.withoutEffects(
disableSplash: true,
disableHover: true,
);
// Access theme colors directly
final surface = theme.surface; // Instead of theme.colorScheme.surface
final primary = theme.primary; // Instead of theme.colorScheme.primary
The color channel modifier methods have been renamed for clarity:
Old API (Deprecated):
color.addOpacity(0.5) // Deprecated
color.addAlpha(128) // Deprecated
color.addRed(255) // Deprecated
color.addGreen(128) // Deprecated
color.addBlue(64) // Deprecated
New API:
color.setOpacity(0.5) // ✅ Clear intent: sets opacity to 0.5
color.setAlpha(128) // ✅ Clear intent: sets alpha to 128
color.setRed(255) // ✅ Clear intent: sets red channel to 255
color.setGreen(128) // ✅ Clear intent: sets green channel to 128
color.setBlue(64) // ✅ Clear intent: sets blue channel to 64
Migration Steps:
- Update to latest v8.x - old methods will show deprecation warnings
- Replace all
add*
calls withset*
equivalents - The deprecated methods will be removed in v9.0
Why this change?
- Clarity:
setOpacity
clearly indicates replacement, not addition - Consistency: Aligns with Flutter's naming conventions
- Future-proof: Prepares for Flutter's own API changes
Generate beautiful, harmonious color schemes based on color theory:
Available Harmonies:
// Complementary - opposite on color wheel (180°)
final opposite = Colors.blue.complementaryHarmony;
// Triadic - 3 colors evenly spaced (120° apart)
final triadic = Colors.red.triadic();
// Returns approximately [red, green, blue]
// Tetradic/Square - 4 colors evenly spaced (90° apart)
final tetradic = Colors.orange.tetradic();
// Split Complementary - base + 2 adjacent to complement
final split = Colors.purple.splitComplementary(angle: 30);
// Analogous - adjacent colors on the wheel
final analogous = Colors.teal.analogous(
count: 5, // Number of colors
angle: 30, // Degrees between colors
);
// Monochromatic - shades of the same hue
final mono = Colors.indigo.monochromatic(
count: 5,
lightnessRange: 0.7, // Variation in lightness
);
Ensure your colors meet Web Content Accessibility Guidelines:
Contrast Checking:
// Check if colors meet WCAG standards
final meetsAA = background.meetsWCAG(
textColor,
level: WCAGLevel.aa, // AA or AAA
context: WCAGContext.normalText, // or largeText, uiComponent
);
// Get accessible color suggestions
final suggestions = background.suggestAccessibleColors(
level: WCAGLevel.aaa,
);
// Use the suggestions
Text(
'Important text',
style: TextStyle(color: suggestions.normalText),
);
IconButton(
icon: Icon(Icons.help, color: suggestions.uiComponent),
onPressed: () {},
);
WCAG Guidelines:
- Normal text: AA requires 4.5:1, AAA requires 7:1
- Large text (18pt+/14pt+ bold): AA requires 3:1, AAA requires 4.5:1
- UI components: 3:1 minimum
Design inclusive interfaces that work for users with color vision deficiencies:
// Simulate how colors appear to users with color blindness
final protanopia = color.simulateColorBlindness(
ColorBlindnessType.protanopia, // Red-blind
);
final deuteranopia = color.simulateColorBlindness(
ColorBlindnessType.deuteranopia, // Green-blind
);
final tritanopia = color.simulateColorBlindness(
ColorBlindnessType.tritanopia, // Blue-blind
);
// Check if two colors are distinguishable
if (!errorRed.isDistinguishableFor(
successGreen,
ColorBlindnessType.protanopia,
minContrast: 3.0,
)) {
// Consider using different colors or additional indicators
}
// Real-world example: Status indicators
final statusColors = {
'error': Colors.red,
'warning': Colors.orange,
'success': Colors.green,
};
// Verify all status colors are distinguishable
for (final type in ColorBlindnessType.values) {
for (final entry1 in statusColors.entries) {
for (final entry2 in statusColors.entries) {
if (entry1.key != entry2.key) {
final distinguishable = entry1.value.isDistinguishableFor(
entry2.value,
type,
);
if (!distinguishable) {
print('${entry1.key} and ${entry2.key} may be confused by users with $type');
}
}
}
}
}
Contributions to this package are welcome. If you have any suggestions, issues, or feature requests, please create a pull request in the repository.
flutter_helper_utils
is available under the BSD 3-Clause License.
If this package saves you time or helps you ship faster, consider buying me a coffee. It goes a long way in helping maintain and improve these tools.