Core Features
This document provides detailed information about the core features in the Flutter Riverpod Clean Architecture template.
Analytics Integration
Track user interactions and app performance with a flexible analytics system:
// Access analytics
final analytics = ref.watch(analyticsProvider);
// Log screen views
analytics.logScreenView('HomeScreen', parameters: {'referrer': 'deeplink'});
// Log user actions
analytics.logUserAction(
action: 'button_tap',
category: 'engagement',
label: 'sign_up_button',
);
// Track errors
analytics.logError(
errorType: 'network_error',
message: 'Failed to fetch user data',
isFatal: false,
);
// Measure performance
analytics.logPerformance(
name: 'image_processing',
value: 340.5,
unit: 'ms',
);
// Use automatic screen tracking
return AnalyticsScreenView(
screenName: 'ProductDetailsScreen',
parameters: {'product_id': product.id},
child: Scaffold(/* ... */),
);
For more details, see the Analytics Guide.
Push Notifications
Complete notification handling with deep linking and background processing:
// Access notification service
final service = ref.watch(notificationServiceProvider);
// Request permission
final status = await service.requestPermission();
// Show a local notification
await service.showLocalNotification(
id: 'msg-123',
title: 'New message',
body: 'You received a new message from John',
action: '/chat/john',
channel: 'messages',
);
// Subscribe to topics
await service.subscribeToTopic('news');
// Handle notification taps through the deep link handler
final deepLinkHandler = ref.watch(notificationDeepLinkHandlerProvider);
final pendingDeepLink = deepLinkHandler.pendingDeepLink;
if (pendingDeepLink != null) {
router.push(pendingDeepLink);
deepLinkHandler.clearPendingDeepLink();
}
Biometric Authentication
Secure fingerprint and face recognition for protecting sensitive operations:
// Access biometric authentication
final biometricAuth = ref.watch(biometricAuthControllerProvider);
// Check if biometrics are available
final isAvailable = await ref.watch(biometricsAvailableProvider.future);
// Authenticate the user
if (isAvailable) {
final result = await biometricAuth.authenticate(
reason: 'Please authenticate to access your account',
authReason: AuthReason.appAccess,
);
if (result == BiometricResult.success) {
// User authenticated successfully
navigator.push('/secure_area');
}
}
// Check if session has expired
if (biometricAuth.isAuthenticationNeeded(timeout: Duration(minutes: 5))) {
// Re-authenticate the user
}
For more details, see the Biometric Auth Guide.
Feature Flags
Runtime feature toggling for A/B testing and staged rollouts:
// Access feature flag service
final service = ref.watch(featureFlagServiceProvider);
// Check if a feature is enabled
if (service.isFeatureEnabled('premium_features')) {
// Show premium features
}
// Get a configuration value
final apiTimeout = service.getInt('api_timeout_ms', defaultValue: 30000);
// Using the provider helpers
final isDarkModeEnabled = ref.watch(featureFlagProvider('enable_dark_mode', defaultValue: true));
final primaryColor = ref.watch(colorConfigProvider('primary_color', defaultValue: Colors.blue));
// Use the feature flag widget
return FeatureFlag(
featureKey: 'experimental_ui',
child: NewExperimentalWidget(),
fallback: ClassicWidget(),
);
For more details, see the Feature Flags Guide.
Advanced Image Handling
Optimized image loading with caching, SVG support, effects, and beautiful placeholders:
// Process images
final processor = ref.watch(imageProcessorProvider);
final thumbnail = await processor.generateThumbnail(
imageData: imageBytes,
maxDimension: 200,
quality: 80,
);
// Advanced image widget with shimmer placeholders
return AdvancedImage(
imageUrl: 'https://example.com/image.jpg',
width: 300,
height: 200,
fit: BoxFit.cover,
placeholder: ShimmerPlaceholder(
borderRadius: BorderRadius.circular(8),
),
useThumbnailPreview: true,
fadeInDuration: Duration(milliseconds: 300),
);
// SVG rendering with coloring
SvgImage.asset(
'assets/images/icon.svg',
width: 48,
height: 48,
color: Theme.of(context).primaryColor,
);
// Apply visual effects to images
ImageTransformer(
effect: ImageEffectConfig(
effectType: ImageEffectType.sepia,
intensity: 0.7,
),
child: Image.network('https://example.com/photo.jpg'),
);
For more details, see the Image Handling Guide.
Multi-language Support
Built-in internationalization with easy language switching:
// Access translated text
Text(context.tr('common.welcome_message'));
// With parameters
Text(context.tr('user.greeting', {'name': userData.displayName}));
// Format dates based on current locale
Text(context.formatDate(DateTime.now(), 'medium'));
// Format currency based on current locale
Text(context.formatCurrency(19.99));
// Change language
ref.read(localeProvider.notifier).setLocale(const Locale('es'));
// Access language-specific assets
Image.asset(LocalizedAssetService.getLocalizedImagePath('logo.png'));
For more details, see the Localization Guide.
Advanced Caching System
The project implements a robust two-level caching system with both memory and disk storage options:
// Memory cache configuration
final userMemoryCacheProvider = memoryCacheManagerProvider<UserEntity>();
// Disk cache with type-safe parameters
final userDiskCacheParams = DiskCacheParams<UserEntity>(
config: CacheConfig(
maxItems: 100,
expiryDuration: Duration(hours: 24),
encryption: true
),
fromJson: (json) => UserModel.fromJson(json).toEntity(),
toJson: (user) => UserModel.fromEntity(user).toJson(),
);
final userDiskCacheProvider = diskCacheManagerProvider<UserEntity>(userDiskCacheParams);
// Using the cache
final cacheManager = ref.watch(userDiskCacheProvider);
await cacheManager.setItem('user_1', userEntity);
final cachedUser = await cacheManager.getItem('user_1');
Dynamic Theming
The theme system allows for complete customization of app appearance:
// Access the theme configuration
final themeConfig = ref.watch(themeConfigProvider);
final themeMode = ref.watch(themeModeProvider);
// Use in MaterialApp
return MaterialApp(
theme: themeConfig.lightTheme,
darkTheme: themeConfig.darkTheme,
themeMode: themeMode,
);
// Update theme settings
ref.read(themeConfigProvider.notifier).updatePrimaryColor(Colors.indigo);
ref.read(themeConfigProvider.notifier).updateBorderRadius(8.0);
ref.read(themeModeProvider.notifier).state = ThemeMode.dark;
Accessibility
Make your app inclusive and usable by everyone:
// Access accessibility settings
final accessibilitySettings = ref.watch(accessibilitySettingsProvider);
// Check if screen reader is active
if (accessibilitySettings.isScreenReaderActive) {
// Provide additional context for screen readers
}
// Announce messages to screen reader
final notifier = ref.read(accessibilitySettingsProvider.notifier);
notifier.announce('Item added to cart successfully');
// Use accessible widgets
AccessibleButton(
onPressed: () => doSomething(),
semanticLabel: 'Save changes',
child: Text('Save'),
)
// Extend regular widgets with accessibility
myButton.withMinimumTouchTargetSize()
myImage.withSemanticLabel('Profile picture')
For more details, see the Accessibility Guide.
Offline-First Architecture
Keep your app working seamlessly with or without an internet connection:
// Queue changes when offline
await offlineSyncService.queueChange(
entityType: 'task',
operationType: OfflineOperationType.create,
data: {
'title': 'Buy groceries',
'completed': false,
},
);
// Watch for pending changes
final pendingChanges = ref.watch(pendingChangesProvider);
pendingChanges.when(
data: (changes) => Text('Pending changes: ${changes.length}'),
loading: () => CircularProgressIndicator(),
error: (_, __) => Text('Error'),
);
// Show sync status
OfflineStatusIndicator()
For more details, see the Offline Architecture Guide.
App Update Flow
Manage app updates with customizable flows:
// Check for updates
final updateController = ref.read(updateControllerProvider.notifier);
await updateController.checkForUpdates();
// Show update dialog
if (result == UpdateCheckResult.updateAvailable) {
final updateInfo = await updateController.getUpdateInfo();
showDialog(
context: context,
builder: (context) => UpdateDialog(
updateInfo: updateInfo!,
isCritical: false,
),
);
}
// Force critical updates
if (result == UpdateCheckResult.criticalUpdateRequired) {
// Prevent app usage until updated
}
App Review System
Get feedback and ratings from your users:
final reviewService = ref.read(appReviewServiceProvider);
// Record significant actions that might trigger a review
await reviewService.recordSignificantAction();
// Show feedback form before store review
final hasFeedback = await reviewService.showFeedbackForm(
context: context,
title: "Enjoying the App?",
message: "We'd love to hear your feedback!",
);
// Request store review
if (shouldRequestReview) {
await reviewService.requestReview();
}