layou_user_avatar

A customizable Flutter package for user avatar management with Firebase, Riverpod, image optimization, and caching.

Features

  • Upload and delete user avatars
  • Automatic WebP conversion for optimal file size (25-35% smaller than PNG/JPEG)
  • Image resizing with aspect ratio preservation
  • Local and memory caching with configurable TTL
  • Customizable widgets for display, upload, and deletion
  • Riverpod integration for state management
  • Firebase Storage integration (with extensible storage provider interface)
  • Configurable storage paths
  • Progress callbacks and error handling
  • Cache busting support
  • Native WebP support on Android and iOS

Installation

Add this to your package's pubspec.yaml file:

dependencies:
  layou_user_avatar: ^0.1.0

Quick Start

1. Configure the package at app startup

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:layou_user_avatar/layou_user_avatar.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:firebase_auth/firebase_auth.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  runApp(
    ProviderScope(
      overrides: [
        avatarConfigProvider.overrideWithValue(
          AvatarConfig(
            storageProvider: FirebaseStorageProvider(FirebaseStorage.instance),
            localCacheProvider: HiveCacheProvider(),
            identityProvider: FirebaseIdentityProvider(FirebaseAuth.instance),
            imageConverter: WebPImageConverter(),
            pathBuilder: (userId) => 'avatars/$userId/avatar.webp',
            cacheTtl: Duration(hours: 24),
            webpQuality: 85,
            maxImageSize: 512,
          ),
        ),
      ],
      child: MyApp(),
    ),
  );
}

2. Display and edit current user's avatar

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:layou_user_avatar/layou_user_avatar.dart';

class ProfileScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(title: Text('Profile')),
      body: Center(
        child: AvatarEditor(
          size: 120,
          onUploadSuccess: (url) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('Avatar uploaded!')),
            );
          },
          onUploadError: (error) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('Upload failed: $error')),
            );
          },
          onProgress: (progress) {
            print('Upload progress: ${(progress * 100).toStringAsFixed(0)}%');
          },
        ),
      ),
    );
  }
}

3. Display external user avatar (read-only)

class UserListItem extends ConsumerWidget {
  final String userId;
  final String userName;

  const UserListItem({
    required this.userId,
    required this.userName,
  });

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final avatarAsync = ref.watch(externalUserAvatarProvider(userId));

    return ListTile(
      leading: avatarAsync.when(
        data: (url) => AvatarDisplay(
          avatarUrl: url,
          userId: userId,
          size: 48,
        ),
        loading: () => CircularProgressIndicator(),
        error: (err, stack) => Icon(Icons.error),
      ),
      title: Text(userName),
    );
  }
}

Widgets

AvatarEditor

All-in-one widget combining avatar display, upload, and delete functionality.

AvatarEditor(
  size: 120,
  showUploadButton: true,
  showDeleteButton: true,
  onUploadSuccess: (url) => print('Uploaded: $url'),
  onUploadError: (error) => print('Error: $error'),
  onDeleteSuccess: () => print('Deleted'),
  onProgress: (progress) => print('Progress: $progress'),
)

AvatarDisplay

Read-only avatar display with placeholder support.

AvatarDisplay(
  avatarUrl: 'https://example.com/avatar.webp',
  userId: 'user123',
  size: 64,
  enableCaching: true,
  onError: () => print('Failed to load avatar'),
)

AvatarUploadButton

Standalone upload button with image picker.

AvatarUploadButton(
  currentAvatarUrl: currentUrl,
  onUploadSuccess: (url) => print('Uploaded: $url'),
  onUploadError: (error) => print('Error: $error'),
  onProgress: (progress) => print('Progress: $progress'),
  showProgress: true,
)

AvatarDeleteButton

Standalone delete button with optional confirmation dialog.

AvatarDeleteButton(
  onDeleteSuccess: () => print('Deleted'),
  onDeleteError: (error) => print('Error: $error'),
  confirmDelete: true,
)

Configuration Options

AvatarConfig

AvatarConfig(
  // Required
  storageProvider: StorageProvider,      // Cloud storage implementation
  identityProvider: IdentityProvider,    // User identity provider
  imageConverter: ImageConverter,        // Image conversion implementation

  // Optional
  localCacheProvider: LocalCacheProvider?, // Local cache (null = no cache)
  pathBuilder: String Function(String userId), // Custom path builder
  cacheTtl: Duration?,                   // Cache expiration (null = no expiry)
  enableCacheBusting: bool,              // Add timestamp to URLs
  webpQuality: int,                      // WebP quality (0-100, default: 80)
  maxImageSize: int?,                    // Max size in pixels (null = no limit)
  placeholderAssetPath: String?,         // Custom placeholder asset
  customLoader: Widget?,                 // Custom loading widget
)

Extensibility

The package is designed to be storage-agnostic. You can implement custom providers:

Custom Storage Provider

class MyStorageProvider implements StorageProvider {
  @override
  Future<String> uploadFile(String path, File file, {String? contentType}) {
    // Your implementation
  }

  @override
  Future<String> getDownloadUrl(String path) {
    // Your implementation
  }

  @override
  Future<void> deleteFile(String path) {
    // Your implementation
  }

  @override
  Future<bool> fileExists(String path) {
    // Your implementation
  }

  @override
  Stream<double> getUploadProgress(String path) {
    // Your implementation
  }
}

License

MIT License - see LICENSE file for details.

Libraries

layou_user_avatar
A customizable Flutter package for user avatar management.