crash_safe_image 0.3.0
crash_safe_image: ^0.3.0 copied to clipboard
Crash-safe Flutter image widget with network, asset, file, memory & SVG support. Smart caching, placeholders, error UI, and safe ImageProvider.
crash_safe_image #
Crash‑safe image widget for Flutter. It auto‑detects image source (network / asset / file / memory), shows friendly placeholders & error UI, and uses cached_network_image for smart caching.
Minimal API · Safe defaults · Drop‑in replacement for many
Image.*cases
Table of contents #
- Features
- Why CrashSafeImage?
- Install
- Quick start
- How it decides the source
- API
- Examples
- Advanced Features (Phase 1)
- Platform support
- Performance notes
- Version compatibility
- Roadmap
- Contributing
- License
Features #
- ✅ Auto‑detects:
http/https→ network ·file:///absolute path → file · no scheme → asset ·bytes→ memory - ✅ SVG support: auto-detects
.svgfor network/asset/file/memory, powered byflutter_svg - ✅ Crash‑safe defaults: shows placeholder while loading and a clean error UI on failure
- ✅ Network caching via
cached_network_imagewith configurable size limits & retention periods - ✅ Progressive loading: show thumbnail first, then load full image for better perceived performance
- ✅ Image transformations: resize and crop operations without external tools
- ✅ Hero animations: smooth page-to-page transitions with single
heroTagparameter - ✅ Works in lists/grids with optional fade‑in/out
- ✅ ImageProvider getter for
CircleAvatar,DecorationImage(never-null with transparent fallback) - ✅ Customizable: size, fit, alignment, borderRadius, color, opacity, blend mode, HTTP headers & cacheKey
---Performance notes
Why Crash Safe Image #
- Stops avoidable crashes: invalid asset keys, missing files, empty/null sources → you get a friendly error UI instead of exceptions.
- One widget, four sources: network • asset • file • memory — no
if/elsesoup. - Better UX by default: placeholders and fade‑in/out already wired.
- Caches network images out of the box via
cached_network_image. - Works with existing APIs: grab
.providerforCircleAvatar/DecorationImage. - Easy to style:
fit,alignment,borderRadius,opacity,colorBlendMode. - Zero null checks for Avatar/Decoration:
provideris never null—bad/empty/SVG sources fall back to a transparent pixel. - Lean & tested: small surface area with widget tests.
When should I use it?
- Dynamic sources from API/user input where failures must not crash UI.
- Avatars, logos, list/grid images with consistent placeholders.
When might I not need it?
- You need custom decoding/stream control or web‑only file paths (until web‑safe mode ships).
Before vs After
// Before: branching + manual fallbacks
Widget buildAvatar(String? url) {
if (url == null || url.isEmpty) return const Icon(Icons.person);
return Image.network(url, errorBuilder: (_, __, ___) => const Icon(Icons.person));
}
// After: one line
CrashSafeImage(url, width: 40, height: 40, errorBuilder: (_) => const Icon(Icons.person));
Install #
Add to your pubspec.yaml:
dependencies:
crash_safe_image: ^0.3.0
Import:
import 'package:crash_safe_image/crash_safe_image.dart';
Quick start #
CrashSafeImage(
'https://example.com/pic.png',
width: 80,
height: 80,
placeholderBuilder: (_) => const Center(child: Text('Loading...')),
errorBuilder: (_) => const Icon(Icons.error_outline),
);
Using memory bytes (e.g., from camera/DB):
CrashSafeImage(
null,
bytes: myUint8List,
width: 120,
height: 120,
fit: BoxFit.cover,
);
Using as provider (e.g., for CircleAvatar):
CircleAvatar(
radius: 24,
backgroundImage: CrashSafeImage('https://example.com/avatar.png').provider, // never null
//No null checks needed—provider is always safe.
);
SVG examples
// Network SVG
CrashSafeImage.network('https://example.com/icon.svg', width: 40, height: 40);
// Asset SVG
CrashSafeImage.asset('assets/icons/logo.svg', width: 80);
// File SVG
CrashSafeImage.file(File('/storage/emulated/0/Download/icon.svg'));
// Raw SVG string
CrashSafeImage.svgString('<svg viewBox="0 0 24 24">...</svg>', width: 48);
How it decides the source #
- If
bytes != null && bytes.isNotEmpty→ MemoryImage - Else if
name == null || name.trim().isEmpty→ error UI - Else if
nameishttp/https→ CachedNetworkImage /CachedNetworkImageProvider - Else if
namelooks like a file path (e.g.,file://, absolute) → FileImage - Else → AssetImage
Note: If the asset path is wrong or the file doesn’t exist, the widget shows the error UI instead of crashing.
API #
Constructor parameters #
| Param | Type | Default | Notes |
|---|---|---|---|
name |
String? |
– | Path/URL/asset key. Can be null when using bytes. |
width, height |
double? |
– | Final rendered size. |
fit |
BoxFit? |
– | How to inscribe the image into the box. |
alignment |
AlignmentGeometry |
Alignment.center |
Alignment for the image. |
borderRadius |
BorderRadius? |
– | Rounded corners; applied via ClipRRect. |
clipBehavior |
Clip |
Clip.hardEdge |
Clip strategy for rounding. |
color |
Color? |
– | Color filter tint. |
opacity |
Animation<double>? |
– | Animated opacity for Image.*. |
colorBlendMode |
BlendMode? |
– | Blend mode with color. |
placeholderBuilder |
WidgetBuilder? |
built‑in spinner | Builder for loading state. |
errorBuilder |
WidgetBuilder? |
built‑in broken‑image icon | Builder for error state. |
httpHeaders |
Map<String, String>? |
– | Extra headers for network requests. |
cacheKey |
String? |
– | Custom cache key for network images. |
fadeInDuration |
Duration |
250ms |
Network fade‑in. |
fadeOutDuration |
Duration |
250ms |
Network fade‑out. |
bundle |
AssetBundle? |
– | Custom bundle for assets. |
package |
String? |
– | Asset package name. |
bytes |
Uint8List? |
– | Raw bytes (memory images). |
Using as ImageProvider #
Get a provider for places that need it (e.g., CircleAvatar, BoxDecoration):
final provider = CrashSafeImage('assets/logo.png').provider; // ImageProvider<Object>
The provider is never null. If the source is null/invalid/SVG, a 1×1 transparent
- MemoryImage is returned to keep Avatar/DecorationImage assertion-safe.
Custom placeholders & errors #
CrashSafeImage(
'https://invalid-url.example/broken.png',
width: 96,
height: 96,
placeholderBuilder: (_) => const Center(child: Text('Loading…')),
errorBuilder: (_) => const Icon(Icons.warning_amber_rounded, color: Colors.red),
);
Examples #
Basic
CrashSafeImage('assets/images/logo.png', width: 40, height: 40);
File path
CrashSafeImage('/storage/emulated/0/Download/picture.jpg', width: 120, height: 90);
DecorationImage
Container(
width: 160,
height: 100,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
image: DecorationImage(
image: CrashSafeImage('assets/bg.jpg').provider,
fit: BoxFit.cover,
),
),
);
Advanced Features (Phase 1) #
Progressive Loading #
Show a low-resolution thumbnail first, then seamlessly transition to the full image:
CrashSafeImage(
'https://example.com/full-res.jpg',
thumbnailUrl: 'https://example.com/thumbnail.jpg',
useProgressiveLoading: true,
width: 300,
height: 200,
);
Benefits:
- Better perceived performance
- Reduced data usage for slow connections
- Smooth visual experience
Image Transformations #
Apply resize and crop transformations without external tools:
// Resize transformation
CrashSafeImage(
'https://example.com/image.jpg',
transformations: [
ImageTransformation.resize(400, 300, fit: BoxFit.cover),
],
);
// Crop transformation
CrashSafeImage(
'https://example.com/image.jpg',
transformations: [
ImageTransformation.crop(Rect.fromLTWH(50, 50, 200, 200)),
],
);
// Multiple transformations
CrashSafeImage(
'https://example.com/image.jpg',
transformations: [
ImageTransformation.resize(600, 400),
ImageTransformation.crop(Rect.fromLTWH(100, 50, 400, 300)),
],
);
Enhanced Caching #
Control cache behavior globally or per-widget:
// Configure global cache settings (call once at app startup)
void main() {
// Use a preset configuration
CrashSafeImageCache.configure(CrashSafeImageCacheConfig.aggressive);
// Or create custom configuration
CrashSafeImageCache.configure(
CrashSafeImageCacheConfig(
maxNrOfCacheObjects: 300,
stalePeriod: Duration(days: 45),
),
);
runApp(MyApp());
}
// Use cache configuration in widget
CrashSafeImage(
'https://example.com/image.jpg',
cacheConfig: CrashSafeImageCacheConfig.conservative,
width: 200,
height: 200,
);
// Clear cache programmatically
await CrashSafeImageCache.clear();
// Remove specific image from cache
await CrashSafeImageCache.remove('https://example.com/image.jpg');
// Get cache statistics
final stats = await CrashSafeImageCache.getStats();
print('Max objects: ${stats['maxObjects']}');
print('Stale period: ${stats['stalePeriod']} days');
Cache presets:
default: 200 objects, 30 days retentionaggressive: 500 objects, 90 days retentionconservative: 50 objects, 7 days retentionminimal: 20 objects, 1 day retention
Hero Animations #
Enable smooth page-to-page transitions with a single parameter:
// Source page
CrashSafeImage(
'https://example.com/image.jpg',
width: 100,
height: 100,
heroTag: 'image_1',
);
// Destination page
CrashSafeImage(
'https://example.com/image.jpg',
width: 300,
height: 300,
heroTag: 'image_1', // Same tag creates the Hero animation
);
Benefits:
- Fluid user experience
- Professional transitions
- Works with all image types (network, asset, file, memory, SVG)
Platform support #
- Android/iOS, macOS, Windows ✅
- Web: not officially supported yet if your app path relies on
dart:iofile checks. A web‑safe mode is on the roadmap (conditional imports).
Network and asset images work on the web, but direct local file paths (
FileImage) do not.
Performance notes #
- The widget wraps content in a
SizedBox+ClipRRectfor reliable sizing and rounded corners. - Avoid extremely frequent rebuilds with changing
cacheKeyor headers. - For very large images in lists, set an explicit
width/heightandfitto reduce layout thrash. - Transparent fallback is a 1×1 PNG kept in memory; overhead is negligible.
Version compatibility #
- Dart SDK:
>=3.9.0 <4.0.0 - Flutter:
>=3.22.0 cached_network_image: ^3.4.1flutter_cache_manager: ^3.4.1(direct dependency for the cache presets)flutter_svg: ^2.0.0
See pubspec.yaml for full constraints.
Roadmap #
Phase 2 - Advanced Features (Planned) #
- Blur effects: Apply blur transformations (Gaussian, motion blur)
- Image filters: Brightness, contrast, saturation, grayscale
- Shimmer loading: Beautiful skeleton loading effect
- Retry mechanism: Auto-retry failed network loads with exponential backoff
- Bandwidth detection: Auto-adjust image quality based on connection speed
- Offline mode: Queue images for download when online
Phase 3 - Enterprise Features (Planned) #
- Memory pressure handling: Auto-clear cache on low memory
- Prefetching API: Preload images before they're needed
- Custom cache backends: S3, Firebase Storage integration
- Analytics hooks: Track load times, cache hits, failures
- Image optimization: Auto-convert to WebP on supported platforms
- CDN integration: Smart URL generation for image CDNs
Infrastructure #
- Web‑safe file detection (conditional
dart:ioimports) - More knobs for placeholders (colors, shapes)
- Additional tests for builders and error propagation
Have ideas? Open an issue or a PR.
Contributing #
PRs are welcome! Please run the checks before opening a PR:
dart format .
flutter analyze
flutter test
License #
MIT © DevsLoom — see LICENSE