flutter_coupon_card 0.1.0 copy "flutter_coupon_card: ^0.1.0" to clipboard
flutter_coupon_card: ^0.1.0 copied to clipboard

A highly customizable coupon, voucher, ticket, promotion and discount card widget for Flutter, inspired by modern food delivery and e-commerce apps.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_coupon_card/flutter_coupon_card.dart';

void main() => runApp(const ExampleApp());

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

  @override
  State<ExampleApp> createState() => _ExampleAppState();
}

class _ExampleAppState extends State<ExampleApp> {
  ThemeMode _mode = ThemeMode.light;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'flutter_coupon_card',
      debugShowCheckedModeBanner: false,
      themeMode: _mode,
      theme: ThemeData(colorSchemeSeed: const Color(0xFFFF5A5F)),
      darkTheme: ThemeData.dark(useMaterial3: true),
      home: GalleryPage(
        isDark: _mode == ThemeMode.dark,
        onToggleTheme: () => setState(
          () => _mode = _mode == ThemeMode.dark ? ThemeMode.light : ThemeMode.dark,
        ),
      ),
    );
  }
}

class GalleryPage extends StatelessWidget {
  const GalleryPage({
    super.key,
    required this.isDark,
    required this.onToggleTheme,
  });

  final bool isDark;
  final VoidCallback onToggleTheme;

  void _snack(BuildContext context, String message) {
    ScaffoldMessenger.of(context)
      ..hideCurrentSnackBar()
      ..showSnackBar(SnackBar(
        content: Text(message),
        behavior: SnackBarBehavior.floating,
        duration: const Duration(seconds: 1),
      ));
  }

  @override
  Widget build(BuildContext context) {
    // Center content and cap width so it reads well on tablet / desktop / web.
    return Scaffold(
      backgroundColor: isDark ? const Color(0xFF121216) : const Color(0xFFF4F5F7),
      appBar: AppBar(
        title: const Text('flutter_coupon_card'),
        actions: [
          IconButton(
            tooltip: 'Toggle theme',
            onPressed: onToggleTheme,
            icon: Icon(isDark ? Icons.light_mode : Icons.dark_mode),
          ),
        ],
      ),
      body: Center(
        child: ConstrainedBox(
          constraints: const BoxConstraints(maxWidth: 560),
          child: ListView(
            padding: const EdgeInsets.symmetric(vertical: 16),
            children: [
              _section('1 · Food delivery coupon'),
              CouponCard(
                style: CouponCardStyle.foodDelivery,
                discountText: '50% OFF',
                title: 'Up to \$10 off',
                subtitle: 'On your first food order',
                minimumOrder: 'Min. order \$15',
                usageLimit: 'One time use per account',
                code: 'YUMMY50',
                percentageText: '50%',
                enableFadeIn: true,
                onTap: () => _snack(context, 'Coupon tapped'),
                onCodeCopied: (c) => _snack(context, 'Copied $c'),
              ),

              _section('2 · Shopping voucher (scalloped)'),
              VoucherCard(
                style: CouponCardStyle.shopping,
                discountText: '\$25 OFF',
                title: 'Mega Sale Voucher',
                subtitle: 'Storewide electronics',
                minimumOrder: 'Min. spend \$100',
                code: 'MEGA25',
                trailing: const CouponBarcode(data: 'MEGA25-0099'),
                onCodeCopied: (c) => _snack(context, 'Copied $c'),
              ),

              _section('3 · Event ticket (perforated)'),
              TicketCard(
                style: CouponCardStyle.event,
                shape: CouponShape.eventTicket,
                title: 'Neon Music Festival',
                subtitle: 'Sat 22 Aug · 7:00 PM',
                description: 'Gate A · Row 12 · Seat 34',
                code: 'NMF-88213',
                trailing: const CouponQr(data: 'NMF-88213'),
              ),

              _section('4 · Airline boarding pass'),
              _boardingPass(context),

              _section('5 · Membership card'),
              CouponCard(
                style: CouponCardStyle.premium,
                height: 180,
                header: const _MembershipHeader(),
                body: const SizedBox.shrink(),
                footer: const _MembershipFooter(),
              ),

              _section('6 · Gift voucher'),
              VoucherCard(
                shape: CouponShape.giftVoucher,
                theme: CouponTheme.fromColor(const Color(0xFFEC4899)),
                discountText: 'GIFT',
                title: '\$50 Gift Card',
                subtitle: 'Happy Birthday! 🎁',
                condition: 'Redeemable in-store & online',
                code: 'GIFT-7788-2231',
                percentageText: '\$50',
              ),

              _section('7 · Movie ticket (zig-zag stub)'),
              TicketCard(
                shape: CouponShape.movieTicket,
                theme: CouponTheme.fromColor(
                  const Color(0xFFF59E0B),
                  brightness: CouponBrightness.dark,
                ).copyWith(backgroundColor: const Color(0xFF201A12)),
                title: 'Dune: Part Three',
                subtitle: 'IMAX · Screen 4',
                description: '18:40 · Seat H7',
                code: 'MOV-4471',
                dividerStyle: CouponDividerStyle.dashed,
                trailing: const CouponQr(
                  data: 'MOV-4471',
                  color: Color(0xFFF59E0B),
                  background: Color(0xFF201A12),
                ),
              ),

              _section('8 · Glassmorphism'),
              Container(
                height: 200,
                margin: const EdgeInsets.symmetric(horizontal: 8),
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(20),
                  gradient: const LinearGradient(
                    colors: [Color(0xFF7C3AED), Color(0xFF2563EB)],
                    begin: Alignment.topLeft,
                    end: Alignment.bottomRight,
                  ),
                ),
                alignment: Alignment.center,
                child: CouponCard(
                  style: CouponCardStyle.glassmorphism,
                  width: 340,
                  discountText: '20% OFF',
                  title: 'Frosted Deal',
                  subtitle: 'Limited edition',
                  code: 'GLASS20',
                ),
              ),

              _section('9 · Loading skeleton (shimmer)'),
              const CouponCard(isLoading: true),

              const SizedBox(height: 32),
            ],
          ),
        ),
      ),
    );
  }

  Widget _boardingPass(BuildContext context) {
    return CouponCard(
      style: CouponCardStyle.travel,
      height: 170,
      header: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: const [
          _Airport(code: 'PNH', city: 'Phnom Penh'),
          Icon(Icons.flight_takeoff_rounded, color: Color(0xFF2D6CDF)),
          _Airport(code: 'SIN', city: 'Singapore'),
        ],
      ),
      body: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: const [
          _Field(label: 'FLIGHT', value: 'QR 934'),
          _Field(label: 'GATE', value: 'A12'),
          _Field(label: 'SEAT', value: '14C'),
          _Field(label: 'BOARDING', value: '08:20'),
        ],
      ),
      footer: const CouponBarcode(data: 'PNHSIN934-14C', width: double.infinity),
    );
  }

  Widget _section(String title) => Padding(
        padding: const EdgeInsets.fromLTRB(16, 20, 16, 8),
        child: Text(
          title,
          style: const TextStyle(fontWeight: FontWeight.w800, fontSize: 15),
        ),
      );
}

class _Airport extends StatelessWidget {
  const _Airport({required this.code, required this.city});
  final String code;
  final String city;

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(code,
            style: const TextStyle(
                fontSize: 22,
                fontWeight: FontWeight.w900,
                color: Color(0xFF2D6CDF))),
        Text(city, style: const TextStyle(fontSize: 11, color: Colors.black54)),
      ],
    );
  }
}

class _Field extends StatelessWidget {
  const _Field({required this.label, required this.value});
  final String label;
  final String value;

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(label,
            style: const TextStyle(
                fontSize: 9,
                letterSpacing: 1,
                color: Colors.black45,
                fontWeight: FontWeight.w700)),
        const SizedBox(height: 2),
        Text(value,
            style:
                const TextStyle(fontSize: 14, fontWeight: FontWeight.w800)),
      ],
    );
  }
}

class _MembershipHeader extends StatelessWidget {
  const _MembershipHeader();

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: const [
        Text('GOLD MEMBER',
            style: TextStyle(
                color: Color(0xFFE7C46B),
                fontWeight: FontWeight.w900,
                letterSpacing: 2)),
        Icon(Icons.workspace_premium_rounded, color: Color(0xFFE7C46B)),
      ],
    );
  }
}

class _MembershipFooter extends StatelessWidget {
  const _MembershipFooter();

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: const [
        Text('4821  ••••  ••••  9930',
            style: TextStyle(
                color: Colors.white,
                fontSize: 18,
                letterSpacing: 3,
                fontWeight: FontWeight.w700)),
        SizedBox(height: 6),
        Text('NHEB PANHA · Member since 2021',
            style: TextStyle(color: Colors.white54, fontSize: 12)),
      ],
    );
  }
}
2
likes
160
points
34
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A highly customizable coupon, voucher, ticket, promotion and discount card widget for Flutter, inspired by modern food delivery and e-commerce apps.

Repository (GitHub)
View/report issues

Topics

#coupon #voucher #ticket #card #ui

License

MIT (license)

Dependencies

flutter

More

Packages that depend on flutter_coupon_card