my_animated_widgets 0.0.1 copy "my_animated_widgets: ^0.0.1" to clipboard
my_animated_widgets: ^0.0.1 copied to clipboard

A collection of beautiful animated Flutter widgets with dark/light mode support.

example/lib/main.dart

import 'dart:math';
import 'package:flutter/material.dart';
import 'package:my_animated_widgets/my_animated_widgets.dart';
import 'package:my_animated_widgets/src/liquid_progress_bar.dart';
import 'package:my_animated_widgets/src/sky_theme_toggle.dart';

void main() {
  runApp(const MyApp());
}

// ─────────────────────────────────────────────
//  APP ROOT
// ─────────────────────────────────────────────
class MyApp extends StatefulWidget {
  const MyApp({super.key});
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool _isDark = false;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Animated Widgets Showcase',
      debugShowCheckedModeBanner: false,
      theme: AppTheme.light(),
      darkTheme: AppTheme.dark(),
      themeMode: _isDark ? ThemeMode.dark : ThemeMode.light,
      home: ShowcasePage(
        isDark: _isDark,
        onThemeToggle: (val) => setState(() => _isDark = val),
      ),
    );
  }
}

// ─────────────────────────────────────────────
//  THEME
// ─────────────────────────────────────────────
class AppTheme {
  static const _teal = Color(0xFF01696F);
  static const _darkBg = Color(0xFF171614);
  static const _darkSurface = Color(0xFF1C1B19);

  static ThemeData light() => ThemeData(
        useMaterial3: true,
        brightness: Brightness.light,
        colorSchemeSeed: _teal,
        scaffoldBackgroundColor: const Color(0xFFF7F6F2),
        cardColor: Colors.white,
      );

  static ThemeData dark() => ThemeData(
        useMaterial3: true,
        brightness: Brightness.dark,
        colorSchemeSeed: _teal,
        scaffoldBackgroundColor: _darkBg,
        cardColor: _darkSurface,
      );
}

// ─────────────────────────────────────────────
//  SHOWCASE PAGE
// ─────────────────────────────────────────────
// ✅ StatelessWidget — الـ state كله في MyApp
class ShowcasePage extends StatelessWidget {
  final bool isDark;
  final ValueChanged<bool> onThemeToggle;

  const ShowcasePage({
    super.key,
    required this.isDark,
    required this.onThemeToggle,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          '✨ Animated Widgets',
          style: TextStyle(fontWeight: FontWeight.bold),
        ),
        centerTitle: false,
        actions: [
          Padding(
            padding: const EdgeInsets.only(right: 16),
            // ✅ DarkModeToggle من الـ package
            child: DarkModeToggle(
              isDark: isDark,
              onChanged: onThemeToggle,
            ),
          ),
        ],
      ),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          SizedBox(height: 600, child: _Page()),
          Stack(
            children: [
              Container(
                decoration: const BoxDecoration(
                  gradient: RadialGradient(
                    center: Alignment(0, 0.3),
                    radius: 1.2,
                    colors: [Color(0xFF1A1A2E), Color(0xFF0D0D14)],
                  ),
                ),
              ),
              Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    const Text(
                      '🌌 Orbital Action Menu',
                      style: TextStyle(
                        fontSize: 22,
                        fontWeight: FontWeight.bold,
                        color: Colors.white,
                        letterSpacing: 0.5,
                      ),
                    ),
                    const SizedBox(height: 8),
                    const Text(
                      'اضغط على الزرار',
                      style: TextStyle(color: Colors.white38, fontSize: 14),
                    ),
                    const SizedBox(height: 80),

                    // ★ THE WIDGET ★
                    OrbitalActionMenu(
                      icon: Icons.auto_awesome,
                      color: const Color(0xFF7C4DFF),
                      actions: [
                        OrbitalAction(
                          icon: Icons.receipt_long,
                          label: 'Invoice',
                          color: const Color(0xFF00BCD4),
                          onTap: () {},
                        ),
                        OrbitalAction(
                          icon: Icons.person_add,
                          label: 'Client',
                          color: const Color(0xFF69F0AE),
                          onTap: () {},
                        ),
                        OrbitalAction(
                          icon: Icons.qr_code_scanner,
                          label: 'Scan',
                          color: const Color(0xFFFFD740),
                          onTap: () {},
                        ),
                        OrbitalAction(
                          icon: Icons.bar_chart,
                          label: 'Reports',
                          color: const Color(0xFFFF6D9F),
                          onTap: () {},
                        ),
                      ],
                    ),
                  ],
                ),
              ),
            ],
          ),
          // ── 1. Sky Toggle ──────────────────────────
          const _SectionTitle('🌗 1. Sky Theme Toggle'),
          _DemoCard(
            child: Center(
              child: SkyThemeToggle(
                isDark: isDark,
                // ✅ بيستدعي onThemeToggle مش بيعدل widget.isDark مباشرة
                onChanged: onThemeToggle,
                width: 220,
              ),
            ),
          ),
          const SizedBox(height: 24),

          // ── 2. Counter ────────────────────────────
          const _SectionTitle('🔢 2. Animated Number Counter'),
          const _AnimatedCounterDemo(),
          const SizedBox(height: 24),

          // ── 3. Progress ───────────────────────────
          const _SectionTitle('⏳ 3. Liquid Progress Bar'),
          const _LiquidProgressDemo(),
          const SizedBox(height: 24),

          // ── 4. Shimmer ────────────────────────────
          const _SectionTitle('✨ 4. Shimmer Skeleton Loader'),
          const _ShimmerDemo(),
          const SizedBox(height: 24),

          // ── 5. FAB ────────────────────────────────
          const _SectionTitle('🃏 5. Morphing FAB Button'),
          const _MorphingFabDemo(),
          const SizedBox(height: 24),

          // ── 6. Bottom Nav ─────────────────────────
          const _SectionTitle('🌊 6. Animated Bottom Nav Preview'),
          const _BottomNavDemo(),
          const SizedBox(height: 24),

          // ── 7. Staggered List ─────────────────────
          const _SectionTitle('📋 7. Staggered List Animation'),
          const _StaggeredListDemo(),
          const SizedBox(height: 24),

          // ── 8. Glass Card ─────────────────────────
          const _SectionTitle('💳 8. Glassmorphism Card'),
          const _GlassCardDemo(),
          const SizedBox(height: 40),
        ],
      ),
    );
  }
}

// ─────────────────────────────────────────────
//  SECTION TITLE
// ─────────────────────────────────────────────
class _SectionTitle extends StatelessWidget {
  final String text;
  const _SectionTitle(this.text);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 12),
      child: Text(
        text,
        style: Theme.of(context).textTheme.titleMedium?.copyWith(
              fontWeight: FontWeight.bold,
              letterSpacing: 0.3,
            ),
      ),
    );
  }
}

// ═══════════════════════════════════════════════════════
//  WIDGET 2 — Animated Counter
// ═══════════════════════════════════════════════════════
class AnimatedCounter extends StatelessWidget {
  final double value;
  final String prefix;
  final String suffix;
  final TextStyle? style;

  const AnimatedCounter({
    super.key,
    required this.value,
    this.prefix = '',
    this.suffix = '',
    this.style,
  });

  @override
  Widget build(BuildContext context) {
    return TweenAnimationBuilder<double>(
      tween: Tween(begin: 0, end: value),
      duration: const Duration(milliseconds: 800),
      curve: Curves.easeOutCubic,
      builder: (context, v, _) {
        final display = v >= 1000
            ? v.toStringAsFixed(0).replaceAllMapped(RegExp(r'(\d)(?=(\d{3})+$)'), (m) => '${m[1]},')
            : v.toStringAsFixed(2);
        return Text(
          '$prefix$display$suffix',
          style: style ??
              Theme.of(context).textTheme.headlineMedium?.copyWith(
                    fontWeight: FontWeight.bold,
                    fontFeatures: const [FontFeature.tabularFigures()],
                    color: const Color(0xFF01696F),
                  ),
        );
      },
    );
  }
}

class _AnimatedCounterDemo extends StatefulWidget {
  const _AnimatedCounterDemo();
  @override
  State<_AnimatedCounterDemo> createState() => _AnimatedCounterDemoState();
}

class _AnimatedCounterDemoState extends State<_AnimatedCounterDemo> {
  double _amount = 1250.75;
  final _rng = Random();

  void _randomize() => setState(() => _amount = (_rng.nextDouble() * 50000 + 100));

  @override
  Widget build(BuildContext context) {
    return _DemoCard(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text('Total Sales', style: Theme.of(context).textTheme.bodySmall),
              AnimatedCounter(value: _amount, suffix: ' EGP'),
            ],
          ),
          FilledButton.icon(
            onPressed: _randomize,
            icon: const Icon(Icons.refresh, size: 16),
            label: const Text('Update'),
          ),
        ],
      ),
    );
  }
}

class _Page extends StatelessWidget {
  const _Page();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text(
              '⚡  P L A S M A',
              style: TextStyle(
                fontSize: 26,
                fontWeight: FontWeight.bold,
                color: Colors.white,
                letterSpacing: 8,
              ),
            ),
            const SizedBox(height: 6),
            const Text(
              'المس الكرة',
              style: TextStyle(color: Colors.white30, fontSize: 13, letterSpacing: 2),
            ),
            const SizedBox(height: 56),

            // ★  THE WIDGET  ★
            const PlasmaGlobeWidget(
              radius: 155,
              primaryColor: Color(0xFF8B5CF6),
              secondaryColor: Color(0xFF06B6D4),
            ),

            const SizedBox(height: 48),
            const Text(
              't o u c h  m e',
              style: TextStyle(
                color: Color(0xFF8B5CF6),
                fontSize: 11,
                letterSpacing: 5,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

// ═══════════════════════════════════════════════════════
//  WIDGET 3 — Liquid Progress Bar Demo
// ═══════════════════════════════════════════════════════
class _LiquidProgressDemo extends StatefulWidget {
  const _LiquidProgressDemo();
  @override
  State<_LiquidProgressDemo> createState() => _LiquidProgressDemoState();
}

class _LiquidProgressDemoState extends State<_LiquidProgressDemo> {
  double _progress = 0.45;

  @override
  Widget build(BuildContext context) {
    return _DemoCard(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Text('Monthly Target'),
          const SizedBox(height: 12),
          LiquidProgressBar(progress: _progress),
          const SizedBox(height: 12),
          LiquidProgressBar(progress: _progress * 0.6, color: const Color(0xFF964219)),
          const SizedBox(height: 16),
          Slider(
            value: _progress,
            onChanged: (v) => setState(() => _progress = v),
            activeColor: const Color(0xFF01696F),
          ),
        ],
      ),
    );
  }
}

// ═══════════════════════════════════════════════════════
//  WIDGET 4 — Shimmer Skeleton
// ═══════════════════════════════════════════════════════
class ShimmerBox extends StatefulWidget {
  final double width;
  final double height;
  final double borderRadius;

  const ShimmerBox({
    super.key,
    required this.width,
    required this.height,
    this.borderRadius = 8,
  });

  @override
  State<ShimmerBox> createState() => _ShimmerBoxState();
}

class _ShimmerBoxState extends State<ShimmerBox> with SingleTickerProviderStateMixin {
  late AnimationController _ctrl;
  late Animation<double> _anim;

  @override
  void initState() {
    super.initState();
    _ctrl = AnimationController(vsync: this, duration: const Duration(milliseconds: 1500))..repeat();
    _anim = CurvedAnimation(parent: _ctrl, curve: Curves.easeInOut);
  }

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

  @override
  Widget build(BuildContext context) {
    final isDark = Theme.of(context).brightness == Brightness.dark;
    final baseColor = isDark ? const Color(0xFF2D2C2A) : const Color(0xFFE8E8E8);
    final highlightColor = isDark ? const Color(0xFF3D3C3A) : const Color(0xFFF5F5F5);

    return AnimatedBuilder(
      animation: _anim,
      builder: (_, __) => Container(
        width: widget.width,
        height: widget.height,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(widget.borderRadius),
          gradient: LinearGradient(
            begin: Alignment(-1 + _anim.value * 2, 0),
            end: Alignment(_anim.value * 2, 0),
            colors: [baseColor, highlightColor, baseColor],
          ),
        ),
      ),
    );
  }
}

class _ShimmerDemo extends StatefulWidget {
  const _ShimmerDemo();
  @override
  State<_ShimmerDemo> createState() => _ShimmerDemoState();
}

class _ShimmerDemoState extends State<_ShimmerDemo> {
  bool _loading = true;

  @override
  Widget build(BuildContext context) {
    return _DemoCard(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text(
                _loading ? 'Loading...' : 'Content Loaded ✓',
                style: Theme.of(context).textTheme.bodySmall,
              ),
              Switch(
                value: _loading,
                onChanged: (v) => setState(() => _loading = v),
                activeColor: const Color(0xFF01696F),
              ),
            ],
          ),
          const SizedBox(height: 12),
          if (_loading) _buildSkeleton() else _buildContent(context),
        ],
      ),
    );
  }

  Widget _buildSkeleton() => Column(
        children: List.generate(
          3,
          (i) => Padding(
            padding: const EdgeInsets.only(bottom: 12),
            child: Row(
              children: [
                ShimmerBox(width: 40, height: 40, borderRadius: 20),
                const SizedBox(width: 12),
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      ShimmerBox(width: double.infinity, height: 14),
                      const SizedBox(height: 6),
                      ShimmerBox(width: 120, height: 10),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
      );

  Widget _buildContent(BuildContext context) => Column(
        children: [
          '#1234 - Gold Ring 18K — 1,200 EGP',
          '#1235 - Silver Necklace — 450 EGP',
          '#1236 - Diamond Earrings — 8,500 EGP',
        ]
            .map(
              (t) => ListTile(
                leading: const CircleAvatar(
                  backgroundColor: Color(0xFF01696F),
                  child: Icon(Icons.diamond, color: Colors.white, size: 18),
                ),
                title: Text(t, style: Theme.of(context).textTheme.bodySmall),
                dense: true,
              ),
            )
            .toList(),
      );
}

// ═══════════════════════════════════════════════════════
//  WIDGET 5 — Morphing FAB
// ═══════════════════════════════════════════════════════
class _MorphingFabDemo extends StatefulWidget {
  const _MorphingFabDemo();
  @override
  State<_MorphingFabDemo> createState() => _MorphingFabDemoState();
}

class _MorphingFabDemoState extends State<_MorphingFabDemo> with SingleTickerProviderStateMixin {
  bool _expanded = false;
  late AnimationController _ctrl;
  late Animation<double> _fade;

  @override
  void initState() {
    super.initState();
    _ctrl = AnimationController(vsync: this, duration: const Duration(milliseconds: 400));
    _fade = CurvedAnimation(parent: _ctrl, curve: Curves.easeInOut);
  }

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

  void _toggle() {
    setState(() => _expanded = !_expanded);
    _expanded ? _ctrl.forward() : _ctrl.reverse();
  }

  @override
  Widget build(BuildContext context) {
    return _DemoCard(
      child: Center(
        child: GestureDetector(
          onTap: _toggle,
          child: AnimatedContainer(
            duration: const Duration(milliseconds: 500),
            curve: Curves.fastLinearToSlowEaseIn,
            width: _expanded ? 260 : 60,
            height: _expanded ? 160 : 60,
            decoration: BoxDecoration(
              color: const Color(0xFF01696F),
              borderRadius: BorderRadius.circular(_expanded ? 20 : 30),
              boxShadow: const [
                BoxShadow(color: Color(0x5001696F), blurRadius: 16, spreadRadius: 2),
              ],
            ),
            child: _expanded
                ? FadeTransition(
                    opacity: _fade,
                    child: Padding(
                      padding: const EdgeInsets.all(16),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          const Text('New Invoice',
                              style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16)),
                          const SizedBox(height: 8),
                          Row(
                            children: [
                              _FabAction(icon: Icons.person_add, label: 'Client'),
                              const SizedBox(width: 8),
                              _FabAction(icon: Icons.add_box, label: 'Item'),
                              const SizedBox(width: 8),
                              _FabAction(icon: Icons.close, label: 'Close', onTap: _toggle),
                            ],
                          ),
                        ],
                      ),
                    ),
                  )
                : const Icon(Icons.add, color: Colors.white, size: 28),
          ),
        ),
      ),
    );
  }
}

class _FabAction extends StatelessWidget {
  final IconData icon;
  final String label;
  final VoidCallback? onTap;

  const _FabAction({required this.icon, required this.label, this.onTap});

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onTap,
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Container(
            padding: const EdgeInsets.all(8),
            decoration: BoxDecoration(
              color: Colors.white24,
              borderRadius: BorderRadius.circular(10),
            ),
            child: Icon(icon, color: Colors.white, size: 20),
          ),
          const SizedBox(height: 4),
          Text(label, style: const TextStyle(color: Colors.white, fontSize: 10)),
        ],
      ),
    );
  }
}

// ═══════════════════════════════════════════════════════
//  WIDGET 6 — Animated Bottom Nav
// ═══════════════════════════════════════════════════════
class _BottomNavDemo extends StatefulWidget {
  const _BottomNavDemo();
  @override
  State<_BottomNavDemo> createState() => _BottomNavDemoState();
}

class _BottomNavDemoState extends State<_BottomNavDemo> {
  int _selected = 0;

  final _items = const [
    (Icons.home_rounded, 'Home'),
    (Icons.receipt_long, 'Invoice'),
    (Icons.bar_chart, 'Reports'),
    (Icons.person, 'Profile'),
  ];

  @override
  Widget build(BuildContext context) {
    final isDark = Theme.of(context).brightness == Brightness.dark;
    final bg = isDark ? const Color(0xFF1C1B19) : Colors.white;
    const active = Color(0xFF01696F);

    return _DemoCard(
      child: Container(
        height: 72,
        decoration: BoxDecoration(
          color: bg,
          borderRadius: BorderRadius.circular(20),
          boxShadow: [
            BoxShadow(color: Colors.black.withValues(alpha:0.08), blurRadius: 20, offset: const Offset(0, -4)),
          ],
        ),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: List.generate(_items.length, (i) {
            final isActive = i == _selected;
            return GestureDetector(
              onTap: () => setState(() => _selected = i),
              child: AnimatedContainer(
                duration: const Duration(milliseconds: 300),
                curve: Curves.easeOutBack,
                padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                decoration: BoxDecoration(
                  color: isActive ? active.withValues(alpha:0.12) : Colors.transparent,
                  borderRadius: BorderRadius.circular(16),
                ),
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    AnimatedScale(
                      scale: isActive ? 1.2 : 1.0,
                      duration: const Duration(milliseconds: 300),
                      curve: Curves.elasticOut,
                      child: Icon(
                        _items[i].$1,
                        color: isActive ? active : Colors.grey,
                        size: 24,
                      ),
                    ),
                    const SizedBox(height: 2),
                    AnimatedDefaultTextStyle(
                      duration: const Duration(milliseconds: 200),
                      style: TextStyle(
                        fontSize: 10,
                        fontWeight: isActive ? FontWeight.bold : FontWeight.normal,
                        color: isActive ? active : Colors.grey,
                      ),
                      child: Text(_items[i].$2),
                    ),
                  ],
                ),
              ),
            );
          }),
        ),
      ),
    );
  }
}

// ═══════════════════════════════════════════════════════
//  WIDGET 7 — Staggered List
// ═══════════════════════════════════════════════════════
class _StaggeredListDemo extends StatefulWidget {
  const _StaggeredListDemo();
  @override
  State<_StaggeredListDemo> createState() => _StaggeredListDemoState();
}

class _StaggeredListDemoState extends State<_StaggeredListDemo> with TickerProviderStateMixin {
  final _items = [
    ('Gold Ring 18K', '1,200 EGP', Icons.circle, Colors.amber),
    ('Silver Necklace', '450 EGP', Icons.circle_outlined, Colors.blueGrey),
    ('Diamond Earrings', '8,500 EGP', Icons.diamond, Colors.lightBlue),
    ('Platinum Bracelet', '3,200 EGP', Icons.watch, Colors.grey),
  ];

  late List<AnimationController> _controllers;
  late List<Animation<double>> _anims;

  @override
  void initState() {
    super.initState();
    _controllers = List.generate(
      _items.length,
      (i) => AnimationController(vsync: this, duration: const Duration(milliseconds: 400)),
    );
    _anims = _controllers.map((c) => CurvedAnimation(parent: c, curve: Curves.easeOutBack)).toList();
    _animate();
  }

  void _animate() async {
    for (var i = 0; i < _controllers.length; i++) {
      await Future.delayed(const Duration(milliseconds: 80));
      if (mounted) _controllers[i].forward(from: 0);
    }
  }

  @override
  void dispose() {
    for (var c in _controllers) {
      c.dispose();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return _DemoCard(
      child: Column(
        children: [
          ...List.generate(_items.length, (i) {
            final item = _items[i];
            return FadeTransition(
              opacity: _anims[i],
              child: SlideTransition(
                position: Tween<Offset>(begin: const Offset(0, 0.3), end: Offset.zero).animate(_anims[i]),
                child: ListTile(
                  dense: true,
                  leading: CircleAvatar(
                    backgroundColor: item.$4.withValues(alpha:0.15),
                    child: Icon(item.$3, color: item.$4, size: 18),
                  ),
                  title: Text(item.$1),
                  trailing:
                      Text(item.$2, style: const TextStyle(color: Color(0xFF01696F), fontWeight: FontWeight.bold)),
                ),
              ),
            );
          }),
          const SizedBox(height: 8),
          TextButton.icon(
            onPressed: _animate,
            icon: const Icon(Icons.replay),
            label: const Text('Replay Animation'),
          ),
        ],
      ),
    );
  }
}

// ═══════════════════════════════════════════════════════
//  WIDGET 8 — Glassmorphism Card
// ═══════════════════════════════════════════════════════
class _GlassCardDemo extends StatefulWidget {
  const _GlassCardDemo();
  @override
  State<_GlassCardDemo> createState() => _GlassCardDemoState();
}

class _GlassCardDemoState extends State<_GlassCardDemo> {
  bool _pressed = false;

  @override
  Widget build(BuildContext context) {
    return _DemoCard(
      child: Container(
        height: 160,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(16),
          gradient: const LinearGradient(
            begin: Alignment.topLeft,
            end: Alignment.bottomRight,
            colors: [Color(0xFF01696F), Color(0xFF0c4e54)],
          ),
        ),
        child: Stack(
          children: [
            Positioned(
              right: -20,
              top: -20,
              child: Container(
                width: 120,
                height: 120,
                decoration: BoxDecoration(
                  shape: BoxShape.circle,
                  color: Colors.white.withValues(alpha:0.08),
                ),
              ),
            ),
            Positioned(
              left: -10,
              bottom: -30,
              child: Container(
                width: 100,
                height: 100,
                decoration: BoxDecoration(
                  shape: BoxShape.circle,
                  color: Colors.white.withValues(alpha:0.06),
                ),
              ),
            ),
            GestureDetector(
              onTapDown: (_) => setState(() => _pressed = true),
              onTapUp: (_) => setState(() => _pressed = false),
              onTapCancel: () => setState(() => _pressed = false),
              child: AnimatedScale(
                scale: _pressed ? 0.97 : 1.0,
                duration: const Duration(milliseconds: 120),
                child: Container(
                  margin: const EdgeInsets.all(12),
                  padding: const EdgeInsets.all(16),
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(12),
                    color: Colors.white.withValues(alpha:0.12),
                    border: Border.all(color: Colors.white.withValues(alpha:0.25)),
                  ),
                  child: const Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          Text('💎 Gold Jewelry POS',
                              style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold)),
                          Icon(Icons.more_horiz, color: Colors.white70),
                        ],
                      ),
                      Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text('Today\'s Revenue', style: TextStyle(color: Colors.white70, fontSize: 12)),
                          Text('24,500.00 EGP',
                              style: TextStyle(color: Colors.white, fontSize: 22, fontWeight: FontWeight.bold)),
                        ],
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

// ═══════════════════════════════════════════════════════
//  SHARED — Demo Card Wrapper
// ═══════════════════════════════════════════════════════
class _DemoCard extends StatelessWidget {
  final Widget child;
  const _DemoCard({required this.child});

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: Theme.of(context).cardColor,
        borderRadius: BorderRadius.circular(16),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withValues(alpha:Theme.of(context).brightness == Brightness.dark ? 0.25 : 0.06),
            blurRadius: 12,
            offset: const Offset(0, 4),
          ),
        ],
      ),
      child: child,
    );
  }
}
0
likes
0
points
15
downloads

Publisher

unverified uploader

Weekly Downloads

A collection of beautiful animated Flutter widgets with dark/light mode support.

Repository (GitHub)
View/report issues

Topics

#animation #widget #dark-mode #ui

License

unknown (license)

Dependencies

flutter

More

Packages that depend on my_animated_widgets