Skip to main content

secure_gateway_image 0.0.2 copy "secure_gateway_image: ^0.0.2" to clipboard
secure_gateway_image: ^0.0.2 copied to clipboard

Error-resilient Flutter image widget with network, local cache, asset, and animated initials fallback support.

secure_gateway_image #

Error-resilient image fallback widget for Flutter.

Created and maintained by Rajat Das.

An error-resilient Flutter image widget with a deterministic fallback pipeline:

Network → Local Cache → Asset → Animated Initials Avatar

pub package pub points popularity license

An error-resilient Flutter image widget with a deterministic fallback pipeline:

Network → Local Cache → Asset → Animated Initials Avatar

secure_gateway_image is designed for profile pictures, chat avatars, feed images, business pages, product images, and other UI components where a failed image source should never result in a broken-image UI.


✨ Features #

  • 🌐 Network image as the primary source
  • 💾 Local ImageProvider fallback
  • 📦 Flutter asset fallback
  • 👤 Animated initials avatar as the final fallback
  • 🎨 Deterministic avatar colors
  • ✨ Animated avatar entrance
  • 🧩 Custom avatar builder
  • ⏳ Loading placeholder support
  • 🔐 Network request headers
  • 🖼️ Image decoding controls
  • ♿ Accessibility support
  • 📡 Fallback stage callbacks
  • 🌍 Flutter Web compatible
  • 🪶 Zero third-party runtime dependencies
  • 🚫 No state-management dependency
  • 🔒 Null-safe
  • 🧪 Testable and deterministic

📦 Installation #

Add the package to your pubspec.yaml:

dependencies:
  secure_gateway_image: ^1.0.0

Then run:

flutter pub get

Import it:

import 'package:secure_gateway_image/secure_gateway_image.dart';

🚀 Basic Usage #

The simplest usage is:

SecureGatewayImage(
  networkUrl: user.profileImageUrl,
  initials: user.name,
  size: 56,
)

The widget will try:

Network
   ↓ failure
Initials Avatar

🔥 Complete Fallback Pipeline #

The complete fallback order is:

┌─────────────────────┐
│    Network Image    │
└──────────┬──────────┘
           │
        failure
           ↓
┌─────────────────────┐
│    Local Cache      │
│   ImageProvider     │
└──────────┬──────────┘
           │
        failure
           ↓
┌─────────────────────┐
│    Asset Image      │
└──────────┬──────────┘
           │
        failure
           ↓
┌─────────────────────┐
│ Animated Initials   │
│      Avatar         │
└─────────────────────┘

For example:

SecureGatewayImage(
  networkUrl: user.profileImageUrl,
  cachedImage: FileImage(cachedFile),
  assetPath: 'assets/images/default_avatar.png',
  initials: user.name,
  size: 64,
)

The behavior is:

networkUrl
    ↓
network succeeds
    → display network image

network fails
    ↓
cachedImage
    ↓
cache succeeds
    → display cached image

cache fails
    ↓
assetPath
    ↓
asset succeeds
    → display asset

asset fails
    ↓
initials
    ↓
display animated avatar

If a source isn't provided, it is automatically skipped.


💾 Local Cache #

secure_gateway_image intentionally does not manage disk caching.

The host application owns:

  • HTTP caching
  • disk storage
  • cache expiration
  • cache eviction
  • stale-while-revalidate
  • database storage
  • encrypted storage
  • authentication
  • retry policies

The widget only receives an ImageProvider.

For example, with a cached File:

import 'dart:io';

SecureGatewayImage(
  networkUrl: networkUrl,
  cachedImage: FileImage(cachedFile),
  assetPath: 'assets/images/default_avatar.png',
  initials: 'Rajat Das',
)

You can also use a MemoryImage:

SecureGatewayImage(
  networkUrl: networkUrl,
  cachedImage: MemoryImage(imageBytes),
  assetPath: 'assets/images/default_avatar.png',
  initials: 'Rajat Das',
)

This design keeps caching concerns outside the UI package.


📦 Asset Fallback #

Provide an asset as the third fallback:

SecureGatewayImage(
  networkUrl: networkUrl,
  cachedImage: FileImage(cachedFile),
  assetPath: 'assets/images/default_avatar.png',
  initials: 'Rajat Das',
)

Make sure the asset is declared in your application's pubspec.yaml:

flutter:
  assets:
    - assets/images/default_avatar.png

👤 Initials Avatar #

If every image source fails, the widget generates an avatar from the supplied initials/name.

SecureGatewayImage(
  initials: 'Rajat Das',
  size: 64,
)

Produces:

┌──────────────┐
│              │
│      RD      │
│              │
└──────────────┘

For:

initials: 'Rajat Das'

the generated initials are:

RD

For:

initials: 'Rajat'

the generated initials are:

R

For:

initials: ''

the generated fallback is:

?

🎨 Deterministic Avatar Colors #

Avatar colors are generated deterministically from the supplied name.

For example:

SecureGatewayImage(
  initials: 'Rajat Das',
  size: 64,
)

will consistently generate the same base avatar color for "Rajat Das".

This means the same user doesn't randomly change avatar colors every time the widget rebuilds.


✨ Avatar Animation #

The default initials avatar is animated.

SecureGatewayImage(
  initials: 'Rajat Das',
  size: 64,
  animateAvatar: true,
)

Disable the animation if required:

SecureGatewayImage(
  initials: 'Rajat Das',
  size: 64,
  animateAvatar: false,
)

Customize the animation:

SecureGatewayImage(
  initials: 'Rajat Das',
  size: 64,
  animateAvatar: true,
  avatarAnimationDuration:
      const Duration(milliseconds: 700),
  avatarAnimationCurve:
      Curves.easeOutBack,
)

🧩 Custom Avatar #

If you don't want the built-in initials avatar, provide your own:

SecureGatewayImage(
  initials: 'RD',
  size: 64,
  avatarBuilder: (
    context,
    initials,
  ) {
    return ColoredBox(
      color: Colors.black,
      child: Center(
        child: Text(
          initials,
          style: const TextStyle(
            color: Colors.white,
            fontSize: 24,
            fontWeight: FontWeight.bold,
          ),
        ),
      ),
    );
  },
)

The custom builder is used only when all image sources fail.


⏳ Loading Placeholder #

You can provide a custom loading widget:

SecureGatewayImage(
  networkUrl: imageUrl,
  initials: 'RD',
  placeholder: (context) {
    return const Center(
      child: CircularProgressIndicator(),
    );
  },
)

For a skeleton:

SecureGatewayImage(
  networkUrl: imageUrl,
  initials: 'RD',
  placeholder: (context) {
    return Container(
      color: Colors.grey.shade300,
    );
  },
)

🔐 Network Headers #

Authenticated image endpoints can use headers:

SecureGatewayImage(
  networkUrl: imageUrl,
  headers: {
    'Authorization': 'Bearer $token',
  },
  initials: 'RD',
)

This is useful for APIs where image URLs require authentication.


🖼️ Image Fit #

All standard Flutter BoxFit values are supported.

SecureGatewayImage(
  networkUrl: imageUrl,
  initials: 'RD',
  size: 100,
  fit: BoxFit.cover,
)

Other options:

BoxFit.contain
BoxFit.cover
BoxFit.fill
BoxFit.fitWidth
BoxFit.fitHeight
BoxFit.none
BoxFit.scaleDown

📐 Width and Height #

You can use size:

SecureGatewayImage(
  initials: 'RD',
  size: 56,
)

or specify width and height independently:

SecureGatewayImage(
  initials: 'RD',
  width: 100,
  height: 60,
)

If both width/height and size are supplied, explicit width and height take precedence.


🔲 Border Radius #

SecureGatewayImage(
  networkUrl: imageUrl,
  initials: 'RD',
  size: 64,
  borderRadius:
      BorderRadius.circular(16),
)

Circular avatar:

SecureGatewayImage(
  networkUrl: imageUrl,
  initials: 'RD',
  size: 64,
  borderRadius:
      BorderRadius.circular(999),
)

📡 Monitoring Fallback Stages #

You can monitor which source is currently active:

SecureGatewayImage(
  networkUrl: imageUrl,
  cachedImage: FileImage(cachedFile),
  assetPath: 'assets/default.png',
  initials: 'Rajat Das',

  onStageChanged: (stage) {
    debugPrint(
      'Image stage: $stage',
    );
  },
)

Available stages:

GatewayImageStage.network
GatewayImageStage.cache
GatewayImageStage.asset
GatewayImageStage.avatar

For example, if the network fails and cache succeeds:

network
   ↓
cache

If everything fails:

network
   ↓
cache
   ↓
asset
   ↓
avatar

♿ Accessibility #

For meaningful images, provide a semantic label:

SecureGatewayImage(
  networkUrl: profileImage,
  initials: 'Rajat Das',
  semanticLabel:
      'Profile photo of Rajat Das',
)

For purely decorative images:

SecureGatewayImage(
  networkUrl: backgroundImage,
  initials: '',
  excludeFromSemantics: true,
)

⚡ Performance #

For large source images displayed at small dimensions, use cacheWidth and cacheHeight.

Example:

SecureGatewayImage(
  networkUrl: imageUrl,
  initials: 'RD',
  size: 48,
  cacheWidth: 144,
  cacheHeight: 144,
)

This can prevent unnecessarily decoding a huge original image when the UI only needs a small avatar.

Do not blindly use the original image resolution for tiny UI elements.


🌐 Flutter Web #

The package itself does not import dart:io.

The cache source is an ImageProvider, which means the widget can be used across Flutter platforms.

For mobile/desktop file caching:

SecureGatewayImage(
  networkUrl: url,
  cachedImage: FileImage(file),
  initials: 'RD',
)

For web-compatible cached bytes:

SecureGatewayImage(
  networkUrl: url,
  cachedImage: MemoryImage(bytes),
  initials: 'RD',
)

🏗️ Architecture #

The package intentionally follows a simple responsibility boundary.

┌─────────────────────────────────────┐
│          Application Layer          │
│                                     │
│  API / Dio / Repository / Database │
│             │                       │
│             │ cached image          │
│             ▼                       │
└─────────────┬───────────────────────┘
              │
              ▼
┌─────────────────────────────────────┐
│      SecureGatewayImage             │
│                                     │
│  Network                            │
│     ↓                               │
│  Cached ImageProvider               │
│     ↓                               │
│  Asset                              │
│     ↓                               │
│  Initials Avatar                    │
└─────────────────────────────────────┘

The package does not own the application's data layer.


🚫 What This Package Does NOT Do #

secure_gateway_image does not provide:

  • HTTP client
  • Disk cache
  • Database
  • Authentication
  • Token refresh
  • Retry policy
  • Cache eviction
  • Background downloads
  • State management
  • Bloc
  • Riverpod
  • Provider
  • GetX
  • Service locator

These responsibilities should remain in the application layer.


🧠 Why No Built-in Cache? #

A common mistake would be to make this widget responsible for downloading and caching images.

That creates unnecessary coupling:

Widget
 ├── HTTP
 ├── Cache
 ├── Database
 ├── File system
 ├── Retry
 └── Rendering

Instead, this package follows:

Repository
    │
    ├── HTTP
    ├── Cache
    └── Persistence
          │
          ▼
SecureGatewayImage
    │
    ├── Render network
    ├── Render cache
    ├── Render asset
    └── Render avatar

This keeps the package small and reusable.


🧪 Testing #

Run:

flutter pub get

Format:

dart format .

Analyze:

flutter analyze

Run tests:

flutter test

Run all checks:

dart format --output=none --set-exit-if-changed .
flutter analyze
flutter test

📱 Example Application #

The repository contains an example application under:

example/

Run it:

cd example
flutter pub get
flutter run

📚 API Documentation #

Detailed API documentation is available at:

doc/api.md

The primary public API is:

SecureGatewayImage

and:

GatewayImageStage

📦 Publishing to pub.dev #

Before publishing:

flutter pub publish --dry-run

Review all warnings.

Then:

flutter pub publish

🔄 Versioning #

This package follows semantic versioning.

MAJOR.MINOR.PATCH

For example:

1.0.0
1.0.1
1.1.0
2.0.0

Use a patch release for backwards-compatible bug fixes.

Use a minor release for backwards-compatible features.

Use a major release for breaking API changes.


📝 Changelog #

See:

CHANGELOG.md

🤝 Contributing #

Contributions are welcome.

See:

CONTRIBUTING.md

🔒 Security #

See:

SECURITY.md

📄 License #

This project is licensed under the MIT License.

See:

LICENSE

⭐ Example #

A typical production usage might look like:

SecureGatewayImage(
  networkUrl: user.profileImageUrl,

  cachedImage: cachedFile == null
      ? null
      : FileImage(cachedFile),

  assetPath:
      'assets/images/default_avatar.png',

  initials: user.name,

  size: 48,

  borderRadius:
      BorderRadius.circular(12),

  fit: BoxFit.cover,

  cacheWidth: 144,
  cacheHeight: 144,

  onStageChanged: (stage) {
    debugPrint(
      'Image source: $stage',
    );
  },
)

The resulting behavior is:

                 Network
                    │
             ┌──────┴──────┐
             │             │
          Success        Failure
             │             │
             ▼             ▼
           Image          Cache
                            │
                     ┌──────┴──────┐
                     │             │
                  Success        Failure
                     │             │
                     ▼             ▼
                   Image          Asset
                                   │
                            ┌──────┴──────┐
                            │             │
                         Success        Failure
                            │             │
                            ▼             ▼
                          Image      Initials Avatar

The widget therefore provides a predictable rendering contract:


👨‍💻 Author #

Rajat Das

Flutter Developer | Mobile Application Developer

Created and maintained by Rajat Das.

GitHub: https://github.com/rajatdas_dev


📄 License #

Copyright © 2026 Rajat Das.

This project is licensed under the MIT License.

See LICENSE for details.

There should always be a valid visual representation, even when every external image source fails.

2
likes
0
points
544
downloads

Publisher

unverified uploader

Weekly Downloads

Error-resilient Flutter image widget with network, local cache, asset, and animated initials fallback support.

Repository (GitHub)
View/report issues

Topics

#flutter #image #avatar #fallback #widget

License

unknown (license)

Dependencies

flutter

More

Packages that depend on secure_gateway_image