import 'package:flutter/material.dart'; import 'package:line_icons/line_icons.dart'; import 'widgets/appbar.dart'; import 'widgets/purchase_tile.dart'; import 'widgets/stat_card.dart'; import 'widgets/status_chip.dart'; // AppColor class (sesuai dengan yang Anda berikan) class AppColor { // Primary Colors static const Color primary = Color(0xFF36175e); static const Color primaryLight = Color(0xFF5a2d85); static const Color primaryDark = Color(0xFF1e0d35); // Secondary Colors static const Color secondary = Color(0xFF4CAF50); static const Color secondaryLight = Color(0xFF81C784); static const Color secondaryDark = Color(0xFF388E3C); // Background Colors static const Color background = Color(0xFFF8F9FA); static const Color backgroundLight = Color(0xFFFFFFFF); static const Color backgroundDark = Color(0xFF1A1A1A); static const Color surface = Color(0xFFFFFFFF); static const Color surfaceDark = Color(0xFF2D2D2D); // Text Colors static const Color textPrimary = Color(0xFF212121); static const Color textSecondary = Color(0xFF757575); static const Color textLight = Color(0xFFBDBDBD); static const Color textWhite = Color(0xFFFFFFFF); // Status Colors static const Color success = Color(0xFF4CAF50); static const Color error = Color(0xFFE53E3E); static const Color warning = Color(0xFFFF9800); static const Color info = Color(0xFF2196F3); // Border Colors static const Color border = Color(0xFFE0E0E0); static const Color borderLight = Color(0xFFF0F0F0); static const Color borderDark = Color(0xFFBDBDBD); // Basic Color static const Color white = Color(0xFFFFFFFF); static const Color black = Color(0xFF000000); // Gradient Colors static const List primaryGradient = [ Color(0xFF36175e), Color(0xFF5a2d85), ]; static const List successGradient = [ Color(0xFF4CAF50), Color(0xFF81C784), ]; static const List backgroundGradient = [ Color(0xFFF5F5F5), Color(0xFFE8E8E8), ]; // Opacity Variations static Color primaryWithOpacity(double opacity) => primary.withOpacity(opacity); static Color successWithOpacity(double opacity) => success.withOpacity(opacity); static Color errorWithOpacity(double opacity) => error.withOpacity(opacity); static Color warningWithOpacity(double opacity) => warning.withOpacity(opacity); } // AppStyle class (sesuai dengan yang Anda berikan) class AppStyle { static TextStyle xs = const TextStyle( color: AppColor.textPrimary, fontSize: 11, ); static TextStyle sm = const TextStyle( color: AppColor.textPrimary, fontSize: 12, ); static TextStyle md = const TextStyle( color: AppColor.textPrimary, fontSize: 14, ); static TextStyle lg = const TextStyle( color: AppColor.textPrimary, fontSize: 16, ); static TextStyle xl = const TextStyle( color: AppColor.textPrimary, fontSize: 18, ); static TextStyle xxl = const TextStyle( color: AppColor.textPrimary, fontSize: 20, ); static TextStyle h6 = const TextStyle( color: AppColor.textPrimary, fontSize: 22, ); static TextStyle h5 = const TextStyle( color: AppColor.textPrimary, fontSize: 24, ); static TextStyle h4 = const TextStyle( color: AppColor.textPrimary, fontSize: 26, ); static TextStyle h3 = const TextStyle( color: AppColor.textPrimary, fontSize: 28, ); static TextStyle h2 = const TextStyle( color: AppColor.textPrimary, fontSize: 30, ); static TextStyle h1 = const TextStyle( color: AppColor.textPrimary, fontSize: 32, ); } class PurchasePage extends StatefulWidget { const PurchasePage({Key? key}) : super(key: key); @override State createState() => _PurchasePageState(); } class _PurchasePageState extends State with TickerProviderStateMixin { late AnimationController rotationAnimation; late AnimationController cardAnimation; late AnimationController floatingAnimation; String selectedFilter = 'Semua'; final List filterOptions = [ 'Semua', 'Pending', 'Completed', 'Cancelled', ]; final List> purchaseData = [ { 'id': 'PO-001', 'supplier': 'PT. Sumber Rezeki', 'date': '15 Aug 2025', 'total': 2500000, 'status': 'Completed', 'items': 15, }, { 'id': 'PO-002', 'supplier': 'CV. Maju Jaya', 'date': '14 Aug 2025', 'total': 1750000, 'status': 'Pending', 'items': 8, }, { 'id': 'PO-003', 'supplier': 'PT. Global Supply', 'date': '13 Aug 2025', 'total': 3200000, 'status': 'Completed', 'items': 22, }, { 'id': 'PO-004', 'supplier': 'UD. Berkah Mandiri', 'date': '12 Aug 2025', 'total': 890000, 'status': 'Cancelled', 'items': 5, }, ]; @override void initState() { super.initState(); rotationAnimation = AnimationController( duration: const Duration(seconds: 20), vsync: this, )..repeat(); cardAnimation = AnimationController( duration: const Duration(milliseconds: 1200), vsync: this, ); floatingAnimation = AnimationController( duration: const Duration(seconds: 3), vsync: this, )..repeat(reverse: true); cardAnimation.forward(); } @override void dispose() { rotationAnimation.dispose(); cardAnimation.dispose(); floatingAnimation.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColor.background, body: CustomScrollView( slivers: [ SliverAppBar( expandedHeight: 120.0, floating: false, pinned: true, elevation: 0, backgroundColor: AppColor.primary, flexibleSpace: PurchaseAppbar( rotationAnimation: rotationAnimation, floatingAnimation: floatingAnimation, ), ), // Stats Cards SliverToBoxAdapter( child: Container( color: AppColor.background, padding: const EdgeInsets.all(16.0), child: Row( children: [ Expanded( child: PurchaseStatCard( title: 'Total Pembelian', value: 'Rp 8.340.000', icon: LineIcons.shoppingCart, iconColor: AppColor.success, cardAnimation: cardAnimation, ), ), const SizedBox(width: 12), Expanded( child: PurchaseStatCard( title: 'Pending Order', value: '3 Orders', icon: LineIcons.clock, iconColor: AppColor.warning, cardAnimation: cardAnimation, ), ), ], ), ), ), // Filter Section SliverToBoxAdapter( child: Container( color: AppColor.surface, padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Riwayat Pembelian', style: AppStyle.lg.copyWith( fontWeight: FontWeight.w600, ), ), Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 6, ), decoration: BoxDecoration( color: AppColor.primary, borderRadius: BorderRadius.circular(20), ), child: Text( '${purchaseData.length} Orders', style: AppStyle.sm.copyWith( color: AppColor.textWhite, ), ), ), ], ), const SizedBox(height: 12), SizedBox( height: 40, child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: filterOptions.length, itemBuilder: (context, index) { final isSelected = selectedFilter == filterOptions[index]; return PurchaseStatusChip( isSelected: isSelected, text: filterOptions[index], onSelected: (selected) { setState(() { selectedFilter = filterOptions[index]; }); }, ); }, ), ), ], ), ), ), // Purchase List SliverPadding( padding: const EdgeInsets.all(16), sliver: SliverList( delegate: SliverChildBuilderDelegate((context, index) { final purchase = purchaseData[index]; return AnimatedBuilder( animation: cardAnimation, builder: (context, child) { final delay = index * 0.1; final animValue = (cardAnimation.value - delay).clamp( 0.0, 1.0, ); return Transform.translate( offset: Offset(0, 30 * (1 - animValue)), child: Opacity( opacity: animValue, child: PurchaseTile(purchase: purchase, index: index), ), ); }, ); }, childCount: purchaseData.length), ), ), // Bottom spacing for FAB const SliverToBoxAdapter(child: SizedBox(height: 80)), ], ), floatingActionButton: FloatingActionButton.extended( onPressed: () { // Navigate to create new purchase }, backgroundColor: AppColor.secondary, icon: const Icon(LineIcons.plus, color: AppColor.textWhite), label: Text( 'Buat Pembelian', style: AppStyle.md.copyWith( color: AppColor.textWhite, fontWeight: FontWeight.w600, ), ), ), ); } }