promo_carousel 1.1.0
promo_carousel: ^1.1.0 copied to clipboard
A flexible, customizable promotional carousel package for Flutter.
A flexible, production-ready Flutter package for creating beautiful promotional carousels with support for user-specific widget injection. Perfect for onboarding flows, feature announcements, and personalized promotions.
β¨ Features #
Core Features #
- π― Modal Overlay - Beautiful dialog-style presentation with dimmed background
- π± Swipeable Carousel - Smooth PageView-based navigation
- π¨ Built-in Visual Types - Images, animations, search bars, videos, and more
- π§ Custom Widget Injection - Inject user-specific widgets without coupling
- πΎ Persistent State - Tracks "show once" slides using SharedPreferences
- π Theme Support - Automatically adapts to light and dark themes
Enhanced Features (v1.1) #
- β±οΈ Auto-Advance - Automatically progress through slides with configurable timing
- π Analytics Callbacks - Track views, clicks, skips, and completions
- β‘ Skip All Button - Let users bypass the entire carousel
- π Multiple Display Modes - Dialog, bottom sheet, or fullscreen
- π Progress Indicators - Linear progress bar or custom indicators
- π¬ Transition Types - Slide, fade, scale, or rotate animations
- π¨ Backdrop Blur - Add frosted glass effect to overlay
- π± Gesture Controls - Swipe or tap to advance
- βΏ Haptic Feedback - Tactile response on page changes
- π Remote Config Ready - Load slides from JSON
- π Conditional Display - Advanced filtering rules (dates, versions, segments, devices)
- π§ͺ Preview Mode - Test all slides without rules
- π Debug Mode - Detailed logging for development
πΈ Preview #
π Getting Started #
Installation #
Add to your pubspec.yaml:
dependencies:
promo_carousel: ^1.1.0
Then run:
flutter pub get
Basic Usage #
import 'package:promo_carousel/promo_carousel.dart';
PromoCarousel.show(
context: context,
slides: [
PromoSlide(
id: 'welcome',
title: 'Welcome to Our App',
subtitle: 'Discover amazing features',
visualType: PromoVisualType.featureHighlight,
cta: PromoCTA(
text: 'Get Started',
action: PromoAction.close,
),
rules: PromoRules(showOnce: true),
),
],
onAction: (action, target) {
print('Action: $action');
},
);
π Documentation #
PromoSlide #
The core model representing a single carousel slide:
PromoSlide(
id: 'unique_id', // Unique identifier
title: 'Main Title', // Required title text
subtitle: 'Optional description', // Optional subtitle
visualType: PromoVisualType.image, // Built-in visual type
cta: PromoCTA( // Call-to-action button
text: 'Button Text',
action: PromoAction.navigate,
target: '/route-name',
),
rules: PromoRules( // Display rules
showOnce: true,
minAppVersion: '1.2.0',
maxAppVersion: '2.0.0',
showAfterDate: DateTime(2025, 1, 1),
showBeforeDate: DateTime(2025, 12, 31),
userSegments: ['premium', 'beta'],
deviceTypes: [DeviceType.mobile],
),
customContentBuilder: (context) { // Optional custom widget
return YourCustomWidget();
},
semanticLabel: 'Welcome screen', // Accessibility
metadata: {'experiment_id': '001'}, // A/B testing
)
Visual Types #
Built-in visual types available:
PromoVisualType.image- Display an image assetPromoVisualType.animation- Show an animated visualPromoVisualType.searchBar- Search bar animationPromoVisualType.featureHighlight- Gradient highlightPromoVisualType.video- Video player (requires video asset)PromoVisualType.custom- Use withcustomContentBuilder
Actions #
Available CTA actions:
PromoAction.navigate- Navigate to a routePromoAction.openFeature- Open a specific featurePromoAction.openPaywall- Show paywall/upgrade screenPromoAction.close- Simply close the modalPromoAction.custom- Custom action with callback
Configuration #
Customize appearance and behavior:
PromoCarousel.show(
context: context,
slides: slides,
config: PromoCarouselConfig(
// Appearance
borderRadius: 24.0,
elevation: 8.0,
barrierColor: Color(0x80000000),
backdropBlur: 10.0,
displayMode: DisplayMode.dialog,
// Behavior
barrierDismissible: true,
showCloseButton: true,
showDontShowAgain: false,
showSkipButton: true,
enableSwipeGestures: true,
enableTapToAdvance: true,
// Auto-advance
autoAdvance: true,
autoAdvanceDuration: Duration(seconds: 5),
pauseOnInteraction: true,
// Progress
showProgressBar: true,
progressBarPosition: ProgressPosition.top,
// Accessibility
enableHaptics: true,
hapticFeedbackType: HapticType.light,
respectReducedMotion: true,
),
);
Pre-built Configs #
Use factory constructors for common scenarios:
// Onboarding flow
config: PromoCarouselConfig.onboarding()
// Feature announcement
config: PromoCarouselConfig.announcement()
// Marketing promotion
config: PromoCarouselConfig.marketing()
π― Advanced Usage #
Custom User-Specific Widgets #
The key feature - inject personalized content without coupling the package to your data models:
PromoSlide(
id: 'zodiac_preview',
title: 'Your Personal Insights',
subtitle: 'Based on your zodiac sign',
visualType: PromoVisualType.custom,
cta: PromoCTA(
text: 'Reveal',
action: PromoAction.openFeature,
target: 'zodiac_detail',
),
rules: PromoRules(showOnce: true),
customContentBuilder: (context) {
// Access your app's user data here
final user = Provider.of<User>(context);
return ZodiacPreviewCard(
sign: user.zodiacSign,
topSearch: user.topSearch,
);
},
)
Analytics Tracking #
Track user interactions with comprehensive callbacks:
PromoCarousel.show(
context: context,
slides: slides,
analytics: PromoCarouselAnalytics(
onSlideViewed: (slideId, index) {
print('Viewed: $slideId at index $index');
analytics.logEvent('promo_slide_viewed', {'slide_id': slideId});
},
onSlideSkipped: (slideId, index) {
analytics.logEvent('promo_slide_skipped');
},
onCTAClicked: (slideId, action, target) {
analytics.logEvent('promo_cta_clicked', {
'slide_id': slideId,
'action': action.name,
'target': target,
});
},
onCarouselCompleted: (viewedSlides) {
analytics.logEvent('promo_completed', {
'slides_viewed': viewedSlides.length,
});
},
onCarouselDismissed: (lastIndex, viewedSlides) {
analytics.logEvent('promo_dismissed', {
'last_index': lastIndex,
'completion_rate': viewedSlides.length / slides.length,
});
},
onSkipAll: () {
analytics.logEvent('promo_skipped_all');
},
),
);
Auto-Advance with Pause #
Automatically progress through slides:
PromoCarousel.show(
context: context,
slides: slides,
config: PromoCarouselConfig(
autoAdvance: true,
autoAdvanceDuration: Duration(seconds: 5),
pauseOnInteraction: true, // Pause when user interacts
showProgressBar: true,
),
);
Display Modes #
Choose how to present the carousel:
// Dialog (default)
PromoCarousel.show(context: context, slides: slides);
// Bottom sheet
PromoCarousel.showBottomSheet(context: context, slides: slides);
// Fullscreen
PromoCarousel.showFullscreen(context: context, slides: slides);
Remote Config Integration #
Load slides from JSON:
// From your Firebase Remote Config, API, etc.
final jsonData = await remoteConfig.getJson('promo_slides');
// Parse to slides
final slides = PromoCarousel.fromJson(jsonData);
// Show carousel
PromoCarousel.show(context: context, slides: slides);
Conditional Display Rules #
Advanced filtering based on multiple criteria:
PromoSlide(
id: 'premium_offer',
title: 'Upgrade to Premium',
rules: PromoRules(
showOnce: true,
minAppVersion: '1.5.0',
maxAppVersion: '2.0.0',
showAfterDate: DateTime(2025, 1, 1),
showBeforeDate: DateTime(2025, 12, 31),
userSegments: ['free_tier', 'trial'],
deviceTypes: [DeviceType.mobile, DeviceType.tablet],
customCondition: () {
// Custom logic
return user.hasUsedAppForDays(7);
},
),
// ...
)
Custom Page Indicators #
Replace the default page counter:
PromoCarousel.show(
context: context,
slides: slides,
config: PromoCarouselConfig(
indicatorBuilder: (context, currentPage, totalPages) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(totalPages, (index) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 4),
width: index == currentPage ? 12 : 8,
height: 8,
decoration: BoxDecoration(
color: index == currentPage ? Colors.blue : Colors.grey,
borderRadius: BorderRadius.circular(4),
),
);
}),
);
},
),
);
Preview Mode #
Test all slides regardless of rules:
PromoCarousel.showPreview(
context: context,
slides: slides,
// Ignores showOnce, date ranges, version checks, etc.
);
Manual State Management #
Control slide visibility programmatically:
// Check if slide was seen
final seen = await PromoCarousel.hasSeenSlide('welcome');
// Reset a specific slide
await PromoCarousel.resetSlide('welcome');
// Reset multiple slides
await PromoCarousel.resetSlides(['slide1', 'slide2']);
// Reset all slides
await PromoCarousel.resetAll();
// Get all seen slides
final seenSlides = await PromoCarousel.getSeenSlides();
// Export analytics
final analytics = await PromoCarousel.exportAnalytics();
Debug Mode #
Enable detailed logging during development:
void main() {
PromoCarousel.debugMode = true;
runApp(MyApp());
}
π¨ Theming #
The carousel automatically adapts to your app's theme:
MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
// Carousel will adapt to both themes
)
π± Use Cases #
Perfect for:
- β Onboarding flows - Welcome new users
- β Feature announcements - Showcase new capabilities
- β Personalized promotions - Zodiac insights, user stats, achievements
- β Contextual tips - Show relevant guidance
- β Marketing campaigns - Promote offers and upgrades
- β Product tours - Guide users through features
- β A/B testing - Test different messaging with metadata tracking
- β Seasonal campaigns - Date-based promotions
ποΈ Architecture #
The package follows clean architecture principles:
lib/
βββ models/
β βββ promo_slide.dart # Core data models
β βββ promo_carousel_config.dart # Configuration classes
βββ controllers/
β βββ promo_carousel_controller.dart # State management
βββ widgets/
β βββ promo_carousel_modal.dart # Main modal widget
β βββ promo_slide_content.dart # Content renderer
βββ promo_carousel.dart # Public API
π« What This Package Does NOT Do #
To keep the package generic and reusable:
- β No Firebase or remote config integration (but provides JSON parsing)
- β No analytics tracking implementation (but provides callbacks)
- β No app-specific navigation logic
- β No user data models or assumptions
- β No network requests
These features should be implemented in your app layer using the provided callbacks and hooks.
π€ Contributing #
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.
π License #
This project is licensed under the MIT License - see the LICENSE file for details.
π Changelog #
See CHANGELOG.md for release history.
π Acknowledgments #
Built with β€οΈ for the Flutter community.
π Support #
- π§ Email: kyawzayartun.contact@gmail.com
- π Issues: GitHub Issues
Made with Flutter π
