# Moai Lang Dart

> Dart best practices with Flutter mobile development, async programming, and server-side Dart for 2025

- Skill: `majiayu000/moai-lang-dart` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds add majiayu000/moai-lang-dart`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/moai-lang-dart/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/moai-lang-dart

---


# Dart Development Mastery

**Modern Dart Development with 2025 Best Practices**

> Comprehensive Dart development guidance covering Flutter mobile applications, async programming patterns, server-side development, and cross-platform solutions using the latest tools and frameworks.

## What It Does

### Flutter Mobile Development
- **Mobile App Development**: Flutter 3.x with Material Design 3 and Cupertino widgets
- **State Management**: Provider, Riverpod, BLoC patterns for scalable applications
- **Navigation**: Go Router for declarative routing and deep linking
- **Performance**: Widget optimization, lazy loading, memory management

### Server-Side Development
- **Web APIs**: Shelf, Dart Frog, or Aqueduct for backend services
- **Database Integration**: PostgreSQL, MongoDB with async drivers
- **Real-time Communication**: WebSockets, gRPC with Dart's async capabilities
- **Testing**: Unit tests, widget tests, integration tests with Dart test framework

### Cross-Platform Development
- **Flutter for Multiple Platforms**: iOS, Android, Web, Desktop, and Embedded
- **Shared Codebases**: Dart packages for business logic across platforms
- **Platform-Specific APIs**: Method channels for native integration

## When to Use

### Perfect Scenarios
- **Building cross-platform mobile applications with Flutter**
- **Developing scalable Flutter apps with modern state management**
- **Creating server-side APIs with Dart**
- **Implementing real-time applications with WebSockets**
- **Building web applications with Flutter Web**
- **Developing desktop applications with Flutter Desktop**
- **Creating embedded systems applications**

### Common Triggers
- "Create Flutter app"
- "Build Dart web API"
- "Implement Flutter state management"
- "Optimize Flutter performance"
- "Test Flutter application"
- "Dart best practices"

## Tool Version Matrix (2025-11-06)

### Core Dart/Flutter
- **Dart**: 3.5.x (current) / 3.4.x (LTS)
- **Flutter**: 3.24.x (current) / 3.22.x (LTS)
- **Dart SDK**: 3.5.0
- **Package Manager**: pub (built-in)

### Flutter Frameworks
- **Material Design**: 3.x (Material 3)
- **Cupertino Widgets**: iOS 17+ support
- **Go Router**: 13.x - Declarative routing
- **Riverpod**: 2.5.x - Reactive state management
- **BLoC**: 8.1.x - State management library

### Testing Tools
- **Dart Test**: Built-in testing framework
- **Flutter Test**: Widget and integration testing
- **Mockito**: 5.4.x - Mocking framework
- **Golden Tests**: Widget screenshot testing
- **Integration Test**: End-to-end testing

### Development Tools
- **Flutter CLI**: 3.24.x
- **Dart DevTools**: Web-based debugging tools
- **Android Studio**: Dolphin 2024.x
- **VS Code**: Flutter extension

### Backend Tools
- **Shelf**: 1.4.x - Web server framework
- **Dart Frog**: 1.0.x - Server-side framework
- **Aqueduct**: 7.x - Full-stack framework
- **MongoDB Dart Driver**: 4.12.x

## Ecosystem Overview

### Package Management

```bash
# Create new Flutter project
flutter create my_app
flutter create --org com.example --platforms=web,desktop my_app

# Create new Dart project
dart create my_dart_app

# Add dependencies
flutter pub add provider riverpod go_router
flutter pub add dio retrofit json_annotation
dart pub add shelf shelf_router

# Get dependencies
flutter pub get
dart pub get

# Run and build
flutter run
flutter run --release
flutter build apk
flutter build web
dart run
```

### Project Structure (2025 Best Practice)

```
my_flutter_app/
├── lib/
│   ├── main.dart                 # App entry point
│   ├── app.dart                  # App configuration
│   ├── core/                     # Core utilities
│   │   ├── constants/           # App constants
│   │   ├── errors/              # Custom error classes
│   │   ├── extensions/          # Dart extensions
│   │   ├── network/             # Network configuration
│   │   ├── themes/              # App themes
│   │   └── utils/               # Utility functions
│   ├── features/                # Feature modules
│   │   ├── authentication/      # Auth feature
│   │   │   ├── data/            # Data layer (repositories, data sources)
│   │   │   ├── domain/          # Domain layer (entities, use cases)
│   │   │   └── presentation/    # UI layer (pages, widgets, providers)
│   │   ├── user_profile/        # User profile feature
│   │   └── settings/            # Settings feature
│   ├── shared/                  # Shared components
│   │   ├── widgets/             # Reusable widgets
│   │   ├── models/              # Shared data models
│   │   ├── services/            # Shared services
│   │   └── providers/           # Shared providers
│   └── routes/                  # App routes
├── test/                        # Test files
│   ├── unit/                    # Unit tests
│   ├── widget/                  # Widget tests
│   └── integration/             # Integration tests
├── assets/                      # Static assets
├── pubspec.yaml                 # Dependencies
└── analysis_options.yaml        # Linting rules
```

## Modern Development Patterns

### Dart 3.x Language Features

```dart
// Enhanced patterns with records and pattern matching
sealed class NetworkResult<T> {
  const NetworkResult();
}

class Success<T> extends NetworkResult<T> {
  final T data;
  const Success(this.data);
}

class Error<T> extends NetworkResult<T> {
  final String message;
  final Exception? exception;
  const Error(this.message, [this.exception]);
}

class Loading<T> extends NetworkResult<T> {
  const Loading();
}

// Pattern matching with switch expressions
T handleNetworkResult<T>(NetworkResult<T> result) {
  return switch (result) {
    Success(data: final data) => data,
    Error(message: final message) => throw Exception(message),
    Loading() => throw StateError('Still loading'),
  };
}

// Records for lightweight data structures
typedef UserInfo = (String name, int age, String email);

class UserService {
  UserInfo getUserInfo(int id) {
    return ('John Doe', 30, 'john@example.com');
  }
  
  void printUserInfo(UserInfo user) {
    final (name, age, email) = user;
    print('$name, $age years old, email: $email');
  }
}

// Enhanced type inference and const constructors
class AppConfig {
  static const apiBaseUrl = String.fromEnvironment('API_BASE_URL', defaultValue: 'https://api.example.com');
  static const appVersion = String.fromEnvironment('APP_VERSION', defaultValue: '1.0.0');
  static const isDebug = bool.fromEnvironment('DEBUG', defaultValue: false);
}

// Enhanced enums with methods and properties
enum ThemeMode {
  light._('Light Theme', '☀️'),
  dark._('Dark Theme', '🌙'),
  system._('System Theme', '💻');
  
  const ThemeMode._(this.displayName, this.icon);
  
  final String displayName;
  final String icon;
  
  Brightness get brightness => switch (this) {
    ThemeMode.light => Brightness.light,
    ThemeMode.dark => Brightness.dark,
    ThemeMode.system => PlatformDispatcher.instance.platformBrightness,
  };
}

// Extension methods for enhanced APIs
extension StringExtension on String {
  bool get isValidEmail {
    return RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(this);
  }
  
  String get capitalize {
    return '${this[0].toUpperCase()}${substring(1)}';
  }
  
  String truncate(int length, {String suffix = '...'}) {
    if (this.length <= length) return this;
    return '${substring(0, length)}$suffix';
  }
}
```

### Modern Flutter State Management with Riverpod

```dart
// Provider setup with Riverpod 2.x
import 'package:flutter_riverpod/flutter_riverpod.dart';

// Model classes with immutability
@immutable
class User {
  final String id;
  final String name;
  final String email;
  final String avatarUrl;
  
  const User({
    required this.id,
    required this.name,
    required this.email,
    required this.avatarUrl,
  });
  
  User copyWith({
    String? id,
    String? name,
    String? email,
    String? avatarUrl,
  }) {
    return User(
      id: id ?? this.id,
      name: name ?? this.name,
      email: email ?? this.email,
      avatarUrl: avatarUrl ?? this.avatarUrl,
    );
  }
  
  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    return other is User && 
           other.id == id && 
           other.name == name && 
           other.email == email;
  }
  
  @override
  int get hashCode => id.hashCode ^ name.hashCode ^ email.hashCode;
}

// Repository interface
abstract class UserRepository {
  Future<User> getUser(String userId);
  Future<List<User>> getUsers({int page = 1, int limit = 20});
  Future<User> updateUser(User user);
  Future<void> deleteUser(String userId);
}

// Implementation with HTTP client
class HttpUserRepository implements UserRepository {
  final Dio _dio;
  
  HttpUserRepository(this._dio);
  
  @override
  Future<User> getUser(String userId) async {
    try {
      final response = await _dio.get('/users/$userId');
      return User.fromJson(response.data);
    } on DioException catch (e) {
      throw UserRepositoryException('Failed to get user: $e');
    }
  }
  
  @override
  Future<List<User>> getUsers({int page = 1, int limit = 20}) async {
    try {
      final response = await _dio.get('/users', queryParameters: {
        'page': page,
        'limit': limit,
      });
      
      return (response.data as List)
          .map((json) => User.fromJson(json))
          .toList();
    } on DioException catch (e) {
      throw UserRepositoryException('Failed to get users: $e');
    }
  }
  
  @override
  Future<User> updateUser(User user) async {
    try {
      final response = await _dio.put('/users/${user.id}', data: user.toJson());
      return User.fromJson(response.data);
    } on DioException catch (e) {
      throw UserRepositoryException('Failed to update user: $e');
    }
  }
  
  @override
  Future<void> deleteUser(String userId) async {
    try {
      await _dio.delete('/users/$userId');
    } on DioException catch (e) {
      throw UserRepositoryException('Failed to delete user: $e');
    }
  }
}

// Riverpod providers
final dioProvider = Provider<Dio>((ref) {
  final dio = Dio(BaseOptions(baseUrl: AppConfig.apiBaseUrl));
  dio.interceptors.add(LogInterceptor());
  return dio;
});

final userRepositoryProvider = Provider<UserRepository>((ref) {
  return HttpUserRepository(ref.read(dioProvider));
});

// Async providers for data fetching
final userProvider = FutureProvider.family<User, String>((ref, userId) async {
  final repository = ref.watch(userRepositoryProvider);
  return repository.getUser(userId);
});

final usersProvider = AsyncNotifierProvider<UsersNotifier, List<User>>(UsersNotifier.new);

// Notifier for managing state
class UsersNotifier extends AsyncNotifier<List<User>> {
  int _page = 1;
  final int _limit = 20;
  bool _hasMore = true;
  
  @override
  Future<List<User>> build() async {
    return _loadUsers();
  }
  
  Future<List<User>> _loadUsers() async {
    if (state.isLoading || !_hasMore) return state.value ?? [];
    
    state = const AsyncLoading();
    
    try {
      final repository = ref.read(userRepositoryProvider);
      final newUsers = await repository.getUsers(page: _page, limit: _limit);
      
      if (newUsers.length < _limit) {
        _hasMore = false;
      }
      
      final currentUsers = state.value ?? [];
      final updatedUsers = _page == 1 ? newUsers : [...currentUsers, ...newUsers];
      
      state = AsyncData(updatedUsers);
      _page++;
      
      return updatedUsers;
    } catch (error, stackTrace) {
      state = AsyncError(error, stackTrace);
      rethrow;
    }
  }
  
  Future<void> loadMoreUsers() async {
    await _loadUsers();
  }
  
  Future<void> refresh() async {
    _page = 1;
    _hasMore = true;
    await _loadUsers();
  }
}

// State management with Notifier for single user
final userNotifierProvider = AsyncNotifierProvider.family<UserNotifier, User, String>(UserNotifier.new);

class UserNotifier extends FamilyAsyncNotifier<User, String> {
  @override
  Future<User> build(String arg) async {
    final repository = ref.read(userRepositoryProvider);
    return repository.getUser(arg);
  }
  
  Future<void> updateUser(User user) async {
    state = const AsyncLoading();
    
    try {
      final repository = ref.read(userRepositoryProvider);
      final updatedUser = await repository.updateUser(user);
      state = AsyncData(updatedUser);
    } catch (error, stackTrace) {
      state = AsyncError(error, stackTrace);
    }
  }
}

// App-wide state providers
final appThemeProvider = StateProvider<ThemeMode>((ref) => ThemeMode.system);
final appLocaleProvider = StateProvider<Locale>((ref) => const Locale('en', 'US'));
```

### Modern Flutter UI with Material 3

```dart
// Modern app with Material 3 and go_router
class MyApp extends ConsumerWidget {
  const MyApp({super.key});
  
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final appRouter = ref.watch(goRouterProvider);
    final themeMode = ref.watch(appThemeProvider);
    final appLocale = ref.watch(appLocaleProvider);
    
    return MaterialApp.router(
      title: 'My Flutter App',
      debugShowCheckedModeBanner: false,
      themeMode: themeMode,
      theme: AppTheme.lightTheme,
      darkTheme: AppTheme.darkTheme,
      locale: appLocale,
      supportedLocales: const [
        Locale('en', 'US'),
        Locale('es', 'ES'),
        Locale('fr', 'FR'),
      ],
      localizationsDelegates: const [
        AppLocalizations.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      routerConfig: appRouter,
    );
  }
}

// Modern theme configuration
class AppTheme {
  static ThemeData get lightTheme {
    return ThemeData(
      useMaterial3: true,
      colorScheme: ColorScheme.fromSeed(
        seedColor: const Color(0xFF6750A4),
        brightness: Brightness.light,
      ),
      appBarTheme: const AppBarTheme(
        centerTitle: true,
        elevation: 0,
        scrolledUnderElevation: 1,
      ),
      cardTheme: CardTheme(
        elevation: 2,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(16),
        ),
      ),
      elevatedButtonTheme: ElevatedButtonThemeData(
        style: ElevatedButton.styleFrom(
          elevation: 1,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(20),
          ),
          padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
        ),
      ),
      inputDecorationTheme: InputDecorationTheme(
        border: OutlineInputBorder(
          borderRadius: BorderRadius.circular(12),
        ),
        contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
      ),
    );
  }
  
  static ThemeData get darkTheme {
    return ThemeData(
      useMaterial3: true,
      colorScheme: ColorScheme.fromSeed(
        seedColor: const Color(0xFF6750A4),
        brightness: Brightness.dark,
      ),
      appBarTheme: const AppBarTheme(
        centerTitle: true,
        elevation: 0,
        scrolledUnderElevation: 1,
      ),
      cardTheme: CardTheme(
        elevation: 2,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(16),
        ),
      ),
    );
  }
}

// Modern user list widget with state management
class UserListScreen extends ConsumerWidget {
  const UserListScreen({super.key});
  
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final usersAsync = ref.watch(usersProvider);
    
    return Scaffold(
      appBar: AppBar(
        title: const Text('Users'),
        actions: [
          IconButton(
            icon: const Icon(Icons.refresh),
            onPressed: () {
              ref.read(usersProvider.notifier).refresh();
            },
          ),
        ],
      ),
      body: RefreshIndicator(
        onRefresh: () async {
          await ref.read(usersProvider.notifier).refresh();
        },
        child: usersAsync.when(
          data: (users) {
            if (users.isEmpty) {
              return const EmptyStateWidget(
                message: 'No users found',
                icon: Icons.people_outline,
              );
            }
            
            return NotificationListener<ScrollNotification>(
              onNotification: (scrollInfo) {
                if (scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) {
                  ref.read(usersProvider.notifier).loadMoreUsers();
                }
                return false;
              },
              child: ListView.builder(
                padding: const EdgeInsets.all(16),
                itemCount: users.length + 1, // +1 for loading indicator
                itemBuilder: (context, index) {
                  if (index == users.length) {
                    return const LoadingIndicator();
                  }
                  
                  return UserCard(user: users[index]);
                },
              ),
            );
          },
          loading: () => const Center(child: CircularProgressIndicator()),
          error: (error, stack) => ErrorWidget(
            error: error,
            onRetry: () {
              ref.read(usersProvider.notifier).refresh();
            },
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton.extended(
        onPressed: () {
          context.go('/add-user');
        },
        icon: const Icon(Icons.add),
        label: const Text('Add User'),
      ),
    );
  }
}

// Modern user card widget
class UserCard extends ConsumerWidget {
  final User user;
  
  const UserCard({
    super.key,
    required this.user,
  });
  
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Card(
      margin: const EdgeInsets.only(bottom: 12),
      child: InkWell(
        onTap: () {
          context.go('/users/${user.id}');
        },
        borderRadius: BorderRadius.circular(16),
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Row(
            children: [
              CircleAvatar(
                radius: 28,
                backgroundImage: NetworkImage(user.avatarUrl),
                backgroundColor: Theme.of(context).colorScheme.surfaceVariant,
                child: user.avatarUrl.isEmpty
                    ? Text(
                        user.name.isNotEmpty ? user.name[0].toUpperCase() : '?',
                        style: Theme.of(context).textTheme.titleLarge,
                      )
                    : null,
              ),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      user.name,
                      style: Theme.of(context).textTheme.titleMedium,
                    ),
                    const SizedBox(height: 4),
                    Text(
                      user.email,
                      style: Theme.of(context).textTheme.bodyMedium?.copyWith(
                        color: Theme.of(context).colorScheme.onSurfaceVariant,
                      ),
                    ),
                  ],
                ),
              ),
              IconButton(
                icon: const Icon(Icons.more_vert),
                onPressed: () {
                  _showUserMenu(context, ref, user);
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
  
  void _showUserMenu(BuildContext context, WidgetRef ref, User user) {
    showModalBottomSheet(
      context: context,
      builder: (context) {
        return SafeArea(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              ListTile(
                leading: const Icon(Icons.edit),
                title: const Text('Edit User'),
                onTap: () {
                  Navigator.pop(context);
                  context.go('/users/${user.id}/edit');
                },
              ),
              ListTile(
                leading: const Icon(Icons.delete, color: Colors.red),
                title: const Text('Delete User', style: TextStyle(color: Colors.red)),
                onTap: () async {
                  Navigator.pop(context);
                  
                  final confirmed = await _showDeleteConfirmation(context);
                  if (confirmed) {
                    try {
                      await ref.read(userRepositoryProvider).deleteUser(user.id);
                      if (context.mounted) {
                        ScaffoldMessenger.of(context).showSnackBar(
                          const SnackBar(content: Text('User deleted successfully')),
                        );
                      }
                    } catch (error) {
                      if (context.mounted) {
                        ScaffoldMessenger.of(context).showSnackBar(
                          SnackBar(content: Text('Failed to delete user: $error')),
                        );
                      }
                    }
                  }
                },
              ),
            ],
          ),
        );
      },
    );
  }
  
  Future<bool> _showDeleteConfirmation(BuildContext context) async {
    return await showDialog<bool>(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: const Text('Delete User'),
          content: Text('Are you sure you want to delete ${user.name}?'),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(context, false),
              child: const Text('Cancel'),
            ),
            TextButton(
              onPressed: () => Navigator.pop(context, true),
              style: TextButton.styleFrom(foregroundColor: Colors.red),
              child: const Text('Delete'),
            ),
          ],
        );
      },
    ) ?? false;
  }
}
```

### Go Router for Navigation

```dart
// Go router configuration
final goRouterProvider = Provider<GoRouter>((ref) {
  return GoRouter(
    initialLocation: '/',
    debugLogDiagnostics: AppConfig.isDebug,
    routes: [
      // Shell route for navigation
      ShellRoute(
        builder: (context, state, child) {
          return MainScaffold(child: child);
        },
        routes: [
          // Home route
          GoRoute(
            path: '/',
            builder: (context, state) => const HomeScreen(),
          ),
          
          // User routes
          GoRoute(
            path: '/users',
            builder: (context, state) => const UserListScreen(),
            routes: [
              GoRoute(
                path: '/:userId',
                builder: (context, state) {
                  final userId = state.pathParameters['userId']!;
                  return UserDetailScreen(userId: userId);
                },
                routes: [
                  GoRoute(
                    path: '/edit',
                    builder: (context, state) {
                      final userId = state.pathParameters['userId']!;
                      return EditUserScreen(userId: userId);
                    },
                  ),
                ],
              ),
            ],
          ),
          
          // Settings route
          GoRoute(
            path: '/settings',
            builder: (context, state) => const SettingsScreen(),
            routes: [
              GoRoute(
                path: '/profile',
                builder: (context, state) => const ProfileSettingsScreen(),
              ),
              GoRoute(
                path: '/appearance',
                builder: (context, state) => const AppearanceSettingsScreen(),
              ),
            ],
          ),
        ],
      ),
      
      // Standalone routes
      GoRoute(
        path: '/add-user',
        builder: (context, state) => const AddUserScreen(),
      ),
      
      GoRoute(
        path: '/login',
        builder: (context, state) => const LoginScreen(),
      ),
    ],
    
    // Error handling
    errorBuilder: (context, state) => ErrorScreen(error: state.error),
    
    // Redirects
    redirect: (context, state) {
      // Example: redirect to login if not authenticated
      final isAuthenticated = true; // Check authentication status
      
      if (!isAuthenticated && !state.location.startsWith('/login')) {
        return '/login';
      }
      
      return null;
    },
  );
});

// Main scaffold with bottom navigation
class MainScaffold extends ConsumerWidget {
  const MainScaffold({
    required this.child,
    super.key,
  });
  
  final Widget child;
  
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final selectedIndex = ref.watch(bottomNavigationIndexProvider);
    
    return Scaffold(
      body: child,
      bottomNavigationBar: NavigationBar(
        selectedIndex: selectedIndex,
        onDestinationSelected: (index) {
          ref.read(bottomNavigationIndexProvider.notifier).state = index;
          
          switch (index) {
            case 0:
              context.go('/');
              break;
            case 1:
              context.go('/users');
              break;
            case 2:
              context.go('/settings');
              break;
          }
        },
        destinations: const [
          NavigationDestination(
            icon: Icon(Icons.home_outlined),
            selectedIcon: Icon(Icons.home),
            label: 'Home',
          ),
          NavigationDestination(
            icon: Icon(Icons.people_outlined),
            selectedIcon: Icon(Icons.people),
            label: 'Users',
          ),
          NavigationDestination(
            icon: Icon(Icons.settings_outlined),
            selectedIcon: Icon(Icons.settings),
            label: 'Settings',
          ),
        ],
      ),
    );
  }
}

// Provider for bottom navigation state
final bottomNavigationIndexProvider = StateProvider<int>((ref) => 0);
```

## Performance Considerations

### Widget Performance

```dart
// Performance-optimized widgets with const constructors
class OptimizedUserCard extends StatelessWidget {
  final User user;
  final VoidCallback? onTap;
  final VoidCallback? onEdit;
  final VoidCallback? onDelete;
  
  const OptimizedUserCard({
    super.key,
    required this.user,
    this.onTap,
    this.onEdit,
    this.onDelete,
  });
  
  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      child: InkWell(
        onTap: onTap,
        borderRadius: BorderRadius.circular(12),
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Row(
            children: [
              // Use Hero widget for smooth avatar transitions
              Hero(
                tag: 'user-avatar-${user.id}',
                child: UserAvatar(
                  imageUrl: user.avatarUrl,
                  name: user.name,
                  size: 48,
                ),
              ),
              const SizedBox(width: 16),
              Expanded(
                child: _buildUserInfo(),
              ),
              _buildActionButtons(),
            ],
          ),
        ),
      ),
    );
  }
  
  Widget _buildUserInfo() {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      mainAxisSize: MainAxisSize.min,
      children: [
        Text(
          user.name,
          style: const TextStyle(
            fontSize: 16,
            fontWeight: FontWeight.w600,
          ),
          maxLines: 1,
          overflow: TextOverflow.ellipsis,
        ),
        const SizedBox(height: 4),
        Text(
          user.email,
          style: const TextStyle(
            fontSize: 14,
            color: Colors.grey,
          ),
          maxLines: 1,
          overflow: TextOverflow.ellipsis,
        ),
      ],
    );
  }
  
  Widget _buildActionButtons() {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        if (onEdit != null)
          IconButton(
            icon: const Icon(Icons.edit_outlined),
            onPressed: onEdit,
            visualDensity: VisualDensity.compact,
          ),
        if (onDelete != null)
          IconButton(
            icon: const Icon(Icons.delete_outline),
            onPressed: onDelete,
            visualDensity: VisualDensity.compact,
          ),
      ],
    );
  }
}

// Efficient image loading and caching
class CachedNetworkImage extends StatefulWidget {
  final String imageUrl;
  final double? width;
  final double? height;
  final Widget? placeholder;
  final Widget? errorWidget;
  final BoxFit fit;
  
  const CachedNetworkImage({
    super.key,
    required this.imageUrl,
    this.width,
    this.height,
    this.placeholder,
    this.errorWidget,
    this.fit = BoxFit.cover,
  });
  
  @override
  State<CachedNetworkImage> createState() => _CachedNetworkImageState();
}

class _CachedNetworkImageState extends State<CachedNetworkImage> {
  final Map<String, ui.Image> _imageCache = {};
  bool _isLoading = true;
  bool _hasError = false;
  
  @override
  void initState() {
    super.initState();
    _loadImage();
  }
  
  Future<void> _loadImage() async {
    if (_imageCache.containsKey(widget.imageUrl)) {
      if (mounted) {
        setState(() {
          _isLoading = false;
        });
      }
      return;
    }
    
    try {
      final image = await _fetchImage();
      _imageCache[widget.imageUrl] = image;
      
      if (mounted) {
        setState(() {
          _isLoading = false;
        });
      }
    } catch (e) {
      if (mounted) {
        setState(() {
          _isLoading = false;
          _hasError = true;
        });
      }
    }
  }
  
  Future<ui.Image> _fetchImage() async {
    final completer = Completer<ui.Image>();
    final codec = await ui.instantiateImageCodec(
      await NetworkAssetBundle(Uri.parse(widget.imageUrl)).load(widget.imageUrl).then((bytes) => bytes.buffer.asUint8List()),
    );
    final frame = await codec.getNextFrame();
    completer.complete(frame.image);
    return completer.future;
  }
  
  @override
  Widget build(BuildContext context) {
    if (_isLoading) {
      return widget.placeholder ??
          Container(
            width: widget.width,
            height: widget.height,
            color: Colors.grey[200],
            child: const Center(
              child: CircularProgressIndicator(),
            ),
          );
    }
    
    if (_hasError) {
      return widget.errorWidget ??
          Container(
            width: widget.width,
            height: widget.height,
            color: Colors.grey[200],
            child: const Icon(Icons.error),
          );
    }
    
    final image = _imageCache[widget.imageUrl];
    return CustomPaint(
      size: Size(widget.width ?? double.infinity, widget.height ?? double.infinity),
      painter: _ImagePainter(image: image!, fit: widget.fit),
    );
  }
}

class _ImagePainter extends CustomPainter {
  final ui.Image image;
  final BoxFit fit;
  
  _ImagePainter({required this.image, required this.fit});
  
  @override
  void paint(Canvas canvas, Size size) {
    final imageSize = Size(image.width.toDouble(), image.height.toDouble());
    final scales = _calculateScales(imageSize, size);
    
    final paint = Paint()
      ..isAntiAlias = true
      ..filterQuality = FilterQuality.high;
    
    canvas.save();
    
    if (fit == BoxFit.cover) {
      canvas.scale(scales.dx, scales.dy);
      canvas.drawImageRect(
        image,
        Rect.fromLTWH(0, 0, imageSize.width, imageSize.height),
        Rect.fromLTWH(0, 0, size.width / scales.dx, size.height / scales.dy),
        paint,
      );
    }
    
    canvas.restore();
  }
  
  Offset _calculateScales(Size inputSize, Size outputSize) {
    final scaleX = outputSize.width / inputSize.width;
    final scaleY = outputSize.height / inputSize.height;
    return Offset(scaleX, scaleY);
  }
  
  @override
  bool shouldRepaint(covariant _ImagePainter oldDelegate) {
    return image != oldDelegate.image || fit != oldDelegate.fit;
  }
}

// ListView with lazy loading and recycling
class OptimizedListView<T> extends StatelessWidget {
  final List<T> items;
  final Widget Function(BuildContext context, T item, int index) itemBuilder;
  final VoidCallback? onLoadMore;
  final bool hasMore;
  final bool isLoading;
  
  const OptimizedListView({
    super.key,
    required this.items,
    required this.itemBuilder,
    this.onLoadMore,
    this.hasMore = false,
    this.isLoading = false,
  });
  
  @override
  Widget build(BuildContext context) {
    return NotificationListener<ScrollNotification>(
      onNotification: (notification) {
        if (notification is ScrollEndNotification &&
            notification.metrics.extentAfter == 0 &&
            hasMore &&
            !isLoading &&
            onLoadMore != null) {
          onLoadMore!();
        }
        return false;
      },
      child: ListView.builder(
        itemCount: items.length + (hasMore ? 1 : 0),
        itemBuilder: (context, index) {
          if (index == items.length) {
            return const Center(
              child: Padding(
                padding: EdgeInsets.all(16.0),
                child: CircularProgressIndicator(),
              ),
            );
          }
          
          return itemBuilder(context, items[index], index);
        },
      ),
    );
  }
}
```

### Memory Management

```dart
// Efficient memory usage with ImageCache
class ImageCacheManager {
  static final ImageCacheManager _instance = ImageCacheManager._internal();
  factory ImageCacheManager() => _instance;
  ImageCacheManager._internal();
  
  final PaintingBinding _paintingBinding = PaintingBinding.instance;
  final Map<String, ui.Image> _memoryCache = {};
  final int _maxCacheSize = 100 * 1024 * 1024; // 100MB
  int _currentCacheSize = 0;
  
  Future<ui.Image?> getImage(String url) async {
    // Check memory cache first
    if (_memoryCache.containsKey(url)) {
      return _memoryCache[url];
    }
    
    // Check painting binding cache
    final cachedImage = _paintingBinding.imageCache?.image;
    if (cachedImage != null) {
      return cachedImage;
    }
    
    try {
      final image = await _loadImage(url);
      _addToMemoryCache(url, image);
      return image;
    } catch (e) {
      return null;
    }
  }
  
  Future<ui.Image> _loadImage(String url) async {
    final completer = Completer<ui.Image>();
    final codec = await ui.instantiateImageCodec(
      await _fetchImageData(url),
    );
    final frame = await codec.getNextFrame();
    completer.complete(frame.image);
    return completer.future;
  }
  
  Future<Uint8List> _fetchImageData(String url) async {
    final response = await http.get(Uri.parse(url));
    return response.bodyBytes;
  }
  
  void _addToMemoryCache(String url, ui.Image image) {
    final imageSize = image.width * image.height * 4; // 4 bytes per pixel
    
    if (_currentCacheSize + imageSize > _maxCacheSize) {
      _evictLeastRecentlyUsed(imageSize);
    }
    
    _memoryCache[url] = image;
    _currentCacheSize += imageSize;
  }
  
  void _evictLeastRecentlyUsed(int requiredSize) {
    final entries = _memoryCache.entries.toList();
    entries.sort((a, b) => a.key.compareTo(b.key));
    
    int freedSize = 0;
    for (final entry in entries) {
      final imageSize = entry.value.width * entry.value.height * 4;
      _memoryCache.remove(entry.key);
      freedSize += imageSize;
      _currentCacheSize -= imageSize;
      
      if (freedSize >= requiredSize) {
        break;
      }
    }
  }
  
  void clearCache() {
    _memoryCache.clear();
    _currentCacheSize = 0;
    _paintingBinding.imageCache?.clear();
    _paintingBinding.imageCache?.clearLiveImages();
  }
}

// Resource management with automatic cleanup
class ResourceManager {
  final Map<String, StreamSubscription> _subscriptions = {};
  final Map<String, Timer> _timers = {};
  
  StreamSubscription<T>? addSubscription<T>(
    String key,
    StreamSubscription<T> subscription,
  ) {
    _subscriptions[key] = subscription as StreamSubscription;
    return subscription;
  }
  
  Timer? addTimer(String key, Duration duration, VoidCallback callback) {
    final timer = Timer(duration, callback);
    _timers[key] = timer;
    return timer;
  }
  
  void removeSubscription(String key) {
    final subscription = _subscriptions.remove(key);
    subscription?.cancel();
  }
  
  void removeTimer(String key) {
    final timer = _timers.remove(key);
    timer?.cancel();
  }
  
  void dispose() {
    for (final subscription in _subscriptions.values) {
      subscription.cancel();
    }
    _subscriptions.clear();
    
    for (final timer in _timers.values) {
      timer.cancel();
    }
    _timers.clear();
  }
}

// Widget with automatic resource cleanup
class AutoCleanupWidget extends StatefulWidget {
  final Widget child;
  final VoidCallback? onInit;
  final VoidCallback? onDispose;
  
  const AutoCleanupWidget({
    super.key,
    required this.child,
    this.onInit,
    this.onDispose,
  });
  
  @override
  State<AutoCleanupWidget> createState() => _AutoCleanupWidgetState();
}

class _AutoCleanupWidgetState extends State<AutoCleanupWidget> {
  final ResourceManager _resourceManager = ResourceManager();
  
  @override
  void initState() {
    super.initState();
    widget.onInit?.call();
  }
  
  @override
  void dispose() {
    _resourceManager.dispose();
    widget.onDispose?.call();
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    return widget.child;
  }
}
```

## Testing Strategy

### Unit Testing with Dart Test Framework

```dart
// Unit tests for business logic
void main() {
  group('UserRepository', () {
    late UserRepository userRepository;
    late MockDio mockDio;
    
    setUp(() {
      mockDio = MockDio();
      userRepository = HttpUserRepository(mockDio);
    });
    
    test('should return user when getUser is called with valid ID', () async {
      // Arrange
      final userId = '123';
      final userJson = {
        'id': userId,
        'name': 'John Doe',
        'email': 'john@example.com',
        'avatarUrl': 'https://example.com/avatar.jpg',
      };
      
      when(() => mockDio.get('/users/$userId'))
          .thenAnswer((_) async => Response(data: userJson, statusCode: 200));
      
      // Act
      final result = await userRepository.getUser(userId);
      
      // Assert
      expect(result.id, equals(userId));
      expect(result.name, equals('John Doe'));
      expect(result.email, equals('john@example.com'));
      expect(result.avatarUrl, equals('https://example.com/avatar.jpg'));
      
      verify(() => mockDio.get('/users/$userId')).called(1);
    });
    
    test('should throw UserRepositoryException when API call fails', () async {
      // Arrange
      final userId = '123';
      
      when(() => mockDio.get('/users/$userId'))
          .thenThrow(DioException(requestOptions: RequestOptions(path: '/users/$userId')));
      
      // Act & Assert
      expect(
        () => userRepository.getUser(userId),
        throwsA(isA<UserRepositoryException>()),
      );
      
      verify(() => mockDio.get('/users/$userId')).called(1);
    });
    
    test('should return users list when getUsers is called', () async {
      // Arrange
      final usersJson = [
        {
          'id': '1',
          'name': 'John Doe',
          'email': 'john@example.com',
          'avatarUrl': 'https://example.com/avatar1.jpg',
        },
        {
          'id': '2',
          'name': 'Jane Smith',
          'email': 'jane@example.com',
          'avatarUrl': 'https://example.com/avatar2.jpg',
        },
      ];
      
      when(() => mockDio.get('/users', queryParameters: any(named:

…(truncated)
