SavePoints Modern UI ๐จ
๐น Demo
A comprehensive Flutter package providing elegant, customizable UI components with stunning glassmorphism effects, smooth animations, and extensive customization options. Perfect for building modern, professional user interfaces.
Contents
| Overview ยท Key features | what this is |
| Installation ยท Quick start | five minutes in |
| Design styles | the twelve looks, and when to use each |
| Dialog ยท Snackbar ยท Bottom sheet | every parameter |
| Dialog presets ยท Animations | ready-made choices |
Configuration ยท SavePointsTheme |
defaults, app-wide or per subtree |
| Building on the same styles | SpStyles for your own widgets |
| Accessibility ยท Performance | what the package guarantees |
๐ Overview
SavePoints Modern UI is a production-ready Flutter package that offers three powerful, feature-rich UI components:
- ๐ญ Dialogs - Beautiful modal dialogs with glassmorphism design
- ๐ Snackbars - Enhanced notifications with rich animations and customization
- ๐ฑ Bottom Sheets - Modern bottom sheets with drag handles and scroll support
All three share one bold & expressive design language and the same 12 visual styles, from an understated minimal through frosted glass to a loud brutalist. Every style is resolved in one place, so it looks like itself on a dialog, a snackbar and a bottom sheet alike. See Design styles.
All components feature automatic dark mode support, extensive customization options, and are optimized for performance with built-in repaint boundaries and efficient animations. The codebase follows professional Flutter best practices with comprehensive documentation, well-organized structure, and maintainable code.
โจ Key Features
๐ญ SavePointsDialog
- โจ Glassmorphism Design - Beautiful frosted glass effects with backdrop blur
- ๐จ 12 design styles -
solid,outlined,tonal,colorHeader,leftAccent,glass,neon,minimal,brutalist,gradientBorder,aurora,softโcolorHeaderby default, all in light & dark. See the table - ๐จ Fully Customizable - Colors, icons, buttons, and animations
- โก Smooth Animations - Multiple animation types including fade, slide, scale, bounce, and more
- ๐ Dark Mode Support - Automatic theme adaptation
- ๐ฑ Loading States - Built-in support for async operations with loading indicators
- ๐ฏ Flexible Actions - Single or dual button configurations
- ๐งฉ Custom Content - Add custom widgets (forms, ratings, etc.) with the optional
childparameter - ๐ณ Haptic Feedback - Enhanced user experience with tactile responses
- ๐ Async Support - Handle asynchronous confirm callbacks with loading states
๐ SavePointsSnackbar
- ๐ Multiple Types - Success, Error, Warning, and Info variants with predefined styling
- ๐จ 12 design styles -
solid,outlined,tonal,colorHeader,leftAccent,glass,neon,minimal,brutalist,gradientBorder,aurora,softโsolidby default, all in light & dark. See the table - ๐ฌ Rich Animations - 7+ animation types: fade, slide, scale, bounce, rotate, elastic, slideRotate
- ๐ Progress Indicators - Optional progress bars for timed notifications
- ๐จ Gradient Backgrounds - Support for custom gradient designs
- ๐ Position Control - Display at top or bottom of screen with smart margin calculation
- ๐ Interactive - Tap to dismiss, custom tap handlers, and action buttons
- ๐ฏ Customizable Styling - Borders, border radius, margins, colors, and more
- ๐ณ Haptic Feedback - Configurable haptic responses
- โฟ Announced - Snackbars are a
Semanticslive region, so TalkBack and VoiceOver read them on arrival - โก Performance Optimized - Efficient animations with clamped values
๐ฑ SavePointsBottomsheet
- โจ Modern Design - Glassmorphism effects with backdrop blur
- ๐จ 12 design styles -
solid,outlined,tonal,colorHeader,leftAccent,glass,neon,minimal,brutalist,gradientBorder,aurora,softโcolorHeaderby default, all in light & dark. See the table - ๐๏ธ Drag Handle - Optional drag indicator for better UX
- ๐ Scrollable Content - Built-in support for scrollable content with proper constraints
- โจ๏ธ Keyboard Aware - Automatically positions above keyboard when TextFormField is focused
- โณ Loading States - Support for loading indicators during async operations
- ๐ฌ Custom Animations - Flexible enter and exit animations
- ๐ Flexible Sizing - Customizable max height and constraints
- ๐ Dark Mode Support - Automatic theme adaptation
- ๐ฏ Dismissible & Draggable - Full control over user interactions
๐ฆ Installation
Add save_points_snackbar_dialog_bottomsheet to your pubspec.yaml:
dependencies:
save_points_snackbar_dialog_bottomsheet: ^1.2.1
Requires Dart ^3.6.0 (Flutter 3.27 or newer).
Install the package:
flutter pub get
Import the package:
import 'package:save_points_snackbar_dialog_bottomsheet/save_points_snackbar_dialog_bottomsheet.dart';
๐ Quick Start
Basic Dialog
SavePointsDialog.show(
context,
title: 'Success',
message: 'Your changes have been saved successfully!',
icon: Icons.check_circle,
iconColor: Colors.green,
onConfirm: () {
// Handle confirmation
},
);
Basic Snackbar
SavePointsSnackbar.showSuccess(
context,
title: 'Success!',
subtitle: 'Operation completed successfully',
showProgressIndicator: true,
);
Basic Bottom Sheet
SavePointsBottomsheet.show(
context: context,
title: 'Options',
icon: Icons.more_vert,
child: YourContentWidget(),
);
Design styles
All three components share one bold & expressive design language and the same
set of visual styles via ContentDesignStyle. Every style adapts to light and
dark themes.
| Style | Look | Reach for it when |
|---|---|---|
solid |
Vivid gradient fill, white content, a same-hue glow โ snackbar default | The message is the colour: a success, an error |
colorHeader |
Vivid gradient band across the top with a circular icon chip โ dialog & sheet default | A moment deserves a header |
outlined |
Neutral surface inside a coloured border | You want the accent without the weight |
tonal |
Softly tinted surface (Material 3 tonal) | Quiet, but still carrying the intent colour |
leftAccent |
Neutral surface with a gradient bar down the leading edge | Lists and stacked notices, where a bar scans faster |
glass |
Frosted translucency over a backdrop blur, hairline highlight | There is something worth seeing behind it |
neon |
Near-black surface, glowing accent ring, wide bloom | Dark UIs, or anything that should look electric |
minimal |
Opaque surface, one hairline, perfectly flat | The component should get out of the way |
brutalist |
Flat punchy fill, thick hard border, an offset shadow with no blur | Graphic, loud, deliberately un-soft |
gradientBorder |
Neutral surface ringed by a vivid gradient stroke | Premium framing without tinting the content |
aurora |
A multi-stop wash of the accent bleeding across the surface | Hero moments; the most expressive of the set |
soft |
Pastel fill, generous rounding, light-from-above shadows | Friendly and tactile โ onboarding, empty states |
Pick any style per call:
// Snackbar โ solid vivid gradient (default)
SavePointsSnackbar.showSuccess(context, title: 'Done!', subtitle: 'Saved.');
// Dialog โ frosted glass
SavePointsDialog.show(
context,
title: 'Frosted',
message: 'Glassmorphism dialog.',
designStyle: ContentDesignStyle.glass,
);
// Bottom sheet โ neon
SavePointsBottomsheet.show(
context: context,
title: 'Neon',
designStyle: ContentDesignStyle.neon,
child: YourContentWidget(),
);
Or set the default once for a whole subtree โ the recommended way, since it covers all three surfaces at once and rebuilds descendants when it changes:
SavePointsTheme(
data: const SavePointsThemeData(designStyle: ContentDesignStyle.glass),
child: MaterialApp(/* ... */),
);
๐ Complete Documentation
๐ญ SavePointsDialog
Method Signature
static Future<bool?> show(
BuildContext context, {
required String title,
required String message,
String? confirmText,
String? cancelText,
IconData? icon,
Color? iconColor,
Color? backgroundColor,
Color? confirmButtonColor,
Color? cancelButtonColor,
bool? showCancelButton,
VoidCallback? onConfirm,
Future<bool> Function()? onConfirmAsync,
VoidCallback? onCancel,
bool? barrierDismissible,
DialogAnimationType? animationType,
DialogAnimationDirection? startAnimation,
DialogAnimationDirection? endAnimation,
bool isLoading = false,
ValueNotifier<bool>? loadingNotifier,
bool hideLikeCircle = false,
ContentDesignStyle? designStyle,
double? blur,
ImageFilter? backdropFilter,
Widget? child,
})
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
title |
String |
โ Yes | - | Dialog title text |
message |
String |
โ Yes | - | Dialog message/body text |
confirmText |
String? |
No | "OK" |
Confirm button text |
cancelText |
String? |
No | "Cancel" |
Cancel button text |
icon |
IconData? |
No | null |
Optional icon displayed at the top |
iconColor |
Color? |
No | Theme-based | Icon color |
backgroundColor |
Color? |
No | Theme-based | Dialog background color |
confirmButtonColor |
Color? |
No | Theme-based | Confirm button color |
cancelButtonColor |
Color? |
No | Colors.grey |
Cancel button color |
showCancelButton |
bool? |
No | false |
Show cancel button |
onConfirm |
VoidCallback? |
No | null |
Callback when confirm is pressed |
onConfirmAsync |
Future<bool> Function()? |
No | null |
Async callback returning bool (true = close dialog) |
onCancel |
VoidCallback? |
No | null |
Callback when cancel is pressed |
barrierDismissible |
bool? |
No | true |
Allow dismissing by tapping outside |
animationType |
DialogAnimationType? |
No | fadeSlide |
Animation type (legacy) |
startAnimation |
DialogAnimationDirection? |
No | null |
Enter animation direction |
endAnimation |
DialogAnimationDirection? |
No | null |
Exit animation direction |
isLoading |
bool |
No | false |
Initial loading state |
loadingNotifier |
ValueNotifier<bool>? |
No | null |
External loading state control |
hideLikeCircle |
bool |
No | false |
Disable circular reveal exit animation |
designStyle |
ContentDesignStyle? |
No | colorHeader |
solid / outlined / tonal / colorHeader / leftAccent / glass / neon / minimal |
blur |
double? |
No | 20.0 |
Barrier blur sigma. Falls back to SavePointsTheme, then to defaultBarrierBlurSigma. Pass 0 to opt out |
backdropFilter |
ImageFilter? |
No | null |
Custom backdrop filter (overrides blur when set) |
enablePulse |
bool? |
No | false |
Loops a subtle scale + glow on the icon. Off by default: it never stops, so it repaints every frame and hangs pumpAndSettle() in tests |
child |
Widget? |
No | null |
Custom widget displayed between message and buttons |
Examples
1. Info Dialog
SavePointsDialog.show(
context,
title: 'Information',
message: 'This is an informational dialog with a custom icon and message.',
icon: Icons.info,
iconColor: Colors.blue,
onConfirm: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Dialog confirmed!')),
);
},
);
2. Success Dialog
SavePointsDialog.show(
context,
title: 'Success!',
message: 'Your action has been completed successfully.',
icon: Icons.check_circle,
iconColor: Colors.green,
confirmText: 'Great!',
onConfirm: () {},
);
3. Confirmation Dialog
SavePointsDialog.show(
context,
title: 'Confirm Action',
message: 'Are you sure you want to proceed? This action cannot be undone.',
icon: Icons.warning,
iconColor: Colors.orange,
confirmText: 'Yes, Continue',
cancelText: 'Cancel',
showCancelButton: true,
onConfirm: () {
SavePointsSnackbar.showSuccess(
context,
title: 'Confirmed!',
subtitle: 'Action has been completed',
);
},
onCancel: () {
SavePointsSnackbar.show(
context,
title: 'Cancelled',
subtitle: 'Action was cancelled',
type: SnackbarType.info,
);
},
);
4. Error Dialog
SavePointsDialog.show(
context,
title: 'Error',
message: 'Something went wrong. Please try again later.',
icon: Icons.error,
iconColor: Colors.red,
confirmText: 'OK',
onConfirm: () {},
);
5. Dialog with Async Loading State
final loadingNotifier = ValueNotifier<bool>(false);
SavePointsDialog.show(
context,
title: 'Processing',
message: 'Please wait while we process your request...',
isLoading: false,
loadingNotifier: loadingNotifier,
onConfirmAsync: () async {
loadingNotifier.value = true;
await Future.delayed(const Duration(seconds: 3));
loadingNotifier.value = false;
return true; // Close dialog on success
},
);
6. Custom Animation Dialog
SavePointsDialog.show(
context,
title: 'Animated Dialog',
message: 'This dialog has custom enter and exit animations!',
startAnimation: DialogAnimationDirection.fromLeft,
endAnimation: DialogAnimationDirection.fromRight,
icon: Icons.celebration,
);
7. Dialog with Custom Backdrop Blur
import 'dart:ui';
SavePointsDialog.show(
context,
title: 'Glassmorphism',
message: 'Custom blur intensity for the frosted glass effect.',
blur: 24.0,
icon: Icons.blur_on,
);
// Or disable blur: blur: 0
8. Dialog with Custom Child Widget (Form)
final nameController = TextEditingController();
final emailController = TextEditingController();
SavePointsDialog.show(
context,
title: 'User Information',
message: 'Please fill in your details below:',
icon: Icons.person_add,
iconColor: Colors.deepPurple,
confirmText: 'Submit',
cancelText: 'Cancel',
showCancelButton: true,
child: Column(
mainAxisSize: .min,
children: [
TextField(
controller: nameController,
decoration: InputDecoration(
labelText: 'Name',
hintText: 'Enter your name',
prefixIcon: const Icon(Icons.person),
border: OutlineInputBorder(
borderRadius: .circular(12),
),
filled: true,
),
),
const SizedBox(height: 12),
TextField(
controller: emailController,
decoration: InputDecoration(
labelText: 'Email',
hintText: 'Enter your email',
prefixIcon: const Icon(Icons.email),
border: OutlineInputBorder(
borderRadius: .circular(12),
),
filled: true,
),
keyboardType: TextInputType.emailAddress,
),
],
),
onConfirm: () {
if (nameController.text.isNotEmpty && emailController.text.isNotEmpty) {
// Process form data
print('Name: ${nameController.text}, Email: ${emailController.text}');
}
nameController.dispose();
emailController.dispose();
},
onCancel: () {
nameController.dispose();
emailController.dispose();
},
);
9. Dialog with Interactive Rating Widget
int rating = 0;
SavePointsDialog.show(
context,
title: 'Rate Your Experience',
message: 'How would you rate our service?',
icon: Icons.star_rounded,
iconColor: Colors.amber,
designStyle: ContentDesignStyle.colorHeader,
confirmText: 'Submit Rating',
cancelText: 'Skip',
showCancelButton: true,
child: StatefulBuilder(
builder: (context, setState) {
return Row(
mainAxisAlignment: MainAxis.center,
children: List.generate(5, (index) {
return IconButton(
icon: Icon(
index < rating ? Icons.star : Icons.star_border,
size: 40,
),
color: Colors.amber,
onPressed: () {
setState(() {
rating = index + 1;
});
},
);
}),
);
},
),
onConfirm: () {
if (rating > 0) {
print('User rated: $rating stars');
}
},
);
๐ SavePointsSnackbar
Method Signature
static ScaffoldFeatureController<SnackBar, SnackBarClosedReason> show(
BuildContext context, {
required String title,
String? subtitle,
Color? background,
Gradient? gradient,
Duration? duration,
IconData? icon,
Color? iconColor,
VoidCallback? onActionPressed,
String? actionLabel,
SnackbarType? type,
SnackbarPosition? position,
SnackbarAnimation? animation,
SnackbarAnimationDirection? startAnimation,
SnackbarAnimationDirection? endAnimation,
bool? showProgressIndicator,
bool? dismissible,
bool? enableHapticFeedback,
bool? dismissOnTap,
double? maxWidth,
EdgeInsets? margin,
BorderRadius? borderRadius,
Color? borderColor,
double? borderWidth,
VoidCallback? onDismissed,
VoidCallback? onTap,
ContentDesignStyle? designStyle,
double? blur,
ImageFilter? backdropFilter,
})
Quick Methods
showSuccess(context, {...})- Success variant with green stylingshowError(context, {...})- Error variant with red stylingshowWarning(context, {...})- Warning variant with orange styling
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
title |
String |
โ Yes | - | Snackbar title text |
subtitle |
String? |
No | null |
Optional subtitle text |
type |
SnackbarType? |
No | info |
Type: info, success, error, warning |
position |
SnackbarPosition? |
No | top |
Position: top or bottom |
animation |
SnackbarAnimation? |
No | fadeSlide |
Animation type (legacy) |
startAnimation |
SnackbarAnimationDirection? |
No | null |
Enter animation direction |
endAnimation |
SnackbarAnimationDirection? |
No | null |
Exit animation direction |
duration |
Duration? |
No | 4 seconds |
Display duration |
showProgressIndicator |
bool? |
No | false |
Show progress bar |
gradient |
Gradient? |
No | null |
Custom gradient background |
borderColor |
Color? |
No | null |
Border color |
borderWidth |
double? |
No | 0 |
Border width |
dismissOnTap |
bool? |
No | false |
Dismiss when tapped |
onTap |
VoidCallback? |
No | null |
Custom tap handler |
onDismissed |
VoidCallback? |
No | null |
Callback when dismissed |
designStyle |
ContentDesignStyle? |
No | solid |
solid / outlined / tonal / colorHeader / leftAccent / glass / neon / minimal |
blur |
double? |
No | null |
Surface blur sigma. Unlike dialogs and sheets a snackbar has no barrier, so leaving it unset applies no blur |
backdropFilter |
ImageFilter? |
No | null |
Custom backdrop filter (overrides blur when set) |
enablePulse |
bool? |
No | false |
Loops a subtle scale + glow on the icon. Off by default: it never stops, so it repaints every frame and hangs pumpAndSettle() in tests |
Examples
1. Basic Snackbar
SavePointsSnackbar.show(
context,
title: 'Basic Snackbar',
subtitle: 'Simple notification example',
type: SnackbarType.info,
);
2. Success Snackbar
SavePointsSnackbar.showSuccess(
context,
title: 'Success!',
subtitle: 'Operation completed successfully',
showProgressIndicator: true,
);
3. Error Snackbar
SavePointsSnackbar.showError(
context,
title: 'Error',
subtitle: 'Failed to complete operation',
showProgressIndicator: true,
);
4. Warning Snackbar
SavePointsSnackbar.showWarning(
context,
title: 'Warning',
subtitle: 'Low balance remaining',
showProgressIndicator: true,
);
5. Top Position Snackbar
SavePointsSnackbar.show(
context,
title: 'Top Snackbar',
subtitle: 'Displayed at the top of the screen',
position: SnackbarPosition.top,
showProgressIndicator: true,
startAnimation: SnackbarAnimationDirection.fromTop,
);
6. Gradient Snackbar with Progress
SavePointsSnackbar.show(
context,
title: 'Gradient Snackbar',
subtitle: 'Beautiful gradient background',
gradient: const LinearGradient(
colors: [Color(0xFF667eea), Color(0xFF764ba2)],
),
showProgressIndicator: true,
);
7. Bounce Animation Snackbar
SavePointsSnackbar.show(
context,
title: 'Bounce Animation',
subtitle: 'Custom bounce effect',
animation: SnackbarAnimation.bounce,
type: SnackbarType.success,
);
8. Slide Rotate Animation Snackbar
SavePointsSnackbar.show(
context,
title: 'Slide Rotate',
subtitle: 'Combined animation effect',
animation: SnackbarAnimation.slideRotate,
type: SnackbarType.info,
showProgressIndicator: true,
);
9. Tap to Dismiss Snackbar
SavePointsSnackbar.show(
context,
title: 'Tap to Dismiss',
subtitle: 'Touch anywhere to close',
dismissOnTap: true,
type: SnackbarType.info,
);
10. Bordered Snackbar
SavePointsSnackbar.show(
context,
title: 'Bordered Snackbar',
subtitle: 'With custom border styling',
borderColor: Colors.orange,
borderWidth: 2,
borderRadius: .circular(12),
type: SnackbarType.warning,
);
11. Elastic Animation Snackbar
SavePointsSnackbar.show(
context,
title: 'Elastic Animation',
subtitle: 'Smooth elastic effect',
animation: SnackbarAnimation.elastic,
type: SnackbarType.success,
);
12. Custom Direction Animation Snackbar
SavePointsSnackbar.show(
context,
title: 'Custom Animation',
subtitle: 'Slides in from left',
startAnimation: SnackbarAnimationDirection.fromLeft,
endAnimation: SnackbarAnimationDirection.fromRight,
type: SnackbarType.info,
showProgressIndicator: true,
);
13. Snackbar with Backdrop Blur
import 'dart:ui';
SavePointsSnackbar.show(
context,
title: 'Glassmorphism Snackbar',
subtitle: 'Frosted glass effect behind the snackbar',
blur: 12.0,
type: SnackbarType.info,
);
๐ฑ SavePointsBottomsheet
Method Signature
static Future<T?> show<T>({
required BuildContext context,
String? title,
Widget? child,
IconData? icon,
Color? iconColor,
Color? backgroundColor,
bool? isDismissible,
bool? enableDrag,
bool? showHandle,
double? maxHeight,
bool isScrollControlled = false,
BottomsheetAnimationDirection? startAnimation,
BottomsheetAnimationDirection? endAnimation,
bool isLoading = false,
ValueNotifier<bool>? loadingNotifier,
bool hideLikeCircle = false,
ContentDesignStyle? designStyle,
double? blur,
ImageFilter? backdropFilter,
})
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
title |
String? |
No | null |
Bottom sheet title |
child |
Widget? |
No | null |
Content widget |
icon |
IconData? |
No | null |
Optional icon next to title |
iconColor |
Color? |
No | Theme-based | Icon color |
backgroundColor |
Color? |
No | Theme-based | Background color |
isDismissible |
bool? |
No | true |
Allow dismissing by tapping outside |
enableDrag |
bool? |
No | true |
Enable drag to dismiss |
showHandle |
bool? |
No | true |
Show drag handle indicator |
maxHeight |
double? |
No | 90% of screen |
Maximum height |
isScrollControlled |
bool |
No | false |
Enable scroll control |
startAnimation |
BottomsheetAnimationDirection? |
No | null |
Enter animation |
endAnimation |
BottomsheetAnimationDirection? |
No | null |
Exit animation |
isLoading |
bool |
No | false |
Initial loading state |
loadingNotifier |
ValueNotifier<bool>? |
No | null |
External loading control |
hideLikeCircle |
bool |
No | false |
Disable circular reveal exit animation |
designStyle |
ContentDesignStyle? |
No | colorHeader |
solid / outlined / tonal / colorHeader / leftAccent / glass / neon / minimal |
blur |
double? |
No | 20.0 |
Barrier blur sigma. Falls back to SavePointsTheme, then to defaultBarrierBlurSigma. Pass 0 to opt out |
backdropFilter |
ImageFilter? |
No | null |
Custom backdrop filter (overrides blur when set) |
enablePulse |
bool? |
No | false |
Loops a subtle scale + glow on the icon. Off by default: it never stops, so it repaints every frame and hangs pumpAndSettle() in tests |
Examples
1. Basic Bottom Sheet
SavePointsBottomsheet.show(
context: context,
title: 'Bottom Sheet',
child: const Padding(
padding: .all(24.0),
child: Text(
'This is a modern bottom sheet with glassmorphism design. '
'It features beautiful backdrop blur effects and smooth animations.',
style: TextStyle(fontSize: 16),
),
),
);
2. Options Menu Bottom Sheet
SavePointsBottomsheet.show(
context: context,
title: 'Options',
icon: Icons.more_vert,
child: Column(
mainAxisSize: .min,
children: [
ListTile(
leading: const Icon(Icons.edit),
title: const Text('Edit'),
subtitle: const Text('Modify this item'),
onTap: () => Navigator.pop(context),
),
const Divider(),
ListTile(
leading: const Icon(Icons.share),
title: const Text('Share'),
subtitle: const Text('Share with others'),
onTap: () => Navigator.pop(context),
),
const Divider(),
ListTile(
leading: const Icon(Icons.delete, color: Colors.red),
title: const Text('Delete', style: TextStyle(color: Colors.red)),
subtitle: const Text('Remove this item permanently'),
onTap: () => Navigator.pop(context),
),
],
),
);
3. Animated Bottom Sheet
SavePointsBottomsheet.show(
context: context,
title: 'Animated Bottom Sheet',
startAnimation: BottomsheetAnimationDirection.fromLeft,
endAnimation: BottomsheetAnimationDirection.fromRight,
child: const Padding(
padding: .all(24.0),
child: Text(
'This bottom sheet slides in from the left and exits to the right.',
style: TextStyle(fontSize: 16),
),
),
);
4. Bottom Sheet with Loading State
final loadingNotifier = ValueNotifier<bool>(false);
SavePointsBottomsheet.show(
context: context,
title: 'Loading Data',
isLoading: false,
loadingNotifier: loadingNotifier,
child: const SizedBox(),
);
// Simulate loading
Future.delayed(const Duration(milliseconds: 500), () {
loadingNotifier.value = true;
Future.delayed(const Duration(seconds: 2), () {
loadingNotifier.value = false;
if (context.mounted) {
Navigator.pop(context);
SavePointsSnackbar.showSuccess(
context,
title: 'Loaded!',
subtitle: 'Data loaded successfully',
);
}
});
});
5. Scrollable Bottom Sheet
SavePointsBottomsheet.show(
context: context,
title: 'Scrollable Content',
icon: Icons.swap_vert,
isScrollControlled: true,
child: Column(
mainAxisSize: .min,
children: List.generate(
15,
(index) => ListTile(
leading: CircleAvatar(
child: Text('${index + 1}'),
),
title: Text('Item ${index + 1}'),
subtitle: Text('This is item number ${index + 1}'),
onTap: () => Navigator.pop(context),
),
),
),
);
6. Settings Bottom Sheet
SavePointsBottomsheet.show(
context: context,
title: 'Settings',
icon: Icons.settings,
child: Column(
mainAxisSize: .min,
children: [
SwitchListTile(
title: const Text('Enable Notifications'),
subtitle: const Text('Receive push notifications'),
value: true,
onChanged: (_) {},
),
const Divider(),
SwitchListTile(
title: const Text('Dark Mode'),
subtitle: const Text('Use dark theme'),
value: false,
onChanged: (_) {},
),
const Divider(),
ListTile(
leading: const Icon(Icons.language),
title: const Text('Language'),
subtitle: const Text('English'),
trailing: const Icon(Icons.chevron_right),
onTap: () => Navigator.pop(context),
),
],
),
);
7. Bottom Sheet with Custom Blur
import 'dart:ui';
SavePointsBottomsheet.show(
context: context,
title: 'Glassmorphism',
icon: Icons.blur_on,
blur: 16.0,
child: const Padding(
padding: .all(24.0),
child: Text(
'Backdrop blur can be customized with the blur parameter.',
style: TextStyle(fontSize: 16),
),
),
);
๐ญ Dialog Presets
Use predefined configurations for common dialog flows:
import 'package:save_points_snackbar_dialog_bottomsheet/presets/presets.dart';
Delete confirmation
final confirmed = await DialogPresets.showDeleteConfirmation(
context,
itemName: 'My Document',
);
if (confirmed == true) {
// Delete the item
}
Logout confirmation
final confirmed = await DialogPresets.showLogoutConfirmation(context);
if (confirmed == true) {
// Perform logout
}
Discard changes
final confirmed = await DialogPresets.showDiscardChangesConfirmation(context);
if (confirmed == true) {
Navigator.pop(context);
}
Update available
DialogPresets.showUpdateAvailable(context);
Feature not available
DialogPresets.showFeatureNotAvailable(context);
๐จ Animation Types
Dialog Animations
DialogAnimationType (Legacy):
fadeSlide- Fade with slide (default)scale- Scale animationslideBottom- Slide from bottomslideTop- Slide from topslideLeft- Slide from leftslideRight- Slide from rightbounce- Bounce animationrotateScale- Rotate with scaleelastic- Elastic animationnone- No animation
DialogAnimationDirection (New):
fromTop,fromBottom,fromLeft,fromRight- Slide directionsfade- Fade in/outscale- Scale animationrotateScale- Rotate with scalebounce- Bounce animationelastic- Elastic animationnone- No animation
Snackbar Animations
SnackbarAnimation (Legacy):
fadeSlide- Fade with slide (default)scale- Scale animationslide- Slide animationbounce- Bounce animationrotate- Rotate animationelastic- Elastic animationslideRotate- Slide with rotatenone- No animation
SnackbarAnimationDirection (New):
fromTop,fromBottom,fromLeft,fromRight- Slide directionsfade- Fade in/outscale- Scale animationrotateScale- Rotate with scalebounce- Bounce animationelastic- Elastic animationnone- No animation
Bottom Sheet Animations
BottomsheetAnimationDirection:
fromBottom- Slide from bottom (default)fromLeft- Slide from leftfromRight- Slide from rightfade- Fade in/outscale- Scale animationnone- No animation
โ๏ธ Configuration
SavePoints Modern UI provides a centralized configuration system through SnackDiaBottomConfig:
// Configure global defaults
final config = SnackDiaBottomConfig();
config.snackbar
..defaultDuration = Duration(seconds: 5)
..defaultType = SnackbarType.info
..defaultShowProgressIndicator = true
..defaultDesignStyle = ContentDesignStyle.solid; // any ContentDesignStyle
config.dialog
..defaultConfirmText = 'Continue'
..defaultShowCancelButton = true
..defaultDesignStyle = ContentDesignStyle.colorHeader; // any ContentDesignStyle
Warning
SavePointsBottomsheet.defaultDesignStyle is deprecated as of 1.2.1. A
mutable static is process-wide and notifies nothing already on screen โ use
SavePointsTheme instead, which
also sets the default for dialogs and snackbars in one place.
Resolution order for every component is explicit argument โ nearest
SavePointsTheme โ this config.
See the Configuration Guide for more details.
๐จ Scoped defaults with SavePointsTheme
SnackDiaBottomConfig sets defaults globally by mutating a singleton. When
you'd rather declare defaults once in your widget tree โ scoped, overridable
per subtree, and without touching global state โ wrap your app in a
SavePointsTheme:
SavePointsTheme(
data: const SavePointsThemeData(
designStyle: ContentDesignStyle.glass,
blur: 24,
snackbarPosition: SnackbarPosition.top,
enableHapticFeedback: true,
),
child: MaterialApp(/* ... */),
);
Now every dialog, snackbar and bottom sheet below it defaults to the glass style with a 24px backdrop blur โ no need to repeat those arguments on each call:
// Uses the themed glass style + blur automatically.
SavePointsDialog.show(context, title: 'Saved', message: 'All set!');
// Explicit arguments still win over the theme.
SavePointsDialog.show(
context,
title: 'Heads up',
message: 'This one is different',
designStyle: ContentDesignStyle.neon,
);
Resolution order for every field is explicit argument โ nearest
SavePointsTheme โ built-in default, so adopting a theme is fully backward
compatible. Any field left null in SavePointsThemeData falls through to the
component's own default. Because it is a standard InheritedWidget, a subtree
can wrap itself in another SavePointsTheme to override just that branch.
Supported fields: designStyle, blur, snackbarPosition,
snackbarDuration, enableHapticFeedback, barrierDismissible,
enablePulse.
๐จ Building on the same styles
Every style resolves through one public helper, so you can decorate your own surfaces in the package's language instead of eyeballing its colours:
final spec = SpStyles.of(
ContentDesignStyle.aurora,
Theme.of(context).colorScheme.primary,
Theme.of(context).brightness == Brightness.dark,
);
Container(
decoration: BoxDecoration(
color: spec.fillGradient == null ? spec.fill : null,
gradient: spec.fillGradient,
borderRadius: BorderRadius.circular(24 * spec.radiusScale),
border: spec.hasBorder
? Border.all(color: spec.borderColor!, width: spec.borderWidth)
: null,
boxShadow: spec.shadows,
),
child: Text('Matches the family', style: TextStyle(color: spec.onSurface)),
);
SpStyleSpec carries everything a style decides: fill, fillGradient,
onSurface, onSurfaceMuted, shadows, borderColor, borderWidth,
borderGradient, radiusScale and blurSigma.
The underlying tokens are public too โ SpRadius, SpSpacing, SpType,
SpMotion, SpSurface, SpPalette, SpShadows and SpContrast โ if you
would rather compose your own.
๐ฑ Platform Support
| Platform | Status |
|---|---|
| iOS | โ Fully Supported |
| Android | โ Fully Supported |
| Web | โ Fully Supported |
| macOS | โ Fully Supported |
| Linux | โ Fully Supported |
| Windows | โ Fully Supported |
Pure Dart and Flutter โ no platform channels, no native code.
โฟ Accessibility
- Snackbars are announced by TalkBack and VoiceOver on arrival (they render
inside a
Semanticslive region). - Every icon-only close button carries a localized label, taken from
MaterialLocalizations, so it reads correctly in all supported locales. - Reveal and slide animations resolve against
Directionality.of(context), so directional alignments mirror correctly in RTL layouts.
๐ฏ Performance
- Repaint Boundaries - Strategic use of
RepaintBoundarywidgets to minimize repaints - Cached Configurations - Color configs and MediaQuery values are cached
- Optimized Animations - Clamped animations prevent overflow errors
- Efficient Builds - Widgets extracted to prevent unnecessary rebuilds
- Code Quality - Professional code structure with constants extraction and optimized helper methods
๐ง Running the Example
The example app is located in the lib/main.dart file and demonstrates all features of the package.
-
Clone the repository:
git clone https://github.com/m7hamed-dev/save-points-modern-ui.git cd save_points_snackbar_dialog_bottomsheet -
Install dependencies:
flutter pub get -
Run the example:
flutter run
The example app includes:
- Animated UI - Beautiful gradient backgrounds, staggered animations, and smooth transitions
- Interactive Buttons - Scale, hover, and ripple effects on all action buttons
- Bottom Navigation - Navigate between sections with snackbar feedback
- Comprehensive Examples - Over 40+ examples showcasing all features
- Dialog Presets - Examples using predefined dialog configurations
- Advanced Flows - Multi-step interactions and combined component usage
- Professional Code - Well-organized, documented, and maintainable codebase following Flutter best practices
๐ Additional Resources
- ๐ Live Demo - Try the components in your browser
- Full API Documentation
- Example App
- Issue Tracker
๐ค Contributing
Contributions are welcome and greatly appreciated! Before submitting a pull request, please ensure:
- โ Code follows the existing style and conventions
- โ
All tests pass (
flutter test) - โ Documentation is updated
- โ No breaking changes (or properly documented)
Development Setup
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments
- Built with Flutter
- Inspired by modern UI/UX design principles
- Glassmorphism effects using Flutter's
BackdropFilter - Performance optimizations based on Flutter best practices
๐ฌ Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Email: support@savepoints.dev
Made with โค๏ธ by the SavePoints team
โญ Star us on GitHub โข ๐ Live Demo โข ๐ฆ Pub.dev โข ๐ Documentation
Libraries
- bottomsheet/bottomsheet
- Barrel file for bottom sheet widgets and classes
- bottomsheet/bottomsheet_animation_direction
- bottomsheet/bottomsheet_color_config
- bottomsheet/bottomsheet_constants
- bottomsheet/bottomsheet_container
- Bottom sheet container widget with styling and safe area handling.
- bottomsheet/bottomsheet_handle
- bottomsheet/bottomsheet_loading_indicator
- bottomsheet/bottomsheet_shadows
- bottomsheet/bottomsheet_transition_builder
- bottomsheet/bottomsheet_transition_scope
- bottomsheet/modern_bottomsheet
- config/config
- Barrel file for configuration classes
- config/dialog_config
- config/savepoints_config
- config/snackbar_config
- config/snackbar_type_config
- content_design_style
- design/animated_barrier
- design/color_header_band
- design/pulse_scope
- design/save_points_tokens
- Bold & expressive design tokens โ the single source of truth shared by the snackbar, dialog and bottom sheet so they all speak one visual language.
- design/sp_style
- dialog/circular_reveal_clip
- dialog/dialog
- Barrel file for dialog widgets and classes
- dialog/dialog_animation_direction
- dialog/dialog_animation_type
- dialog/dialog_color_config
- dialog/dialog_constants
- dialog/dialog_container
- dialog/dialog_icon
- dialog/dialog_loading_indicator
- dialog/dialog_message
- dialog/dialog_shadows
- dialog/dialog_title
- dialog/dialog_transition_builder
- dialog/dialog_transition_scope
- dialog/header_dialog
- dialog/modern_dialog
- dialog/savepoints_dialog
- extensions/context_extensions
- presets/dialog_presets
- presets/presets
- Barrel file for preset configurations
- save_points_snackbar_dialog_bottomsheet
- SavePoints Modern UI โ canonical entry point.
- savepoints_bottomsheet
- SavePoints Bottom Sheet Library
- savepoints_config
- Main configuration file - re-exports from config directory
- savepoints_dialog
- SavePoints Dialog Library
- savepoints_modern_ui
- SavePoints Modern UI - A Flutter package for modern UI components
- savepoints_snackbar
- SavePoints Snackbar Library
- savepoints_theme
- shared/enhanced_icon
- snackbar/animated_icon
- snackbar/animated_wrapper
- snackbar/circular_reveal_clip
- snackbar/clamped_animation
- snackbar/modern_snackbar_content
- snackbar/progress_indicator_bar
- snackbar/snackbar
- Barrel file for snackbar widgets and classes
- snackbar/snackbar_animation_direction
- snackbar/snackbar_color_config
- snackbar/snackbar_constants
- snackbar/snackbar_enums
- snackbar/snackbar_shadows
- snackbar/top_snackbar_overlay
- utils/constants
- utils/keyboard_utils
- utils/snackbar_queue
- utils/utils
- Barrel file for utility classes