Adaptive Dialog Manager
A comprehensive Flutter package that provides adaptive, responsive dialog management across all platforms including mobile, web, desktop, and tablet with platform-specific behaviors, accessibility support, and advanced notification systems.
Features
🎉 New in v1.1.0: Advanced toast timing behavior with independent/dependent modes, enhanced snackbar dismissal controls, and improved debugging capabilities!
🎯 Adaptive & Responsive
- Multi-platform support: Android, iOS, Web, Windows, macOS, Linux
- Responsive design: Automatic layout adaptation for mobile, tablet, and desktop
- Platform-specific behaviors: Material, Cupertino, Fluent, and macOS design systems
- Breakpoint-aware: Smart sizing based on screen dimensions
- Advanced queue management: Handle multiple dialogs, snackbars, and toasts gracefully with intelligent queuing and timing control
🎨 Dialog System
- 25 dialog types: Alert, confirmation, input, loading, progress, bottomSheet, custom, modal, fullScreen, datePicker, timePicker, colorPicker, filePicker, search, settings, about, help, error, warning, success, info, toast, snackbar
- Platform-specific styling: Automatic adaptation to Material, Cupertino, Fluent, and macOS design languages
- Custom content support: Fully customizable dialog content with widget injection
- Advanced configurations: Comprehensive dialog configuration with safe type handling
🍞 Toast System
- 5 toast types: Info, success, warning, error, custom
- Flexible positioning: Top, bottom, center positioning with offset control
- Stack and column layouts: Traditional overlapping or vertical column display
- Column mode features: Maximum 4 visible toasts, clean vertical arrangement
- Advanced timing management: Independent and dependent timing behaviors with intelligent pause/resume
- Toast timing behavior: Independent (classic) or dependent (newer toasts pause older ones)
- Real-time timer control: Automatic duration control with position-aware timing management
- Custom content: Widget-based custom toast content with full styling control
📱 Snackbar System
- 10 snackbar types: Info, success, warning, error, loading, action, custom, toast, banner, persistent
- Advanced positioning: Top, bottom, center with fine-grained control (default: top)
- Behavior types: Queue, stack, replace, skip, force, priority, custom
- Stack layout: Display up to 5 snackbars simultaneously with stacking behavior
- Action support: Interactive buttons with customizable callbacks
- Priority queue: Intelligent priority-based queue management
- Queue behaviors: Smart handling of multiple snackbars with customizable limits
- Enhanced dismissal control: Advanced dismissible behavior with tap, swipe, auto-dismiss, and directional control
- Smart auto-dismiss logic: Context-aware dismissal based on snackbar type and configuration
- Animation customization: Custom animation duration, curves, directions, and platform-optimized timing
🎭 Animations & Transitions
- 31 animation types: None, fade, scale, slideFromBottom, slideFromTop, slideFromLeft, slideFromRight, slideUp, slideDown, elastic, bounce, rotation, flip, pop, blur, custom, plus compound animations combining multiple effects
- Platform-optimized timing: Adaptive durations and curves
- Performance profiles: Mobile-friendly and high-performance variants
- Reduced motion support: Accessibility-friendly alternatives
♿ Accessibility
- Screen reader support: Comprehensive semantic labeling
- Keyboard navigation: Full desktop keyboard support
- Focus management: Proper focus trapping and restoration
- High contrast support: Theme-aware color schemes
- Touch target sizing: Minimum accessibility requirements
🔧 Developer Experience
- Type-safe configuration: Strongly typed models extending BaseDataModel
- Dependency injection ready: Abstract interfaces for testability
- State tracking: Comprehensive lifecycle monitoring with streams
- Error handling: Robust exception management with detailed error reporting
- Advanced debug mode: Detailed logging with real-time timer monitoring and position tracking
- Queue monitoring: Real-time queue status and management with enhanced debugging
- ID generation utilities: Built-in unique ID generation for toast and dialog tracking
- Timing system debugging: Real-time timer status monitoring with pause/resume state tracking
Installation
Add to your pubspec.yaml
:
dependencies:
adaptive_dialog_manager: ^x.y.z
Run:
flutter pub get
Platform Setup
No additional platform-specific setup required. The package works out of the box on all supported platforms.
Quick Start
Basic Setup
import 'package:adaptive_dialog_manager/adaptive_dialog_manager.dart';
void main() {
// Initialize the managers
AdaptiveDialogManager.initialize();
AdaptiveSnackbarManager.initialize();
AdaptiveToastManager.initialize();
runApp(MyApp());
}
Dialog Examples
Simple Alert Dialog
final dialogManager = AdaptiveDialogManager.instance;
await dialogManager.showDialog(
context,
DialogConfig(
dialogType: DialogType.alert,
platformType: PlatformDetector.currentPlatform,
title: 'Hello World',
content: 'This is an adaptive dialog!',
),
);
Confirmation Dialog
final result = await dialogManager.showDialog<bool>(
context,
DialogConfig(
dialogType: DialogType.confirmation,
platformType: PlatformDetector.currentPlatform,
title: 'Delete Item',
content: 'Are you sure you want to delete this item?',
actions: [
DialogAction(
label: 'Cancel',
onPressed: () => Navigator.pop(context, false),
),
DialogAction(
label: 'Delete',
isPrimary: true,
isDestructive: true,
onPressed: () => Navigator.pop(context, true),
),
],
),
);
if (result?.data == true) {
// Handle deletion
}
Custom Dialog with Animations
final config = DialogConfig(
dialogType: DialogType.custom,
platformType: PlatformDetector.currentPlatform,
animationType: AnimationType.elastic,
animationDuration: const Duration(milliseconds: 600),
customContent: MyCustomWidget(),
backgroundColor: Colors.white,
borderRadius: BorderRadius.circular(16),
);
await dialogManager.showDialog(context, config);
Snackbar Examples
Basic Snackbars
final snackbarManager = AdaptiveSnackbarManager.instance;
// Success snackbar
await snackbarManager.showSnackbar(
context,
SnackbarConfig(
snackbarType: SnackbarType.success,
platformType: PlatformDetector.currentPlatform,
message: 'Operation completed successfully!',
),
);
// Error snackbar with action and custom dismissal
await snackbarManager.showSnackbar(
context,
SnackbarConfig(
snackbarType: SnackbarType.error,
platformType: PlatformDetector.currentPlatform,
message: 'Failed to save data',
showAction: true,
actionLabel: 'Retry',
onActionPressed: () => retryOperation(),
// Enhanced dismissal configuration
dismissible: true,
tapToDismiss: true,
swipeToDismiss: true,
dismissDirection: DismissDirection.endToStart,
duration: const Duration(seconds: 8),
),
);
Advanced Snackbar Configuration
final config = SnackbarConfig(
snackbarType: SnackbarType.custom,
platformType: PlatformDetector.currentPlatform,
message: 'Custom snackbar',
position: SnackbarPosition.top, // Default position is now top
behavior: SnackbarBehavior.floating,
duration: const Duration(seconds: 5),
backgroundColor: Colors.purple,
textColor: Colors.white,
borderRadius: BorderRadius.circular(12),
customContent: MyCustomSnackbarContent(),
// Enhanced dismissible and animation properties
dismissible: true, // Can be dismissed by user interaction
autoDismiss: true, // Auto-dismiss after duration (smart logic)
tapToDismiss: true, // Tap to dismiss
swipeToDismiss: true, // Swipe to dismiss
dismissDirection: DismissDirection.horizontal, // Swipe direction
animationDuration: const Duration(milliseconds: 400), // Custom animation timing
animationCurve: Curves.easeInOut, // Custom animation curve
);
await snackbarManager.showSnackbar(context, config);
Loading Snackbar with Controller
// Loading snackbar with controlled dismissal
final loadingController = snackbarManager.showLoading(
context: context,
message: 'Processing data...',
cancellable: true, // User can dismiss loading
showProgress: true,
);
// Update progress and message
loadingController.updateProgress(0.5);
loadingController.updateMessage('Halfway done...');
// Complete or cancel
loadingController.complete('Processing completed!');
// or loadingController.cancel();
Multiple Snackbars with Stack Behavior
// Single stacked snackbar
await snackbarManager.showSnackbar(
context,
SnackbarConfig(
snackbarType: SnackbarType.info,
platformType: PlatformDetector.currentPlatform,
message: 'Stacked snackbar',
position: SnackbarPosition.bottom,
behavior: SnackbarBehavior.stack, // Use stack behavior for multiple snackbars
duration: const Duration(seconds: 5),
),
);
// Multiple snackbars stacked (max 5 visible at once)
final messages = ['Task 1 Complete', 'File Uploaded', 'Sync Finished'];
final types = [SnackbarType.success, SnackbarType.info, SnackbarType.success];
for (int i = 0; i < messages.length; i++) {
await snackbarManager.showSnackbar(
context,
SnackbarConfig(
snackbarType: types[i],
platformType: PlatformDetector.currentPlatform,
message: messages[i],
position: SnackbarPosition.bottom,
behavior: SnackbarBehavior.stack,
duration: const Duration(seconds: 6),
showIcon: true,
),
);
}
// Customize behavior limits
snackbarManager.updateBehaviorSettings(
maxSimultaneous: 5, // Allow up to 5 simultaneous snackbars
);
Toast Examples
Basic Toast Notifications
final toastManager = AdaptiveToastManager.instance;
// Info toast
await toastManager.showInfo(
context,
message: 'This is an info message',
title: 'Information',
);
// Success toast
await toastManager.showSuccess(
context,
message: 'Data saved successfully!',
duration: const Duration(seconds: 3),
);
// Error toast
await toastManager.showError(
context,
message: 'Failed to load data',
title: 'Error',
);
Custom Toast
await toastManager.showCustom(
context,
content: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(8),
),
child: const Text(
'Custom Toast Content',
style: TextStyle(color: Colors.white),
),
),
duration: const Duration(seconds: 4),
);
Column Layout Toast
// Show toast in column layout mode
await toastManager.showToast<String>(
context,
ToastConfig(
toastType: ToastType.info,
platformType: PlatformDetector.currentPlatform,
message: 'Column layout toast',
title: 'Information',
position: ToastPosition.bottomCenter,
layout: ToastLayout.column, // Use column layout
duration: const Duration(seconds: 4),
),
);
// Multiple toasts in column - max 4 visible at once
for (int i = 1; i <= 6; i++) {
await toastManager.showToast<String>(
context,
ToastConfig(
toastType: ToastType.success,
platformType: PlatformDetector.currentPlatform,
message: 'Toast #$i',
layout: ToastLayout.column,
position: ToastPosition.topCenter,
),
);
}
// Only 4 toasts will be visible at once in column mode
Advanced Toast Timing Behavior
// Independent timing (classic behavior) - each toast dismisses independently
await toastManager.showToast<String>(
context,
ToastConfig(
toastType: ToastType.info,
platformType: PlatformDetector.currentPlatform,
message: 'Independent timing toast',
timingBehavior: ToastTimingBehavior.independent,
duration: const Duration(seconds: 3),
),
);
// Dependent timing (new feature) - older toasts pause when newer ones appear
await toastManager.showToast<String>(
context,
ToastConfig(
toastType: ToastType.success,
platformType: PlatformDetector.currentPlatform,
message: 'Dependent timing toast',
timingBehavior: ToastTimingBehavior.dependent, // Default
duration: const Duration(seconds: 5),
),
);
// Multiple toasts with dependent timing
for (int i = 1; i <= 3; i++) {
await toastManager.showToast<String>(
context,
ToastConfig(
toastType: ToastType.warning,
platformType: PlatformDetector.currentPlatform,
message: 'Toast #$i - will pause when newer toast appears',
timingBehavior: ToastTimingBehavior.dependent,
duration: const Duration(seconds: 4),
),
);
}
// Only the topmost toast will actively count down, others pause until visible
Advanced Usage
Platform Detection & Responsive Design
// Get current platform
final platformType = PlatformDetector.currentPlatform;
// Get responsive breakpoint
final breakpoint = ResponsiveBreakpoint.fromWidth(
MediaQuery.of(context).size.width,
);
// Create responsive configuration
final responsiveConfig = ResponsiveConfig(
breakpoint: breakpoint,
maxWidth: breakpoint.isDesktop ? 600 : double.infinity,
padding: breakpoint.isMobile
? const EdgeInsets.all(16)
: const EdgeInsets.all(24),
);
Queue Management
// Get queue status
final dialogQueue = DialogQueueManager.instance;
final snackbarQueue = SnackbarQueueManager.instance;
final toastQueue = ToastQueueManager.instance;
// Monitor queue changes
dialogQueue.stateStream.listen((dialogState) {
print('Dialog state: ${dialogState.status}');
});
// Clear queues
await dialogQueue.clearQueue();
await snackbarQueue.clearQueue();
await toastQueue.clearQueue();
Debug Mode
// Enable debug logging
AdaptiveDialogManager.instance.enableDebugMode();
AdaptiveSnackbarManager.instance.enableDebugMode();
AdaptiveToastManager.instance.enableDebugMode();
// View queue status
final dialogStatus = DialogQueueManager.instance.getQueueStatus();
print('Active dialogs: ${dialogStatus.activeCount}');
print('Pending dialogs: ${dialogStatus.pendingCount}');
Architecture
Core Classes
AdaptiveDialogManager
- Main dialog manager singletonAdaptiveSnackbarManager
- Snackbar manager singletonAdaptiveToastManager
- Toast manager singletonDialogConfig
- Dialog configuration modelSnackbarConfig
- Snackbar configuration modelToastConfig
- Toast configuration model with timing behavior supportDialogResult<T>
- Type-safe dialog resultSnackbarResult<T>
- Type-safe snackbar resultToastResult<T>
- Type-safe toast resultPlatformDetector
- Platform detection utilityResponsiveManager
- Responsive layout managerToastTimingManager
- Advanced toast timing control managerIdGenerator
- Utility for generating unique IDs
Enums
DialogType
- 25 dialog typesSnackbarType
- 10 snackbar typesToastType
- 5 toast typesPlatformType
- 7 supported platformsAnimationType
- 31 animation options including compound animationsResponsiveBreakpoint
- Screen size breakpointsSnackbarPosition
,SnackbarBehavior
- Advanced snackbar optionsToastPosition
,ToastLayout
- Toast positioning and layout optionsToastTimingBehavior
- Independent vs dependent timing behaviorToastDisplayMode
- Stack vs column display modes
Interfaces
abstract class DialogManager {
Future<DialogResult<T?>?> showDialog<T>(BuildContext context, DialogConfig config);
Stream<DialogState> get stateStream;
void enableDebugMode();
void disableDebugMode();
}
abstract class SnackbarManager {
Future<SnackbarResult<T?>?> showSnackbar<T>(BuildContext context, SnackbarConfig config);
LoadingSnackbarController showLoading({required BuildContext context, String message, bool cancellable});
Stream<SnackbarState> get stateStream;
}
abstract class ToastManager {
Future<ToastResult<T>?> showToast<T>(BuildContext context, ToastConfig config);
Future<ToastResult<String>?> showInfo(BuildContext context, {required String message});
Future<ToastResult<String>?> showSuccess(BuildContext context, {required String message});
Future<ToastResult<String>?> showWarning(BuildContext context, {required String message});
Future<ToastResult<String>?> showError(BuildContext context, {required String message});
}
Testing
Unit Testing
import 'package:flutter_test/flutter_test.dart';
import 'package:adaptive_dialog_manager/adaptive_dialog_manager.dart';
void main() {
group('DialogConfig', () {
test('should create valid configuration', () {
final config = DialogConfig(
dialogType: DialogType.alert,
platformType: PlatformType.android,
title: 'Test',
content: 'Test content',
);
expect(config.dialogType, DialogType.alert);
expect(config.title, 'Test');
expect(config.content, 'Test content');
});
});
group('PlatformDetector', () {
test('should detect current platform', () {
final platform = PlatformDetector.currentPlatform;
expect(platform, isA<PlatformType>());
});
});
}
Widget Testing
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:adaptive_dialog_manager/adaptive_dialog_manager.dart';
void main() {
setUp(() {
AdaptiveDialogManager.initialize();
});
testWidgets('should show adaptive dialog', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: Builder(
builder: (context) => ElevatedButton(
onPressed: () async {
await AdaptiveDialogManager.instance.showDialog(
context,
DialogConfig(
dialogType: DialogType.alert,
platformType: PlatformDetector.currentPlatform,
title: 'Test Dialog',
content: 'Test content',
),
);
},
child: const Text('Show Dialog'),
),
),
),
);
await tester.tap(find.text('Show Dialog'));
await tester.pumpAndSettle();
expect(find.text('Test Dialog'), findsOneWidget);
expect(find.text('Test content'), findsOneWidget);
});
}
Performance
Optimization Features
- Lazy initialization: Managers initialize only when needed
- Efficient queue management: Optimized algorithms for multiple notifications
- Memory management: Automatic cleanup and disposal
- Animation optimization: Mobile-friendly and high-performance variants
- Platform-specific optimizations: Tailored behavior for each platform
Performance Profiles
// Mobile-optimized configuration
final mobileConfig = DialogConfig(
dialogType: DialogType.alert,
platformType: PlatformDetector.currentPlatform,
animationType: AnimationType.fade, // Simple animation
animationDuration: const Duration(milliseconds: 200), // Faster
);
// Desktop-optimized configuration
final desktopConfig = DialogConfig(
dialogType: DialogType.alert,
platformType: PlatformDetector.currentPlatform,
animationType: AnimationType.elastic, // Complex animation
animationDuration: const Duration(milliseconds: 600), // Longer
);
Accessibility
Built-in Accessibility Features
- Screen reader support: Comprehensive semantic labeling
- Keyboard navigation: Full desktop keyboard support
- Focus management: Proper focus trapping and restoration
- High contrast support: Theme-aware color schemes
- Touch target sizing: Minimum 48dp touch targets
- Reduced motion: Automatic detection and adaptation
Accessibility Configuration
final accessibleConfig = DialogConfig(
dialogType: DialogType.alert,
platformType: PlatformDetector.currentPlatform,
semanticLabel: 'Important alert dialog',
animationType: MediaQuery.of(context).accessibleNavigation
? AnimationType.fade
: AnimationType.scale,
);
API Reference
For complete API documentation, visit pub.flutter-io.cn documentation.
Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
- Fork the repository
- Clone your fork:
git clone https://github.com/yourusername/flutter-adaptive-dialog-manager.git
- Install dependencies:
flutter pub get
- Run the example:
cd example && flutter run
- Make your changes and test thoroughly
- Submit a pull request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog
See CHANGELOG.md for a detailed history of changes.
Support
- Documentation: API Reference
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Email: bahricanyesildev@gmail.com
Author
Bahrican Yeşil - GitHub | LinkedIn
Made with ❤️ in Turkey
Libraries
- adaptive_dialog_manager
- Adaptive Dialog Manager - A comprehensive Flutter package for multi-platform dialog management