smart_snack 1.0.6 copy "smart_snack: ^1.0.6" to clipboard
smart_snack: ^1.0.6 copied to clipboard

A beautiful, feature-rich Dynamic Island-style notification system for Flutter. Premium animations, glass morphism, gradient effects, priority queues, haptic feedback, and more.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:smart_snack/smart_snack.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setSystemUIOverlayStyle(
    const SystemUiOverlayStyle(
      statusBarColor: Colors.transparent,
      statusBarIconBrightness: Brightness.dark,
    ),
  );
  runApp(const SmartSnackShowcase());
}

class SmartSnackShowcase extends StatelessWidget {
  const SmartSnackShowcase({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'SmartSnack Showcase',
      theme: ThemeData(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSeed(
          seedColor: const Color(0xFF8B5CF6),
          brightness: Brightness.light,
        ),
        scaffoldBackgroundColor: const Color(0xFFFAFAFA),
      ),
      darkTheme: ThemeData(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSeed(
          seedColor: const Color(0xFF8B5CF6),
          brightness: Brightness.dark,
        ),
        scaffoldBackgroundColor: const Color(0xFF0A0A0A),
      ),
      themeMode: ThemeMode.light,
      home: const ShowcasePage(),
    );
  }
}

class ShowcasePage extends StatefulWidget {
  const ShowcasePage({super.key});

  @override
  State<ShowcasePage> createState() => _ShowcasePageState();
}

class _ShowcasePageState extends State<ShowcasePage>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 4, vsync: this);
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            _buildHeader(),
            _buildTabs(),
            Expanded(
              child: TabBarView(
                controller: _tabController,
                children: const [
                  _BasicStylesTab(),
                  _CustomStylesTab(),
                  _InteractiveTab(),
                  _AdvancedTab(),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildHeader() {
    return Padding(
      padding: const EdgeInsets.fromLTRB(24, 16, 24, 8),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            children: [
              Container(
                width: 48,
                height: 48,
                decoration: BoxDecoration(
                  gradient: const LinearGradient(
                    colors: [Color(0xFF8B5CF6), Color(0xFFD946EF)],
                  ),
                  borderRadius: BorderRadius.circular(14),
                  boxShadow: [
                    BoxShadow(
                      color: const Color(0xFF8B5CF6).withOpacity(0.3),
                      blurRadius: 12,
                      offset: const Offset(0, 4),
                    ),
                  ],
                ),
                child: const Icon(Icons.notifications_active_rounded,
                    color: Colors.white, size: 26),
              ),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text(
                      'SmartSnack',
                      style: TextStyle(
                        fontSize: 28,
                        fontWeight: FontWeight.w700,
                        letterSpacing: -0.5,
                      ),
                    ),
                    Text(
                      'Dynamic Island-style notifications',
                      style: TextStyle(
                        fontSize: 14,
                        color: Colors.grey[600],
                        fontWeight: FontWeight.w500,
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }

  Widget _buildTabs() {
    return Container(
      margin: const EdgeInsets.fromLTRB(16, 8, 16, 8),
      decoration: BoxDecoration(
        color: Colors.grey[200],
        borderRadius: BorderRadius.circular(12),
      ),
      child: TabBar(
        controller: _tabController,
        labelColor: Colors.white,
        unselectedLabelColor: Colors.grey[600],
        labelStyle: const TextStyle(fontWeight: FontWeight.w600, fontSize: 13),
        unselectedLabelStyle:
            const TextStyle(fontWeight: FontWeight.w500, fontSize: 13),
        indicator: BoxDecoration(
          gradient: const LinearGradient(
            colors: [Color(0xFF8B5CF6), Color(0xFFD946EF)],
          ),
          borderRadius: BorderRadius.circular(10),
          boxShadow: [
            BoxShadow(
              color: const Color(0xFF8B5CF6).withOpacity(0.3),
              blurRadius: 8,
              offset: const Offset(0, 2),
            ),
          ],
        ),
        indicatorSize: TabBarIndicatorSize.tab,
        dividerColor: Colors.transparent,
        padding: const EdgeInsets.all(4),
        tabs: const [
          Tab(text: 'Basic'),
          Tab(text: 'Styles'),
          Tab(text: 'Interactive'),
          Tab(text: 'Advanced'),
        ],
      ),
    );
  }
}

// ═══════════════════════════════════════════════════════════════════════════════
// BASIC STYLES TAB
// ═══════════════════════════════════════════════════════════════════════════════

class _BasicStylesTab extends StatelessWidget {
  const _BasicStylesTab();

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: const EdgeInsets.all(20),
      children: [
        const _SectionTitle('Status Notifications'),
        const SizedBox(height: 12),
        _ShowcaseCard(
          title: 'Success',
          subtitle: 'Confirms completed actions',
          gradient: const [Color(0xFF10B981), Color(0xFF14B8A6)],
          icon: Icons.check_circle_rounded,
          onTap: () => SmartSnack.success(
            context,
            title: 'Payment Successful!',
            subtitle: '\$50.00 sent to Sarah',
          ),
        ),
        _ShowcaseCard(
          title: 'Error',
          subtitle: 'Shows failure messages',
          gradient: const [Color(0xFFEF4444), Color(0xFFF97316)],
          icon: Icons.error_rounded,
          onTap: () => SmartSnack.error(
            context,
            title: 'Connection Failed',
            subtitle: 'Please check your internet',
          ),
        ),
        _ShowcaseCard(
          title: 'Warning',
          subtitle: 'Alerts for caution',
          gradient: const [Color(0xFFF59E0B), Color(0xFFEAB308)],
          icon: Icons.warning_rounded,
          onTap: () => SmartSnack.warning(
            context,
            title: 'Low Battery',
            subtitle: '10% remaining',
          ),
        ),
        _ShowcaseCard(
          title: 'Info',
          subtitle: 'Informational messages',
          gradient: const [Color(0xFF3B82F6), Color(0xFF06B6D4)],
          icon: Icons.info_rounded,
          onTap: () => SmartSnack.info(
            context,
            title: 'New Update Available',
            subtitle: 'Version 2.0 is ready',
          ),
        ),
        const SizedBox(height: 24),
        const _SectionTitle('Loading State'),
        const SizedBox(height: 12),
        _ShowcaseCard(
          title: 'Loading',
          subtitle: 'Animated gradient border',
          gradient: const [Color(0xFF8B5CF6), Color(0xFFD946EF)],
          icon: Icons.sync_rounded,
          onTap: () async {
            SmartSnack.loading(context, title: 'Syncing data...');
            await Future.delayed(const Duration(seconds: 2));
            if (context.mounted) {
              SmartSnack.success(context, title: 'Sync complete!');
            }
          },
        ),
      ],
    );
  }
}

// ═══════════════════════════════════════════════════════════════════════════════
// CUSTOM STYLES TAB
// ═══════════════════════════════════════════════════════════════════════════════

class _CustomStylesTab extends StatelessWidget {
  const _CustomStylesTab();

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: const EdgeInsets.all(20),
      children: [
        const _SectionTitle('Premium Styles'),
        const SizedBox(height: 12),
        _ShowcaseCard(
          title: 'Glass Morphism',
          subtitle: 'Frosted glass blur effect',
          gradient: const [Color(0xFF64748B), Color(0xFF475569)],
          icon: Icons.blur_on_rounded,
          onTap: () => SmartSnack.glass(
            context,
            title: 'AirDrop Received',
            subtitle: 'Photo from iPhone nearby',
            leading:
                const Icon(Icons.phone_iphone, color: Colors.white70, size: 22),
          ),
        ),
        _ShowcaseCard(
          title: 'Gradient',
          subtitle: 'Beautiful gradient backgrounds',
          gradient: const [Color(0xFF8B5CF6), Color(0xFFEC4899)],
          icon: Icons.gradient_rounded,
          onTap: () => SmartSnack.gradient(
            context,
            title: 'Premium Unlocked! ✨',
            gradientColors: const [Color(0xFF8B5CF6), Color(0xFFEC4899)],
          ),
        ),
        _ShowcaseCard(
          title: 'Minimal',
          subtitle: 'Clean and simple',
          gradient: const [Color(0xFF374151), Color(0xFF1F2937)],
          icon: Icons.minimize_rounded,
          onTap: () => SmartSnack.show(
            context,
            title: 'Copied to clipboard',
            style: SmartSnackStyle.minimal,
          ),
        ),
        const SizedBox(height: 24),
        const _SectionTitle('Custom Notifications'),
        const SizedBox(height: 12),
        _ShowcaseCard(
          title: 'Now Playing',
          subtitle: 'Music player style',
          gradient: const [Color(0xFFEC4899), Color(0xFFF43F5E)],
          icon: Icons.music_note_rounded,
          onTap: () => SmartSnack.show(
            context,
            title: '',
            style: SmartSnackStyle.custom,
            leading: ClipRRect(
              borderRadius: BorderRadius.circular(6),
              child: Container(
                width: 36,
                height: 36,
                decoration: const BoxDecoration(
                  gradient: LinearGradient(
                    colors: [Color(0xFFEC4899), Color(0xFFF43F5E)],
                  ),
                ),
                child:
                    const Icon(Icons.music_note, color: Colors.white, size: 20),
              ),
            ),
            bodyWidget: const Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  'Blinding Lights',
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 14,
                    fontWeight: FontWeight.w600,
                    decoration: TextDecoration.none,
                  ),
                ),
                Text(
                  'The Weeknd',
                  style: TextStyle(
                    color: Colors.white54,
                    fontSize: 12,
                    fontWeight: FontWeight.w400,
                    decoration: TextDecoration.none,
                  ),
                ),
              ],
            ),
            trailing: const _AnimatedWave(),
          ),
        ),
        _ShowcaseCard(
          title: 'Incoming Call',
          subtitle: 'With action buttons',
          gradient: const [Color(0xFF22C55E), Color(0xFF16A34A)],
          icon: Icons.call_rounded,
          onTap: () => SmartSnack.show(
            context,
            title: 'Sarah Wilson',
            subtitle: 'Incoming call...',
            style: SmartSnackStyle.custom,
            duration: const Duration(seconds: 8),
            leading: const CircleAvatar(
              radius: 18,
              backgroundColor: Color(0xFF22C55E),
              child: Text('SW',
                  style: TextStyle(
                      color: Colors.white,
                      fontSize: 12,
                      fontWeight: FontWeight.bold)),
            ),
            trailing: Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                _CallButton(
                    color: Colors.red,
                    icon: Icons.call_end,
                    onTap: () => SmartSnack.dismiss()),
                const SizedBox(width: 8),
                _CallButton(
                    color: Colors.green,
                    icon: Icons.call,
                    onTap: () =>
                        SmartSnack.success(context, title: 'Call connected')),
              ],
            ),
          ),
        ),
        _ShowcaseCard(
          title: 'Message',
          subtitle: 'Chat notification',
          gradient: const [Color(0xFF3B82F6), Color(0xFF1D4ED8)],
          icon: Icons.message_rounded,
          onTap: () => SmartSnack.show(
            context,
            title: 'New message from Alex',
            subtitle: 'Hey! Are you free tonight? 🎉',
            style: SmartSnackStyle.custom,
            leading: CircleAvatar(
              radius: 18,
              backgroundColor: Colors.blue[100],
              child: const Text('A',
                  style: TextStyle(
                      color: Colors.blue, fontWeight: FontWeight.bold)),
            ),
          ),
        ),
      ],
    );
  }
}

// ═══════════════════════════════════════════════════════════════════════════════
// INTERACTIVE TAB
// ═══════════════════════════════════════════════════════════════════════════════

class _InteractiveTab extends StatelessWidget {
  const _InteractiveTab();

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: const EdgeInsets.all(20),
      children: [
        const _SectionTitle('Action Buttons'),
        const SizedBox(height: 12),
        _ShowcaseCard(
          title: 'With Actions',
          subtitle: 'Undo deleted item',
          gradient: const [Color(0xFFEF4444), Color(0xFFDC2626)],
          icon: Icons.delete_rounded,
          onTap: () => SmartSnack.show(
            context,
            title: 'Item deleted',
            style: SmartSnackStyle.custom,
            leading: const Icon(Icons.delete_outline,
                color: Color(0xFFEF4444), size: 22),
            actions: [
              SmartSnackAction(
                label: 'Undo',
                onPressed: () =>
                    SmartSnack.success(context, title: 'Item restored'),
              ),
            ],
          ),
        ),
        _ShowcaseCard(
          title: 'Multiple Actions',
          subtitle: 'Save or share file',
          gradient: const [Color(0xFF3B82F6), Color(0xFF2563EB)],
          icon: Icons.file_present_rounded,
          onTap: () => SmartSnack.info(
            context,
            title: 'File ready',
            subtitle: 'document.pdf',
            actions: [
              SmartSnackAction(
                label: 'Share',
                icon: Icons.share,
                onPressed: () {},
              ),
              SmartSnackAction(
                label: 'Save',
                icon: Icons.download,
                onPressed: () => SmartSnack.success(context, title: 'Saved!'),
              ),
            ],
          ),
        ),
        const SizedBox(height: 24),
        const _SectionTitle('Progress Indicators'),
        const SizedBox(height: 12),
        _ShowcaseCard(
          title: 'Upload Progress',
          subtitle: 'Animated progress bar',
          gradient: const [Color(0xFF06B6D4), Color(0xFF0891B2)],
          icon: Icons.cloud_upload_rounded,
          onTap: () async {
            for (double i = 0; i <= 1.0; i += 0.1) {
              SmartSnack.progress(
                context,
                id: 'upload',
                title: 'Uploading file...',
                progress: i,
                showProgressText: true,
                accentColor: const Color(0xFF06B6D4),
              );
              await Future.delayed(const Duration(milliseconds: 300));
            }
            if (context.mounted) {
              SmartSnack.success(context, title: 'Upload complete!');
            }
          },
        ),
        const SizedBox(height: 24),
        const _SectionTitle('Loading Transitions'),
        const SizedBox(height: 12),
        _ShowcaseCard(
          title: 'Load → Success',
          subtitle: 'Common async pattern',
          gradient: const [Color(0xFF8B5CF6), Color(0xFF7C3AED)],
          icon: Icons.sync_rounded,
          onTap: () async {
            SmartSnack.loading(context, title: 'Processing payment...');
            await Future.delayed(const Duration(seconds: 2));
            if (context.mounted) {
              SmartSnack.success(context, title: 'Payment successful! 💰');
            }
          },
        ),
        _ShowcaseCard(
          title: 'Load → Error',
          subtitle: 'Failure handling',
          gradient: const [Color(0xFFEF4444), Color(0xFFDC2626)],
          icon: Icons.error_outline_rounded,
          onTap: () async {
            SmartSnack.loading(context, title: 'Connecting...');
            await Future.delayed(const Duration(seconds: 2));
            if (context.mounted) {
              SmartSnack.error(context, title: 'Connection timeout');
            }
          },
        ),
      ],
    );
  }
}

// ═══════════════════════════════════════════════════════════════════════════════
// ADVANCED TAB
// ═══════════════════════════════════════════════════════════════════════════════

class _AdvancedTab extends StatelessWidget {
  const _AdvancedTab();

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: const EdgeInsets.all(20),
      children: [
        const _SectionTitle('Queue Management'),
        const SizedBox(height: 12),
        _ShowcaseCard(
          title: 'Queued Messages',
          subtitle: 'Shows 3 notifications in sequence',
          gradient: const [Color(0xFF8B5CF6), Color(0xFFA78BFA)],
          icon: Icons.queue_rounded,
          onTap: () {
            SmartSnack.info(context, title: 'First notification');
            SmartSnack.warning(context, title: 'Second notification');
            SmartSnack.success(context, title: 'Third notification');
          },
        ),
        _ShowcaseCard(
          title: 'High Priority',
          subtitle: 'Jumps the queue',
          gradient: const [Color(0xFFF59E0B), Color(0xFFD97706)],
          icon: Icons.priority_high_rounded,
          onTap: () {
            SmartSnack.info(context, title: 'Normal priority');
            SmartSnack.show(
              context,
              title: '⚡ URGENT: Check this first!',
              style: SmartSnackStyle.warning,
              priority: SmartSnackPriority.urgent,
            );
          },
        ),
        const SizedBox(height: 24),
        const _SectionTitle('Position & Gestures'),
        const SizedBox(height: 12),
        _ShowcaseCard(
          title: 'Bottom Position',
          subtitle: 'Display at screen bottom',
          gradient: const [Color(0xFF64748B), Color(0xFF475569)],
          icon: Icons.vertical_align_bottom_rounded,
          onTap: () => SmartSnack.info(
            context,
            title: 'Bottom notification',
            position: SmartSnackPosition.bottom,
          ),
        ),
        _ShowcaseCard(
          title: 'Swipe to Dismiss',
          subtitle: 'Try swiping up on any notification',
          gradient: const [Color(0xFF06B6D4), Color(0xFF0891B2)],
          icon: Icons.swipe_up_rounded,
          onTap: () => SmartSnack.info(
            context,
            title: '⬆️ Swipe up to dismiss',
            duration: const Duration(seconds: 10),
          ),
        ),
        const SizedBox(height: 24),
        const _SectionTitle('System Notifications'),
        const SizedBox(height: 12),
        _ShowcaseCard(
          title: 'AirPods Connected',
          subtitle: 'Device connection style',
          gradient: const [Color(0xFF22C55E), Color(0xFF16A34A)],
          icon: Icons.headphones_rounded,
          onTap: () => SmartSnack.show(
            context,
            title: 'AirPods Pro',
            subtitle: 'Connected',
            style: SmartSnackStyle.custom,
            leading: const Icon(Icons.headphones_rounded,
                color: Color(0xFF22C55E), size: 24),
            trailing: Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                const Icon(Icons.battery_full,
                    color: Color(0xFF22C55E), size: 16),
                const SizedBox(width: 4),
                Text(
                  '85%',
                  style: TextStyle(
                    color: Colors.grey[400],
                    fontSize: 12,
                    fontWeight: FontWeight.w500,
                    decoration: TextDecoration.none,
                  ),
                ),
              ],
            ),
          ),
        ),
        _ShowcaseCard(
          title: 'Screenshot Taken',
          subtitle: 'System capture notification',
          gradient: const [Color(0xFF3B82F6), Color(0xFF2563EB)],
          icon: Icons.screenshot_rounded,
          onTap: () => SmartSnack.show(
            context,
            title: 'Screenshot saved',
            subtitle: 'Tap to view',
            style: SmartSnackStyle.custom,
            leading: Container(
              width: 36,
              height: 36,
              decoration: BoxDecoration(
                color: Colors.blue.withOpacity(0.2),
                borderRadius: BorderRadius.circular(8),
              ),
              child: const Icon(Icons.image, color: Colors.blue, size: 20),
            ),
            onTap: () => SmartSnack.info(context, title: 'Opening gallery...'),
          ),
        ),
        _ShowcaseCard(
          title: 'Face ID',
          subtitle: 'Authentication notification',
          gradient: const [Color(0xFF8B5CF6), Color(0xFF7C3AED)],
          icon: Icons.face_rounded,
          onTap: () async {
            SmartSnack.show(
              context,
              title: 'Face ID',
              style: SmartSnackStyle.loading,
              leading: const Icon(Icons.face_rounded,
                  color: Color(0xFF8B5CF6), size: 24),
            );
            await Future.delayed(const Duration(seconds: 1));
            if (context.mounted) {
              SmartSnack.success(context, title: 'Face ID verified ✓');
            }
          },
        ),
      ],
    );
  }
}

// ═══════════════════════════════════════════════════════════════════════════════
// HELPER WIDGETS
// ═══════════════════════════════════════════════════════════════════════════════

class _SectionTitle extends StatelessWidget {
  final String title;

  const _SectionTitle(this.title);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(left: 4, bottom: 4),
      child: Text(
        title.toUpperCase(),
        style: TextStyle(
          color: Colors.grey[500],
          fontSize: 12,
          fontWeight: FontWeight.w700,
          letterSpacing: 1.2,
        ),
      ),
    );
  }
}

class _ShowcaseCard extends StatelessWidget {
  final String title;
  final String subtitle;
  final List<Color> gradient;
  final IconData icon;
  final VoidCallback onTap;

  const _ShowcaseCard({
    required this.title,
    required this.subtitle,
    required this.gradient,
    required this.icon,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.only(bottom: 12),
      child: Material(
        color: Colors.white,
        borderRadius: BorderRadius.circular(16),
        elevation: 0,
        child: InkWell(
          onTap: onTap,
          borderRadius: BorderRadius.circular(16),
          child: Container(
            padding: const EdgeInsets.all(16),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(16),
              border: Border.all(color: Colors.grey[200]!, width: 1),
            ),
            child: Row(
              children: [
                Container(
                  width: 48,
                  height: 48,
                  decoration: BoxDecoration(
                    gradient: LinearGradient(colors: gradient),
                    borderRadius: BorderRadius.circular(12),
                    boxShadow: [
                      BoxShadow(
                        color: gradient.first.withOpacity(0.3),
                        blurRadius: 8,
                        offset: const Offset(0, 2),
                      ),
                    ],
                  ),
                  child: Center(
                    child: Icon(
                      icon,
                      color: Colors.white,
                      size: 24,
                    ),
                  ),
                ),
                const SizedBox(width: 16),
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        title,
                        style: const TextStyle(
                          fontSize: 16,
                          fontWeight: FontWeight.w600,
                        ),
                      ),
                      const SizedBox(height: 2),
                      Text(
                        subtitle,
                        style: TextStyle(
                          fontSize: 13,
                          color: Colors.grey[600],
                        ),
                      ),
                    ],
                  ),
                ),
                Container(
                  width: 32,
                  height: 32,
                  decoration: BoxDecoration(
                    color: Colors.grey[100],
                    shape: BoxShape.circle,
                  ),
                  child: Icon(
                    Icons.arrow_forward_ios_rounded,
                    color: Colors.grey[400],
                    size: 14,
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class _CallButton extends StatelessWidget {
  final Color color;
  final IconData icon;
  final VoidCallback onTap;

  const _CallButton({
    required this.color,
    required this.icon,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onTap,
      child: Container(
        width: 28,
        height: 28,
        decoration: BoxDecoration(
          color: color,
          shape: BoxShape.circle,
        ),
        child: Icon(icon, color: Colors.white, size: 16),
      ),
    );
  }
}

// Animated wave widget for music player
class _AnimatedWave extends StatefulWidget {
  const _AnimatedWave();

  @override
  State<_AnimatedWave> createState() => _AnimatedWaveState();
}

class _AnimatedWaveState extends State<_AnimatedWave>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 800),
    )..repeat();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: 28,
      height: 20,
      child: AnimatedBuilder(
        animation: _controller,
        builder: (context, child) {
          return CustomPaint(
            painter: WavePainter(
              animationValue: _controller.value,
              color: const Color(0xFFEC4899),
              barCount: 4,
              maxHeight: 16,
            ),
          );
        },
      ),
    );
  }
}
5
likes
160
points
190
downloads
screenshot

Publisher

unverified uploader

Weekly Downloads

A beautiful, feature-rich Dynamic Island-style notification system for Flutter. Premium animations, glass morphism, gradient effects, priority queues, haptic feedback, and more.

Repository (GitHub)
View/report issues

Topics

#notification #snackbar #toast #dynamic-island #ui

Documentation

Documentation
API reference

Funding

Consider supporting this project:

github.com

License

MIT (license)

Dependencies

flutter

More

Packages that depend on smart_snack