From dc4fdf5fbf6f35918b37f408c63e66313104a208 Mon Sep 17 00:00:00 2001 From: efrilm Date: Thu, 4 Sep 2025 21:40:30 +0700 Subject: [PATCH] feat: update draw detail page --- lib/presentation/pages/draw/draw_page.dart | 2 +- .../pages/draw_detail/draw_detail_page.dart | 910 +----------------- .../draw_detail/pages/draw_info_page.dart | 685 +++++++++++++ .../pages/draw_my_number_page.dart | 478 +++++++++ .../draw_detail/pages/draw_today_page.dart | 452 +++++++++ .../draw_detail/pages/draw_winner_page.dart | 536 +++++++++++ .../draw_detail/widgets/bottom_navbar.dart | 39 + lib/presentation/router/app_router.dart | 10 +- lib/presentation/router/app_router.gr.dart | 459 +++++---- 9 files changed, 2473 insertions(+), 1098 deletions(-) create mode 100644 lib/presentation/pages/draw/pages/draw_detail/pages/draw_info_page.dart create mode 100644 lib/presentation/pages/draw/pages/draw_detail/pages/draw_my_number_page.dart create mode 100644 lib/presentation/pages/draw/pages/draw_detail/pages/draw_today_page.dart create mode 100644 lib/presentation/pages/draw/pages/draw_detail/pages/draw_winner_page.dart create mode 100644 lib/presentation/pages/draw/pages/draw_detail/widgets/bottom_navbar.dart diff --git a/lib/presentation/pages/draw/draw_page.dart b/lib/presentation/pages/draw/draw_page.dart index a2c90ab..9bdd31b 100644 --- a/lib/presentation/pages/draw/draw_page.dart +++ b/lib/presentation/pages/draw/draw_page.dart @@ -217,7 +217,7 @@ class _DrawPageState extends State { final timeRemaining = _getTimeRemaining(draw.drawDate); return GestureDetector( - onTap: () => context.router.push(DrawDetailRoute(drawEvent: draw)), + onTap: () => context.router.push(DrawDetailRoute()), child: Container( margin: EdgeInsets.only(bottom: 8), padding: EdgeInsets.all(12), diff --git a/lib/presentation/pages/draw/pages/draw_detail/draw_detail_page.dart b/lib/presentation/pages/draw/pages/draw_detail/draw_detail_page.dart index e716a61..addb295 100644 --- a/lib/presentation/pages/draw/pages/draw_detail/draw_detail_page.dart +++ b/lib/presentation/pages/draw/pages/draw_detail/draw_detail_page.dart @@ -1,905 +1,31 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; + import '../../../../../common/theme/theme.dart'; -import '../../draw_page.dart'; - -// Prize model -class Prize { - final String id; - final String name; - final String value; - final String icon; - final int quantity; - final String description; - - Prize({ - required this.id, - required this.name, - required this.value, - required this.icon, - required this.quantity, - required this.description, - }); -} - -// Voucher model -class UserVoucher { - final String id; - final String drawId; - final String voucherNumber; - final DateTime createdDate; - final String status; // 'active', 'used', 'expired' - - UserVoucher({ - required this.id, - required this.drawId, - required this.voucherNumber, - required this.createdDate, - required this.status, - }); -} +import '../../../../router/app_router.gr.dart'; +import 'widgets/bottom_navbar.dart'; @RoutePage() -class DrawDetailPage extends StatefulWidget { - final DrawEvent drawEvent; - - const DrawDetailPage({super.key, required this.drawEvent}); - - @override - State createState() => _DrawDetailPageState(); -} - -class _DrawDetailPageState extends State - with TickerProviderStateMixin { - late TabController _tabController; - - // Sample data - final List prizes = [ - Prize( - id: "1", - name: "Emas 3 Gram", - value: "Rp 2.500.000", - icon: "👑", - quantity: 1, - description: - "Emas murni 24 karat seberat 3 gram dari toko emas terpercaya", - ), - Prize( - id: "2", - name: "Emas 1 Gram", - value: "Rp 850.000", - icon: "🥇", - quantity: 1, - description: - "Emas murni 24 karat seberat 1 gram dari toko emas terpercaya", - ), - ]; - - final List userVouchers = [ - UserVoucher( - id: "1", - drawId: "1", - voucherNumber: "ENK001234567", - createdDate: DateTime.now().subtract(Duration(hours: 2)), - status: 'active', - ), - ]; - - @override - void initState() { - super.initState(); - _tabController = TabController(length: 4, vsync: this); - } - - @override - void dispose() { - _tabController.dispose(); - super.dispose(); - } - - String _getTimeRemaining(DateTime targetDate) { - final now = DateTime.now(); - final difference = targetDate.difference(now); - - if (difference.isNegative) return "Sudah berakhir"; - - if (difference.inDays > 0) { - return "${difference.inDays} hari ${difference.inHours % 24} jam"; - } else if (difference.inHours > 0) { - return "${difference.inHours} jam ${difference.inMinutes % 60} menit"; - } else if (difference.inMinutes > 0) { - return "${difference.inMinutes} menit"; - } else { - return "Berakhir sekarang!"; - } - } - - String _formatCurrency(int amount) { - return amount.toString().replaceAllMapped( - RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), - (Match m) => '${m[1]}.', - ); - } +class DrawDetailPage extends StatelessWidget { + const DrawDetailPage({super.key}); @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppColor.background, - body: CustomScrollView( - slivers: [ - // App Bar with gradient - SliverAppBar( - expandedHeight: 200, - pinned: true, - backgroundColor: widget.drawEvent.primaryColor, - leading: IconButton( - icon: Icon(Icons.arrow_back, color: AppColor.textWhite), - onPressed: () => Navigator.of(context).pop(), - ), - flexibleSpace: FlexibleSpaceBar( - background: Container( - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - widget.drawEvent.primaryColor, - widget.drawEvent.primaryColor.withOpacity(0.8), - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - ), - child: Stack( - children: [ - // Background decoration - Positioned( - right: 20, - top: 60, - child: Opacity( - opacity: 0.2, - child: Column( - children: [ - Row( - children: [ - _buildCoin(), - SizedBox(width: 8), - _buildCoin(), - SizedBox(width: 8), - _buildCoin(), - ], - ), - SizedBox(height: 12), - _buildGoldBar(), - ], - ), - ), - ), - - // Content - Padding( - padding: EdgeInsets.only(left: 20, right: 20, top: 100), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (widget.drawEvent.isActive) - Container( - padding: EdgeInsets.symmetric( - horizontal: 12, - vertical: 6, - ), - decoration: BoxDecoration( - color: AppColor.success, - borderRadius: BorderRadius.circular(20), - ), - child: Text( - "UNDIAN AKTIF", - style: AppStyle.xs.copyWith( - color: AppColor.textWhite, - fontWeight: FontWeight.bold, - ), - ), - ), - SizedBox(height: 8), - Text( - widget.drawEvent.name, - style: AppStyle.h3.copyWith( - color: AppColor.textWhite, - fontWeight: FontWeight.bold, - ), - ), - Text( - widget.drawEvent.description.split('\n').first, - style: AppStyle.md.copyWith( - color: AppColor.textWhite.withOpacity(0.9), - ), - ), - ], - ), - ), - ], - ), - ), - ), - ), - - // Tab Bar - SliverPersistentHeader( - pinned: true, - delegate: _SliverTabBarDelegate( - TabBar( - controller: _tabController, - labelColor: AppColor.primary, - unselectedLabelColor: AppColor.textSecondary, - indicatorColor: AppColor.primary, - indicatorWeight: 3, - labelStyle: AppStyle.md.copyWith(fontWeight: FontWeight.w600), - unselectedLabelStyle: AppStyle.md, - tabs: [ - Tab(text: "Info"), - Tab(text: "Hadiah"), - Tab(text: "Voucher"), - Tab(text: "S&K"), - ], - ), - ), - ), - - // Tab Content - SliverFillRemaining( - child: TabBarView( - controller: _tabController, - children: [ - _buildInfoTab(), - _buildPrizesTab(), - _buildVouchersTab(), - _buildTermsTab(), - ], - ), - ), - ], - ), - ); - } - - Widget _buildInfoTab() { - final timeRemaining = _getTimeRemaining(widget.drawEvent.drawDate); - - return SingleChildScrollView( - padding: EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildInfoCard( - title: "Informasi Undian", - children: [ - _buildInfoRow("Nama Undian", widget.drawEvent.name), - _buildInfoRow("Deskripsi", widget.drawEvent.description), - _buildInfoRow( - "Total Hadiah", - "${widget.drawEvent.hadiah} hadiah", - ), - _buildInfoRow("Nilai Hadiah", widget.drawEvent.prizeValue), - _buildInfoRow( - "Status", - widget.drawEvent.isActive ? "Aktif" : "Selesai", - ), - ], - ), - - SizedBox(height: 16), - - _buildInfoCard( - title: "Waktu Undian", - children: [ - _buildInfoRow( - "Tanggal Pengundian", - _formatDateTime(widget.drawEvent.drawDate), - ), - _buildInfoRow("Waktu Tersisa", timeRemaining), - ], - ), - - SizedBox(height: 16), - - _buildInfoCard( - title: "Statistik", - children: [ - _buildInfoRow( - "Total Peserta", - "${widget.drawEvent.totalParticipants} orang", - ), - _buildInfoRow( - "Voucher Anda", - "${userVouchers.where((v) => v.drawId == widget.drawEvent.id).length}", - ), - _buildInfoRow( - "Minimum Belanja", - "Rp ${_formatCurrency(widget.drawEvent.minSpending)}", - ), - ], - ), - ], - ), - ); - } - - Widget _buildPrizesTab() { - return SingleChildScrollView( - padding: EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Daftar Hadiah", - style: AppStyle.lg.copyWith( - fontWeight: FontWeight.bold, - color: AppColor.textPrimary, - ), - ), - SizedBox(height: 16), - - ...prizes.map((prize) => _buildPrizeCard(prize)).toList(), - - SizedBox(height: 16), - - _buildInfoCard( - title: "Ketentuan Hadiah", - children: [ - _buildBulletPoint( - "Hadiah akan diumumkan setelah pengundian selesai", - ), - _buildBulletPoint( - "Pemenang akan dihubungi melalui nomor telepon terdaftar", - ), - _buildBulletPoint("Hadiah harus diambil dalam waktu 30 hari"), - _buildBulletPoint( - "Hadiah tidak dapat dipindahtangankan atau ditukar uang", - ), - ], - ), - ], - ), - ); - } - - Widget _buildVouchersTab() { - final drawVouchers = userVouchers - .where((v) => v.drawId == widget.drawEvent.id) - .toList(); - - return SingleChildScrollView( - padding: EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Voucher Anda", - style: AppStyle.lg.copyWith( - fontWeight: FontWeight.bold, - color: AppColor.textPrimary, - ), - ), - SizedBox(height: 8), - Text( - "Total: ${drawVouchers.length} voucher", - style: AppStyle.md.copyWith(color: AppColor.textSecondary), - ), - SizedBox(height: 16), - - if (drawVouchers.isEmpty) - _buildEmptyVoucherState() - else - ...drawVouchers - .map((voucher) => _buildVoucherCard(voucher)) - .toList(), - - SizedBox(height: 16), - - _buildInfoCard( - title: "Cara Mendapat Voucher", - children: [ - _buildBulletPoint( - "Lakukan pembelian minimum Rp ${_formatCurrency(widget.drawEvent.minSpending)}", - ), - _buildBulletPoint("Voucher otomatis akan masuk ke akun Anda"), - _buildBulletPoint( - "Semakin banyak voucher, semakin besar peluang menang", - ), - _buildBulletPoint("Voucher berlaku hingga pengundian selesai"), - ], - ), - ], - ), - ); - } - - Widget _buildTermsTab() { - return SingleChildScrollView( - padding: EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Syarat dan Ketentuan", - style: AppStyle.lg.copyWith( - fontWeight: FontWeight.bold, - color: AppColor.textPrimary, - ), - ), - SizedBox(height: 16), - - _buildTermsSection( - title: "Syarat Partisipasi", - terms: [ - "Pengguna harus terdaftar sebagai member Enaklo", - "Melakukan pembelian minimum Rp ${_formatCurrency(widget.drawEvent.minSpending)}", - "Pembelian harus dilakukan sebelum waktu pengundian", - "Satu transaksi pembelian = satu voucher undian", - ], - ), - - _buildTermsSection( - title: "Ketentuan Pengundian", - terms: [ - "Pengundian dilakukan secara transparan dan fair", - "Pemenang ditentukan secara acak oleh sistem", - "Keputusan pengundian bersifat final dan tidak dapat diganggu gugat", - "Pengumuman pemenang akan dilakukan maksimal 3 hari setelah pengundian", - ], - ), - - _buildTermsSection( - title: "Ketentuan Hadiah", - terms: [ - "Hadiah harus diambil dalam waktu 30 hari setelah pengumuman", - "Hadiah yang tidak diambil dalam batas waktu dianggap hangus", - "Hadiah tidak dapat ditukar dengan uang tunai", - "Pajak hadiah (jika ada) menjadi tanggung jawab pemenang", - ], - ), - - _buildTermsSection( - title: "Ketentuan Lainnya", - terms: [ - "Enaklo berhak membatalkan undian jika terjadi kecurangan", - "Peserta bertanggung jawab atas kebenaran data yang diberikan", - "Enaklo tidak bertanggung jawab atas kerugian akibat kesalahan peserta", - "Syarat dan ketentuan dapat berubah sewaktu-waktu tanpa pemberitahuan", - ], - ), - ], - ), - ); - } - - Widget _buildInfoCard({ - required String title, - required List children, - }) { - return Container( - width: double.infinity, - decoration: BoxDecoration( - color: AppColor.surface, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: AppColor.black.withOpacity(0.05), - blurRadius: 8, - offset: Offset(0, 2), - ), - ], - ), - child: Padding( - padding: EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: AppStyle.lg.copyWith( - fontWeight: FontWeight.bold, - color: AppColor.textPrimary, - ), - ), - SizedBox(height: 12), - ...children, - ], + return AutoTabsRouter.pageView( + routes: [ + DrawTodayRoute(), + DrawMyNumberRoute(), + DrawWinnerRoute(), + DrawInfoRoute(), + ], + physics: const NeverScrollableScrollPhysics(), + builder: (context, child, pageController) => Scaffold( + body: child, + backgroundColor: AppColor.primary, + bottomNavigationBar: DrawDetailBottomNavbar( + tabsRouter: AutoTabsRouter.of(context), ), ), ); } - - Widget _buildInfoRow(String label, String value) { - return Padding( - padding: EdgeInsets.symmetric(vertical: 4), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: 120, - child: Text( - label, - style: AppStyle.sm.copyWith(color: AppColor.textSecondary), - ), - ), - Text( - ": ", - style: AppStyle.sm.copyWith(color: AppColor.textSecondary), - ), - Expanded( - child: Text( - value, - style: AppStyle.sm.copyWith( - color: AppColor.textPrimary, - fontWeight: FontWeight.w500, - ), - ), - ), - ], - ), - ); - } - - Widget _buildPrizeCard(Prize prize) { - return Container( - margin: EdgeInsets.only(bottom: 12), - decoration: BoxDecoration( - color: AppColor.surface, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColor.borderLight), - boxShadow: [ - BoxShadow( - color: AppColor.black.withOpacity(0.05), - blurRadius: 8, - offset: Offset(0, 2), - ), - ], - ), - child: Padding( - padding: EdgeInsets.all(16), - child: Row( - children: [ - Container( - width: 60, - height: 60, - decoration: BoxDecoration( - color: widget.drawEvent.primaryColor.withOpacity(0.1), - borderRadius: BorderRadius.circular(30), - ), - child: Center(child: Text(prize.icon, style: AppStyle.h4)), - ), - SizedBox(width: 16), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - prize.name, - style: AppStyle.lg.copyWith( - fontWeight: FontWeight.bold, - color: AppColor.textPrimary, - ), - ), - SizedBox(height: 4), - Text( - prize.value, - style: AppStyle.md.copyWith( - color: AppColor.primary, - fontWeight: FontWeight.w600, - ), - ), - SizedBox(height: 4), - Text( - prize.description, - style: AppStyle.sm.copyWith(color: AppColor.textSecondary), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - ], - ), - ), - Container( - padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: AppColor.primary.withOpacity(0.1), - borderRadius: BorderRadius.circular(6), - ), - child: Text( - "${prize.quantity}x", - style: AppStyle.sm.copyWith( - color: AppColor.primary, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - ), - ); - } - - Widget _buildVoucherCard(UserVoucher voucher) { - Color statusColor; - String statusText; - - switch (voucher.status) { - case 'active': - statusColor = AppColor.success; - statusText = "Aktif"; - break; - case 'used': - statusColor = AppColor.textSecondary; - statusText = "Terpakai"; - break; - case 'expired': - statusColor = AppColor.error; - statusText = "Kadaluarsa"; - break; - default: - statusColor = AppColor.textSecondary; - statusText = "Tidak Diketahui"; - } - - return Container( - margin: EdgeInsets.only(bottom: 12), - decoration: BoxDecoration( - color: AppColor.surface, - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: voucher.status == 'active' - ? AppColor.primary.withOpacity(0.3) - : AppColor.borderLight, - ), - boxShadow: [ - BoxShadow( - color: AppColor.black.withOpacity(0.05), - blurRadius: 8, - offset: Offset(0, 2), - ), - ], - ), - child: Padding( - padding: EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Voucher Undian", - style: AppStyle.md.copyWith( - fontWeight: FontWeight.w600, - color: AppColor.textPrimary, - ), - ), - Container( - padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: statusColor.withOpacity(0.1), - borderRadius: BorderRadius.circular(6), - ), - child: Text( - statusText, - style: AppStyle.xs.copyWith( - color: statusColor, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - SizedBox(height: 8), - Container( - padding: EdgeInsets.all(12), - decoration: BoxDecoration( - color: AppColor.backgroundLight, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColor.borderLight), - ), - child: Center( - child: Text( - voucher.voucherNumber, - style: AppStyle.lg.copyWith( - fontWeight: FontWeight.bold, - color: AppColor.textPrimary, - letterSpacing: 1.2, - ), - ), - ), - ), - SizedBox(height: 8), - Text( - "Diperoleh: ${_formatDateTime(voucher.createdDate)}", - style: AppStyle.sm.copyWith(color: AppColor.textSecondary), - ), - ], - ), - ), - ); - } - - Widget _buildEmptyVoucherState() { - return Container( - width: double.infinity, - padding: EdgeInsets.all(32), - decoration: BoxDecoration( - color: AppColor.surface, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColor.borderLight), - ), - child: Column( - children: [ - Icon(Icons.receipt_outlined, size: 64, color: AppColor.textLight), - SizedBox(height: 16), - Text( - "Belum Ada Voucher", - style: AppStyle.lg.copyWith( - fontWeight: FontWeight.w600, - color: AppColor.textPrimary, - ), - ), - SizedBox(height: 8), - Text( - "Lakukan pembelian untuk mendapatkan voucher undian", - style: AppStyle.md.copyWith(color: AppColor.textSecondary), - textAlign: TextAlign.center, - ), - SizedBox(height: 16), - ElevatedButton( - onPressed: () { - // Navigate to shop or show purchase dialog - }, - style: ElevatedButton.styleFrom( - backgroundColor: AppColor.primary, - foregroundColor: AppColor.textWhite, - padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - child: Text( - "Belanja Sekarang", - style: AppStyle.md.copyWith(fontWeight: FontWeight.w600), - ), - ), - ], - ), - ); - } - - Widget _buildTermsSection({ - required String title, - required List terms, - }) { - return Container( - margin: EdgeInsets.only(bottom: 24), - decoration: BoxDecoration( - color: AppColor.surface, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: AppColor.black.withOpacity(0.05), - blurRadius: 8, - offset: Offset(0, 2), - ), - ], - ), - child: Padding( - padding: EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: AppStyle.lg.copyWith( - fontWeight: FontWeight.bold, - color: AppColor.textPrimary, - ), - ), - SizedBox(height: 12), - ...terms.map((term) => _buildBulletPoint(term)).toList(), - ], - ), - ), - ); - } - - Widget _buildBulletPoint(String text) { - return Padding( - padding: EdgeInsets.symmetric(vertical: 4), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - margin: EdgeInsets.only(top: 6), - width: 4, - height: 4, - decoration: BoxDecoration( - color: AppColor.primary, - shape: BoxShape.circle, - ), - ), - SizedBox(width: 12), - Expanded( - child: Text( - text, - style: AppStyle.md.copyWith(color: AppColor.textPrimary), - ), - ), - ], - ), - ); - } - - Widget _buildCoin() { - return Container( - width: 24, - height: 24, - decoration: BoxDecoration( - color: AppColor.warning, - shape: BoxShape.circle, - border: Border.all(color: Colors.yellow, width: 1), - ), - child: Center( - child: Text( - "₹", - style: AppStyle.sm.copyWith( - color: Colors.orange[800], - fontWeight: FontWeight.bold, - ), - ), - ), - ); - } - - Widget _buildGoldBar() { - return Container( - width: 40, - height: 20, - decoration: BoxDecoration( - color: AppColor.warning, - borderRadius: BorderRadius.circular(4), - border: Border.all(color: Colors.yellow, width: 1), - ), - child: Center( - child: Text( - "GOLD", - style: AppStyle.xs.copyWith( - color: Colors.orange[800], - fontWeight: FontWeight.bold, - ), - ), - ), - ); - } - - String _formatDateTime(DateTime date) { - return "${date.day}/${date.month}/${date.year} ${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}"; - } -} - -// Custom SliverTabBarDelegate -class _SliverTabBarDelegate extends SliverPersistentHeaderDelegate { - final TabBar _tabBar; - - _SliverTabBarDelegate(this._tabBar); - - @override - double get minExtent => _tabBar.preferredSize.height; - @override - double get maxExtent => _tabBar.preferredSize.height; - - @override - Widget build( - BuildContext context, - double shrinkOffset, - bool overlapsContent, - ) { - return Container(color: AppColor.surface, child: _tabBar); - } - - @override - bool shouldRebuild(_SliverTabBarDelegate oldDelegate) { - return false; - } } diff --git a/lib/presentation/pages/draw/pages/draw_detail/pages/draw_info_page.dart b/lib/presentation/pages/draw/pages/draw_detail/pages/draw_info_page.dart new file mode 100644 index 0000000..e29d6a7 --- /dev/null +++ b/lib/presentation/pages/draw/pages/draw_detail/pages/draw_info_page.dart @@ -0,0 +1,685 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; + +import '../../../../../../common/theme/theme.dart'; + +@RoutePage() +class DrawInfoPage extends StatefulWidget { + const DrawInfoPage({super.key}); + + @override + State createState() => _DrawInfoPageState(); +} + +class _DrawInfoPageState extends State + with TickerProviderStateMixin { + bool showHadiah = true; + + late AnimationController _fadeController; + late AnimationController _slideController; + late AnimationController _scaleController; + late AnimationController _tabController; + + late Animation _fadeAnimation; + late Animation _slideAnimation; + late Animation _scaleAnimation; + + @override + void initState() { + super.initState(); + + _fadeController = AnimationController( + duration: Duration(milliseconds: 1200), + vsync: this, + ); + + _slideController = AnimationController( + duration: Duration(milliseconds: 800), + vsync: this, + ); + + _scaleController = AnimationController( + duration: Duration(milliseconds: 1000), + vsync: this, + ); + + _tabController = AnimationController( + duration: Duration(milliseconds: 300), + vsync: this, + ); + + _fadeAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: _fadeController, curve: Curves.easeInOut), + ); + + _slideAnimation = Tween(begin: Offset(0, 0.3), end: Offset.zero) + .animate( + CurvedAnimation(parent: _slideController, curve: Curves.easeOutCubic), + ); + + _scaleAnimation = Tween(begin: 0.8, end: 1.0).animate( + CurvedAnimation(parent: _scaleController, curve: Curves.elasticOut), + ); + + _startAnimations(); + } + + void _startAnimations() async { + await Future.delayed(Duration(milliseconds: 100)); + _fadeController.forward(); + + await Future.delayed(Duration(milliseconds: 200)); + _slideController.forward(); + + await Future.delayed(Duration(milliseconds: 300)); + _scaleController.forward(); + } + + @override + void dispose() { + _fadeController.dispose(); + _slideController.dispose(); + _scaleController.dispose(); + _tabController.dispose(); + super.dispose(); + } + + Widget _buildTitle() { + return SlideTransition( + position: _slideAnimation, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), + child: Row( + children: [ + Container( + width: 3, + height: 28, + decoration: BoxDecoration( + color: AppColor.white, + borderRadius: BorderRadius.circular(2), + ), + ), + SizedBox(width: 12), + Text( + 'Hadiah & Info', + style: AppStyle.h3.copyWith( + color: AppColor.textWhite, + fontWeight: FontWeight.w600, + letterSpacing: -0.5, + ), + ), + ], + ), + ), + ); + } + + Widget _buildTabButtons() { + return ScaleTransition( + scale: _scaleAnimation, + child: Container( + margin: EdgeInsets.symmetric(horizontal: 20), + child: Row( + children: [ + Expanded( + child: GestureDetector( + onTap: () { + setState(() => showHadiah = true); + _tabController.forward(); + }, + child: AnimatedContainer( + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + padding: EdgeInsets.symmetric(vertical: 14), + decoration: BoxDecoration( + color: showHadiah + ? AppColor.white + : AppColor.white.withOpacity(0.1), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: showHadiah + ? AppColor.white + : AppColor.white.withOpacity(0.3), + width: 1, + ), + boxShadow: showHadiah + ? [ + BoxShadow( + color: AppColor.black.withOpacity(0.1), + blurRadius: 15, + offset: Offset(0, 5), + ), + ] + : null, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.card_giftcard_rounded, + color: showHadiah + ? AppColor.primary + : AppColor.white.withOpacity(0.8), + size: 18, + ), + SizedBox(width: 6), + Text( + 'Hadiah', + style: AppStyle.sm.copyWith( + color: showHadiah + ? AppColor.primary + : AppColor.white.withOpacity(0.9), + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ), + ), + SizedBox(width: 12), + Expanded( + child: GestureDetector( + onTap: () { + setState(() => showHadiah = false); + _tabController.forward(); + }, + child: AnimatedContainer( + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + padding: EdgeInsets.symmetric(vertical: 14), + decoration: BoxDecoration( + color: !showHadiah + ? AppColor.white + : AppColor.white.withOpacity(0.1), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: !showHadiah + ? AppColor.white + : AppColor.white.withOpacity(0.3), + width: 1, + ), + boxShadow: !showHadiah + ? [ + BoxShadow( + color: AppColor.black.withOpacity(0.1), + blurRadius: 15, + offset: Offset(0, 5), + ), + ] + : null, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.info_outline_rounded, + color: !showHadiah + ? AppColor.primary + : AppColor.white.withOpacity(0.8), + size: 18, + ), + SizedBox(width: 6), + Text( + 'Info Undian', + style: AppStyle.sm.copyWith( + color: !showHadiah + ? AppColor.primary + : AppColor.white.withOpacity(0.9), + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildHadiahContent() { + return ListView( + physics: BouncingScrollPhysics(), + padding: EdgeInsets.symmetric(horizontal: 20), + children: [ + SizedBox(height: 20), + _buildPrizeCard( + 'Emas Batangan 3KG', + 'Hadiah utama untuk pemenang harian', + Icons.stars_rounded, + true, + 0, + ), + _buildPrizeCard( + 'Motor Yamaha NMAX', + 'Hadiah mingguan untuk 1 pemenang', + Icons.two_wheeler_rounded, + false, + 1, + ), + _buildPrizeCard( + 'Voucher Belanja 1 Juta', + 'Hadiah bulanan untuk 5 pemenang', + Icons.card_giftcard_rounded, + false, + 2, + ), + _buildPrizeCard( + 'Smartphone Samsung', + 'Hadiah khusus acara tertentu', + Icons.smartphone_rounded, + false, + 3, + ), + SizedBox(height: 20), + _buildContactButton(), + SizedBox(height: 30), + ], + ); + } + + Widget _buildInfoContent() { + return ListView( + physics: BouncingScrollPhysics(), + padding: EdgeInsets.symmetric(horizontal: 20), + children: [ + SizedBox(height: 20), + _buildInfoSection( + 'Cara Bermain', + [ + 'Setiap hari kamu akan mendapat 1 nomor undian otomatis', + 'Nomor undian global diumumkan setiap hari jam 8 malam', + 'Jika nomormu sama dengan nomor global, kamu menang!', + 'Pemenang akan dihubungi melalui kontak yang terdaftar', + ], + Icons.play_circle_outline_rounded, + 0, + ), + _buildInfoSection( + 'Syarat & Ketentuan', + [ + 'Peserta minimal berusia 18 tahun', + 'Satu akun per nomor telepon', + 'Hadiah wajib diambil dalam 30 hari', + 'Keputusan panitia tidak dapat diganggu gugat', + ], + Icons.gavel_rounded, + 1, + ), + _buildInfoSection( + 'FAQ', + [ + 'Q: Apakah gratis? A: Ya, sepenuhnya gratis', + 'Q: Berapa lama menunggu hasil? A: Maksimal 1 jam setelah pengumuman', + 'Q: Bisa ganti nomor? A: Tidak, nomor otomatis dari sistem', + 'Q: Pajak hadiah? A: Ditanggung penyelenggara', + ], + Icons.help_outline_rounded, + 2, + ), + SizedBox(height: 20), + _buildContactButton(), + SizedBox(height: 30), + ], + ); + } + + Widget _buildPrizeCard( + String title, + String description, + IconData icon, + bool isGold, + int index, + ) { + return TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 800 + (index * 200)), + curve: Curves.easeOutCubic, + builder: (context, value, child) { + return Transform.translate( + offset: Offset(0, 30 * (1 - value)), + child: Opacity( + opacity: value, + child: Container( + margin: EdgeInsets.only(bottom: 16), + decoration: BoxDecoration( + color: isGold + ? AppColor.white + : AppColor.white.withOpacity(0.12), + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: isGold + ? AppColor.warning.withOpacity(0.3) + : AppColor.white.withOpacity(0.2), + width: isGold ? 2 : 1, + ), + boxShadow: [ + BoxShadow( + color: isGold + ? AppColor.warning.withOpacity(0.3) + : AppColor.black.withOpacity(0.05), + blurRadius: isGold ? 20 : 10, + offset: Offset(0, isGold ? 8 : 4), + ), + ], + ), + child: Padding( + padding: EdgeInsets.all(20), + child: Row( + children: [ + Container( + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + gradient: isGold + ? LinearGradient( + colors: [ + AppColor.warning, + AppColor.warning.withOpacity(0.8), + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ) + : LinearGradient( + colors: AppColor.primaryGradient, + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: isGold + ? AppColor.warning.withOpacity(0.3) + : AppColor.primary.withOpacity(0.3), + blurRadius: 12, + offset: Offset(0, 4), + ), + ], + ), + child: Icon(icon, color: AppColor.white, size: 24), + ), + SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: AppStyle.md.copyWith( + color: isGold ? AppColor.primary : AppColor.white, + fontWeight: FontWeight.w700, + ), + ), + SizedBox(height: 4), + Text( + description, + style: AppStyle.sm.copyWith( + color: isGold + ? AppColor.textSecondary + : AppColor.white.withOpacity(0.8), + fontWeight: FontWeight.w500, + height: 1.3, + ), + ), + ], + ), + ), + if (isGold) + Container( + padding: EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: AppColor.primaryGradient, + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(8), + ), + child: Text( + 'TOP', + style: AppStyle.xs.copyWith( + color: AppColor.white, + fontWeight: FontWeight.w700, + ), + ), + ), + ], + ), + ), + ), + ), + ); + }, + ); + } + + Widget _buildInfoSection( + String title, + List items, + IconData icon, + int index, + ) { + return TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 800 + (index * 200)), + curve: Curves.easeOutCubic, + builder: (context, value, child) { + return Transform.translate( + offset: Offset(0, 30 * (1 - value)), + child: Opacity( + opacity: value, + child: Container( + margin: EdgeInsets.only(bottom: 16), + decoration: BoxDecoration( + color: AppColor.white.withOpacity(0.12), + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: AppColor.white.withOpacity(0.2), + width: 1, + ), + boxShadow: [ + BoxShadow( + color: AppColor.black.withOpacity(0.05), + blurRadius: 15, + offset: Offset(0, 8), + ), + ], + ), + child: Padding( + padding: EdgeInsets.all(20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: AppColor.primaryGradient, + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(10), + ), + child: Icon(icon, color: AppColor.white, size: 18), + ), + SizedBox(width: 12), + Text( + title, + style: AppStyle.md.copyWith( + color: AppColor.white, + fontWeight: FontWeight.w700, + ), + ), + ], + ), + SizedBox(height: 16), + ...items + .map( + (item) => Padding( + padding: EdgeInsets.only(bottom: 8), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: 4, + height: 4, + margin: EdgeInsets.only(top: 8, right: 12), + decoration: BoxDecoration( + color: AppColor.warning, + shape: BoxShape.circle, + ), + ), + Expanded( + child: Text( + item, + style: AppStyle.sm.copyWith( + color: AppColor.white.withOpacity(0.9), + fontWeight: FontWeight.w500, + height: 1.4, + ), + ), + ), + ], + ), + ), + ) + .toList(), + ], + ), + ), + ), + ), + ); + }, + ); + } + + Widget _buildContactButton() { + return TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 1200), + curve: Curves.elasticOut, + builder: (context, value, child) { + return Transform.scale( + scale: value, + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'Menghubungi layanan pelanggan...', + style: AppStyle.sm.copyWith(color: AppColor.white), + ), + backgroundColor: AppColor.primary, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + behavior: SnackBarBehavior.floating, + ), + ); + }, + borderRadius: BorderRadius.circular(16), + child: Container( + width: double.infinity, + padding: EdgeInsets.symmetric(vertical: 16), + decoration: BoxDecoration( + color: AppColor.white.withOpacity(0.12), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: AppColor.white.withOpacity(0.2), + width: 1, + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.support_agent_rounded, + color: AppColor.white, + size: 20, + ), + SizedBox(width: 8), + Text( + 'Hubungi Layanan Pelanggan', + style: AppStyle.md.copyWith( + color: AppColor.white, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ), + ), + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: AppColor.primaryGradient, + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + ), + child: SafeArea( + child: FadeTransition( + opacity: _fadeAnimation, + child: Column( + children: [ + SizedBox(height: 20), + + // Title + _buildTitle(), + + SizedBox(height: 20), + + // Tab Buttons + _buildTabButtons(), + + SizedBox(height: 20), + + // Content + Expanded( + child: AnimatedSwitcher( + duration: Duration(milliseconds: 300), + transitionBuilder: + (Widget child, Animation animation) { + return FadeTransition( + opacity: animation, + child: SlideTransition( + position: Tween( + begin: Offset(0.0, 0.1), + end: Offset.zero, + ).animate(animation), + child: child, + ), + ); + }, + child: showHadiah + ? _buildHadiahContent() + : _buildInfoContent(), + ), + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/presentation/pages/draw/pages/draw_detail/pages/draw_my_number_page.dart b/lib/presentation/pages/draw/pages/draw_detail/pages/draw_my_number_page.dart new file mode 100644 index 0000000..0e4571b --- /dev/null +++ b/lib/presentation/pages/draw/pages/draw_detail/pages/draw_my_number_page.dart @@ -0,0 +1,478 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; + +import '../../../../../../common/theme/theme.dart'; + +@RoutePage() +class DrawMyNumberPage extends StatefulWidget { + const DrawMyNumberPage({super.key}); + + @override + State createState() => _DrawMyNumberPageState(); +} + +class _DrawMyNumberPageState extends State + with TickerProviderStateMixin { + late AnimationController _fadeController; + late AnimationController _slideController; + late AnimationController _scaleController; + late AnimationController _pulseController; + + late Animation _fadeAnimation; + late Animation _slideAnimation; + late Animation _scaleAnimation; + late Animation _pulseAnimation; + + @override + void initState() { + super.initState(); + + _fadeController = AnimationController( + duration: Duration(milliseconds: 1200), + vsync: this, + ); + + _slideController = AnimationController( + duration: Duration(milliseconds: 800), + vsync: this, + ); + + _scaleController = AnimationController( + duration: Duration(milliseconds: 1000), + vsync: this, + ); + + _pulseController = AnimationController( + duration: Duration(milliseconds: 2500), + vsync: this, + ); + + _fadeAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: _fadeController, curve: Curves.easeInOut), + ); + + _slideAnimation = Tween(begin: Offset(0, 0.3), end: Offset.zero) + .animate( + CurvedAnimation(parent: _slideController, curve: Curves.easeOutCubic), + ); + + _scaleAnimation = Tween(begin: 0.8, end: 1.0).animate( + CurvedAnimation(parent: _scaleController, curve: Curves.elasticOut), + ); + + _pulseAnimation = Tween(begin: 1.0, end: 1.03).animate( + CurvedAnimation(parent: _pulseController, curve: Curves.easeInOut), + ); + + _startAnimations(); + } + + void _startAnimations() async { + await Future.delayed(Duration(milliseconds: 100)); + _fadeController.forward(); + + await Future.delayed(Duration(milliseconds: 200)); + _slideController.forward(); + + await Future.delayed(Duration(milliseconds: 300)); + _scaleController.forward(); + + await Future.delayed(Duration(milliseconds: 800)); + _pulseController.repeat(reverse: true); + } + + @override + void dispose() { + _fadeController.dispose(); + _slideController.dispose(); + _scaleController.dispose(); + _pulseController.dispose(); + super.dispose(); + } + + Widget _buildTitle() { + return SlideTransition( + position: _slideAnimation, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), + child: Row( + children: [ + Container( + width: 3, + height: 28, + decoration: BoxDecoration( + color: AppColor.white, + borderRadius: BorderRadius.circular(2), + ), + ), + SizedBox(width: 12), + Text( + 'Nomorku', + style: AppStyle.h3.copyWith( + color: AppColor.textWhite, + fontWeight: FontWeight.w600, + letterSpacing: -0.5, + ), + ), + ], + ), + ), + ); + } + + Widget _buildMyNumberCard() { + return ScaleTransition( + scale: _scaleAnimation, + child: Container( + margin: EdgeInsets.symmetric(horizontal: 20), + decoration: BoxDecoration( + color: AppColor.white, + borderRadius: BorderRadius.circular(24), + boxShadow: [ + BoxShadow( + color: AppColor.black.withOpacity(0.08), + blurRadius: 30, + spreadRadius: 0, + offset: Offset(0, 15), + ), + ], + ), + child: Padding( + padding: EdgeInsets.all(24), + child: Column( + children: [ + // Label + Container( + padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), + decoration: BoxDecoration( + color: AppColor.primary.withOpacity(0.08), + borderRadius: BorderRadius.circular(20), + ), + child: Text( + 'NOMOR UNDIANMU HARI INI', + style: AppStyle.xs.copyWith( + color: AppColor.primary, + fontWeight: FontWeight.w700, + letterSpacing: 1, + ), + ), + ), + + SizedBox(height: 20), + + // Animated Number + AnimatedBuilder( + animation: _pulseAnimation, + builder: (context, child) { + return Transform.scale( + scale: _pulseAnimation.value, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 16, + ), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + AppColor.primary.withOpacity(0.05), + AppColor.primary.withOpacity(0.02), + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: AppColor.primary.withOpacity(0.1), + width: 1, + ), + ), + child: Text( + '123123', + style: TextStyle( + color: AppColor.primary, + fontSize: 42, + fontWeight: FontWeight.w900, + letterSpacing: 12, + height: 1.0, + ), + ), + ), + ); + }, + ), + + SizedBox(height: 16), + + // Status Badge + TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 1200), + curve: Curves.elasticOut, + builder: (context, value, child) { + return Transform.scale( + scale: value, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 16, + vertical: 8, + ), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: AppColor.primaryGradient, + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: AppColor.primary.withOpacity(0.3), + blurRadius: 12, + offset: Offset(0, 4), + ), + ], + ), + child: Text( + 'Menunggu Hasil', + style: AppStyle.sm.copyWith( + color: AppColor.white, + fontWeight: FontWeight.w600, + ), + ), + ), + ); + }, + ), + ], + ), + ), + ), + ); + } + + Widget _buildShareButton() { + return SlideTransition( + position: Tween(begin: Offset(0, 0.5), end: Offset.zero).animate( + CurvedAnimation( + parent: _slideController, + curve: Interval(0.3, 1.0, curve: Curves.easeOutCubic), + ), + ), + child: Container( + margin: EdgeInsets.symmetric(horizontal: 20), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'Membagikan nomormu: 123123', + style: AppStyle.sm.copyWith(color: AppColor.white), + ), + backgroundColor: AppColor.primary, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + behavior: SnackBarBehavior.floating, + ), + ); + }, + borderRadius: BorderRadius.circular(16), + child: Container( + width: double.infinity, + padding: EdgeInsets.symmetric(vertical: 16), + decoration: BoxDecoration( + color: AppColor.white.withOpacity(0.12), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: AppColor.white.withOpacity(0.2), + width: 1, + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.share_rounded, color: AppColor.white, size: 20), + SizedBox(width: 8), + Text( + 'Bagikan Nomorku', + style: AppStyle.md.copyWith( + color: AppColor.white, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ), + ), + ), + ); + } + + Widget _buildHistorySection() { + return SlideTransition( + position: Tween(begin: Offset(0, 0.8), end: Offset.zero).animate( + CurvedAnimation( + parent: _slideController, + curve: Interval(0.5, 1.0, curve: Curves.easeOutCubic), + ), + ), + child: Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Riwayat Nomorku', + style: AppStyle.lg.copyWith( + color: AppColor.textWhite, + fontWeight: FontWeight.w600, + ), + ), + SizedBox(height: 12), + ], + ), + ), + ); + } + + Widget _buildHistoryCard( + String number, + String date, + String result, + int index, + ) { + return TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 800 + (index * 200)), + curve: Curves.easeOutCubic, + builder: (context, value, child) { + return Transform.translate( + offset: Offset(0, 30 * (1 - value)), + child: Opacity( + opacity: value, + child: Container( + margin: EdgeInsets.symmetric(horizontal: 20, vertical: 6), + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + color: AppColor.white.withOpacity(0.1), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: AppColor.white.withOpacity(0.15), + width: 1, + ), + boxShadow: [ + BoxShadow( + color: AppColor.black.withOpacity(0.05), + blurRadius: 10, + offset: Offset(0, 4), + ), + ], + ), + child: Row( + children: [ + // Number and Date + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + number, + style: AppStyle.md.copyWith( + color: AppColor.white, + fontWeight: FontWeight.w700, + letterSpacing: 2, + ), + ), + SizedBox(height: 4), + Text( + date, + style: AppStyle.xs.copyWith( + color: AppColor.white.withOpacity(0.7), + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ), + + // Result Badge + Container( + padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6), + decoration: BoxDecoration( + color: AppColor.error.withOpacity(0.1), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: AppColor.error.withOpacity(0.3), + width: 1, + ), + ), + child: Text( + result, + style: AppStyle.xs.copyWith( + color: AppColor.error.withOpacity(0.9), + fontWeight: FontWeight.w600, + ), + ), + ), + ], + ), + ), + ), + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: AppColor.primaryGradient, + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + ), + child: SafeArea( + child: FadeTransition( + opacity: _fadeAnimation, + child: ListView( + physics: BouncingScrollPhysics(), + children: [ + SizedBox(height: 20), + + // Title + _buildTitle(), + + SizedBox(height: 24), + + // My Number Card + _buildMyNumberCard(), + + SizedBox(height: 20), + + // Share Button + _buildShareButton(), + + SizedBox(height: 24), + + // History Section Title + _buildHistorySection(), + + // History Cards + _buildHistoryCard('138472', 'Kemarin', 'Kalah 😔', 0), + _buildHistoryCard('928374', '2 hari lalu', 'Kalah 😔', 1), + _buildHistoryCard('475829', '3 hari lalu', 'Kalah 😔', 2), + + SizedBox(height: 20), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/presentation/pages/draw/pages/draw_detail/pages/draw_today_page.dart b/lib/presentation/pages/draw/pages/draw_detail/pages/draw_today_page.dart new file mode 100644 index 0000000..88399e5 --- /dev/null +++ b/lib/presentation/pages/draw/pages/draw_detail/pages/draw_today_page.dart @@ -0,0 +1,452 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; + +import '../../../../../../common/theme/theme.dart'; + +@RoutePage() +class DrawTodayPage extends StatefulWidget { + const DrawTodayPage({super.key}); + + @override + State createState() => _DrawTodayPageState(); +} + +class _DrawTodayPageState extends State + with TickerProviderStateMixin { + late AnimationController _fadeController; + late AnimationController _slideController; + late AnimationController _scaleController; + late AnimationController _pulseController; + + late Animation _fadeAnimation; + late Animation _slideAnimation; + late Animation _scaleAnimation; + late Animation _pulseAnimation; + + @override + void initState() { + super.initState(); + + _fadeController = AnimationController( + duration: Duration(milliseconds: 1200), + vsync: this, + ); + + _slideController = AnimationController( + duration: Duration(milliseconds: 800), + vsync: this, + ); + + _scaleController = AnimationController( + duration: Duration(milliseconds: 1000), + vsync: this, + ); + + _pulseController = AnimationController( + duration: Duration(milliseconds: 2000), + vsync: this, + ); + + _fadeAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: _fadeController, curve: Curves.easeInOut), + ); + + _slideAnimation = Tween(begin: Offset(0, 0.3), end: Offset.zero) + .animate( + CurvedAnimation(parent: _slideController, curve: Curves.easeOutCubic), + ); + + _scaleAnimation = Tween(begin: 0.8, end: 1.0).animate( + CurvedAnimation(parent: _scaleController, curve: Curves.elasticOut), + ); + + _pulseAnimation = Tween(begin: 1.0, end: 1.02).animate( + CurvedAnimation(parent: _pulseController, curve: Curves.easeInOut), + ); + + _startAnimations(); + } + + void _startAnimations() async { + await Future.delayed(Duration(milliseconds: 100)); + _fadeController.forward(); + + await Future.delayed(Duration(milliseconds: 200)); + _slideController.forward(); + + await Future.delayed(Duration(milliseconds: 300)); + _scaleController.forward(); + + await Future.delayed(Duration(milliseconds: 800)); + _pulseController.repeat(reverse: true); + } + + @override + void dispose() { + _fadeController.dispose(); + _slideController.dispose(); + _scaleController.dispose(); + _pulseController.dispose(); + super.dispose(); + } + + Widget _buildTitle() { + return SlideTransition( + position: _slideAnimation, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), + child: Row( + children: [ + Container( + width: 3, + height: 28, + decoration: BoxDecoration( + color: AppColor.white, + borderRadius: BorderRadius.circular(2), + ), + ), + SizedBox(width: 12), + Text( + 'Undian Hari Ini', + style: AppStyle.h3.copyWith( + color: AppColor.textWhite, + fontWeight: FontWeight.w600, + letterSpacing: -0.5, + ), + ), + ], + ), + ), + ); + } + + Widget _buildLotteryCard() { + return ScaleTransition( + scale: _scaleAnimation, + child: Container( + margin: EdgeInsets.symmetric(horizontal: 20), + decoration: BoxDecoration( + color: AppColor.white, + borderRadius: BorderRadius.circular(24), + boxShadow: [ + BoxShadow( + color: AppColor.black.withOpacity(0.08), + blurRadius: 30, + spreadRadius: 0, + offset: Offset(0, 15), + ), + ], + ), + child: Padding( + padding: EdgeInsets.all(24), + child: Column( + children: [ + // Label + Container( + padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), + decoration: BoxDecoration( + color: AppColor.primary.withOpacity(0.08), + borderRadius: BorderRadius.circular(20), + ), + child: Text( + 'NOMOR UNDIAN GLOBAL', + style: AppStyle.xs.copyWith( + color: AppColor.primary, + fontWeight: FontWeight.w700, + letterSpacing: 1, + ), + ), + ), + + SizedBox(height: 20), + + // Animated Number + AnimatedBuilder( + animation: _pulseAnimation, + builder: (context, child) { + return Transform.scale( + scale: _pulseAnimation.value, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 16, + ), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + AppColor.primary.withOpacity(0.05), + AppColor.primary.withOpacity(0.02), + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: AppColor.primary.withOpacity(0.1), + width: 1, + ), + ), + child: Text( + '849302', + style: TextStyle( + color: AppColor.primary, + fontSize: 42, + fontWeight: FontWeight.w900, + letterSpacing: 12, + height: 1.0, + ), + ), + ), + ); + }, + ), + ], + ), + ), + ), + ); + } + + Widget _buildPrizeCard() { + return SlideTransition( + position: Tween(begin: Offset(0, 0.5), end: Offset.zero).animate( + CurvedAnimation( + parent: _slideController, + curve: Interval(0.3, 1.0, curve: Curves.easeOutCubic), + ), + ), + child: Container( + margin: EdgeInsets.symmetric(horizontal: 20), + padding: EdgeInsets.all(20), + decoration: BoxDecoration( + color: AppColor.white.withOpacity(0.12), + borderRadius: BorderRadius.circular(20), + border: Border.all(color: AppColor.white.withOpacity(0.2), width: 1), + boxShadow: [ + BoxShadow( + color: AppColor.black.withOpacity(0.05), + blurRadius: 15, + offset: Offset(0, 8), + ), + ], + ), + child: Column( + children: [ + // Animated Icon + TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 1500), + curve: Curves.elasticOut, + builder: (context, value, child) { + return Transform.scale( + scale: value, + child: Container( + padding: EdgeInsets.all(12), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + AppColor.warning, + AppColor.warning.withOpacity(0.8), + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: AppColor.warning.withOpacity(0.3), + blurRadius: 15, + offset: Offset(0, 6), + ), + ], + ), + child: Icon( + Icons.stars_rounded, + color: AppColor.white, + size: 24, + ), + ), + ); + }, + ), + + SizedBox(height: 16), + + Text( + 'HADIAH UTAMA', + style: AppStyle.xs.copyWith( + color: AppColor.white.withOpacity(0.7), + fontWeight: FontWeight.w600, + letterSpacing: 1.5, + ), + ), + + SizedBox(height: 6), + + Text( + 'Jika nomor undianmu sama,\nkamu pemenang 3KG Emas!', + textAlign: TextAlign.center, + style: AppStyle.md.copyWith( + color: AppColor.white, + fontWeight: FontWeight.w600, + height: 1.4, + ), + ), + ], + ), + ), + ); + } + + Widget _buildInfoCards() { + return SlideTransition( + position: Tween(begin: Offset(0, 0.8), end: Offset.zero).animate( + CurvedAnimation( + parent: _slideController, + curve: Interval(0.5, 1.0, curve: Curves.easeOutCubic), + ), + ), + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Column( + children: [ + // Next Draw Card + Container( + width: double.infinity, + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + color: AppColor.black.withOpacity(0.15), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: AppColor.white.withOpacity(0.15), + width: 1, + ), + ), + child: Row( + children: [ + Container( + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: AppColor.white.withOpacity(0.1), + borderRadius: BorderRadius.circular(10), + ), + child: Icon( + Icons.schedule_rounded, + color: AppColor.white, + size: 18, + ), + ), + + SizedBox(width: 12), + + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Undian Berikutnya', + style: AppStyle.xs.copyWith( + color: AppColor.white.withOpacity(0.7), + fontWeight: FontWeight.w500, + ), + ), + SizedBox(height: 2), + Text( + 'Diumumkan jam 8 malam', + style: AppStyle.sm.copyWith( + color: AppColor.white, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ], + ), + ), + + SizedBox(height: 12), + + // Check Ticket Card + Container( + width: double.infinity, + padding: EdgeInsets.all(14), + decoration: BoxDecoration( + color: AppColor.white.withOpacity(0.08), + borderRadius: BorderRadius.circular(14), + border: Border.all( + color: AppColor.white.withOpacity(0.12), + width: 1, + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.confirmation_number_outlined, + color: AppColor.white.withOpacity(0.8), + size: 16, + ), + SizedBox(width: 8), + Text( + 'Cek tiket undianmu di menu Tiket Saya', + style: AppStyle.xs.copyWith( + color: AppColor.white.withOpacity(0.9), + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ), + ], + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: AppColor.primaryGradient, + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + ), + child: SafeArea( + child: FadeTransition( + opacity: _fadeAnimation, + child: ListView( + physics: BouncingScrollPhysics(), + children: [ + SizedBox(height: 20), + + // Title + _buildTitle(), + + SizedBox(height: 24), + + // Lottery Card + _buildLotteryCard(), + + SizedBox(height: 20), + + // Prize Card + _buildPrizeCard(), + + SizedBox(height: 16), + + // Info Cards + _buildInfoCards(), + + SizedBox(height: 20), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/presentation/pages/draw/pages/draw_detail/pages/draw_winner_page.dart b/lib/presentation/pages/draw/pages/draw_detail/pages/draw_winner_page.dart new file mode 100644 index 0000000..ce7885e --- /dev/null +++ b/lib/presentation/pages/draw/pages/draw_detail/pages/draw_winner_page.dart @@ -0,0 +1,536 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' show cos, sin; + +import '../../../../../../common/theme/theme.dart'; + +@RoutePage() +class DrawWinnerPage extends StatefulWidget { + const DrawWinnerPage({super.key}); + + @override + State createState() => _DrawWinnerPageState(); +} + +class _DrawWinnerPageState extends State + with TickerProviderStateMixin { + late AnimationController _fadeController; + late AnimationController _slideController; + late AnimationController _scaleController; + late AnimationController _pulseController; + late AnimationController _celebrationController; + + late Animation _fadeAnimation; + late Animation _slideAnimation; + late Animation _scaleAnimation; + late Animation _pulseAnimation; + late Animation _celebrationAnimation; + + @override + void initState() { + super.initState(); + + _fadeController = AnimationController( + duration: Duration(milliseconds: 1200), + vsync: this, + ); + + _slideController = AnimationController( + duration: Duration(milliseconds: 800), + vsync: this, + ); + + _scaleController = AnimationController( + duration: Duration(milliseconds: 1000), + vsync: this, + ); + + _pulseController = AnimationController( + duration: Duration(milliseconds: 2000), + vsync: this, + ); + + _celebrationController = AnimationController( + duration: Duration(milliseconds: 3000), + vsync: this, + ); + + _fadeAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: _fadeController, curve: Curves.easeInOut), + ); + + _slideAnimation = Tween(begin: Offset(0, 0.3), end: Offset.zero) + .animate( + CurvedAnimation(parent: _slideController, curve: Curves.easeOutCubic), + ); + + _scaleAnimation = Tween(begin: 0.8, end: 1.0).animate( + CurvedAnimation(parent: _scaleController, curve: Curves.elasticOut), + ); + + _pulseAnimation = Tween(begin: 1.0, end: 1.05).animate( + CurvedAnimation(parent: _pulseController, curve: Curves.easeInOut), + ); + + _celebrationAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: _celebrationController, curve: Curves.elasticOut), + ); + + _startAnimations(); + } + + void _startAnimations() async { + await Future.delayed(Duration(milliseconds: 100)); + _fadeController.forward(); + + await Future.delayed(Duration(milliseconds: 200)); + _slideController.forward(); + + await Future.delayed(Duration(milliseconds: 300)); + _scaleController.forward(); + + await Future.delayed(Duration(milliseconds: 600)); + _celebrationController.forward(); + + await Future.delayed(Duration(milliseconds: 800)); + _pulseController.repeat(reverse: true); + } + + @override + void dispose() { + _fadeController.dispose(); + _slideController.dispose(); + _scaleController.dispose(); + _pulseController.dispose(); + _celebrationController.dispose(); + super.dispose(); + } + + Widget _buildTitle() { + return SlideTransition( + position: _slideAnimation, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), + child: Row( + children: [ + Container( + width: 3, + height: 28, + decoration: BoxDecoration( + color: AppColor.white, + borderRadius: BorderRadius.circular(2), + ), + ), + SizedBox(width: 12), + Text( + 'Pemenang', + style: AppStyle.h3.copyWith( + color: AppColor.textWhite, + fontWeight: FontWeight.w600, + letterSpacing: -0.5, + ), + ), + ], + ), + ), + ); + } + + Widget _buildTodayWinnerBanner() { + return ScaleTransition( + scale: _scaleAnimation, + child: Container( + margin: EdgeInsets.symmetric(horizontal: 20), + decoration: BoxDecoration( + color: AppColor.white, + borderRadius: BorderRadius.circular(24), + boxShadow: [ + BoxShadow( + color: AppColor.warning.withOpacity(0.3), + blurRadius: 30, + spreadRadius: 0, + offset: Offset(0, 15), + ), + ], + ), + child: Stack( + children: [ + // Celebration Particles Effect + Positioned.fill( + child: AnimatedBuilder( + animation: _celebrationAnimation, + builder: (context, child) { + return CustomPaint( + painter: CelebrationPainter(_celebrationAnimation.value), + ); + }, + ), + ), + + // Main Content + Padding( + padding: EdgeInsets.all(24), + child: Column( + children: [ + // Trophy Icon with Animation + AnimatedBuilder( + animation: _celebrationAnimation, + builder: (context, child) { + return Transform.scale( + scale: _celebrationAnimation.value, + child: Transform.rotate( + angle: _celebrationAnimation.value * 0.1, + child: Container( + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + AppColor.warning, + AppColor.warning.withOpacity(0.8), + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: AppColor.warning.withOpacity(0.4), + blurRadius: 20, + offset: Offset(0, 8), + ), + ], + ), + child: Icon( + Icons.emoji_events_rounded, + color: AppColor.white, + size: 32, + ), + ), + ), + ); + }, + ), + + SizedBox(height: 16), + + // Title with Emoji + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Pemenang Hari Ini', + style: AppStyle.lg.copyWith( + color: AppColor.primary, + fontWeight: FontWeight.w700, + ), + ), + SizedBox(width: 8), + TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 1500), + curve: Curves.elasticOut, + builder: (context, value, child) { + return Transform.scale( + scale: value, + child: Text('🎉', style: TextStyle(fontSize: 20)), + ); + }, + ), + ], + ), + + SizedBox(height: 20), + + // Winning Number + AnimatedBuilder( + animation: _pulseAnimation, + builder: (context, child) { + return Transform.scale( + scale: _pulseAnimation.value, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 16, + ), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + AppColor.primary.withOpacity(0.05), + AppColor.primary.withOpacity(0.02), + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: AppColor.primary.withOpacity(0.1), + width: 1, + ), + ), + child: Text( + '849302', + style: TextStyle( + color: AppColor.primary, + fontSize: 36, + fontWeight: FontWeight.w900, + letterSpacing: 8, + height: 1.0, + ), + ), + ), + ); + }, + ), + + SizedBox(height: 16), + + // Winner Name + Container( + padding: EdgeInsets.symmetric(horizontal: 16, vertical: 10), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: AppColor.primaryGradient, + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: AppColor.primary.withOpacity(0.3), + blurRadius: 12, + offset: Offset(0, 4), + ), + ], + ), + child: Text( + 'Selamat untuk Andi***', + style: AppStyle.md.copyWith( + color: AppColor.white, + fontWeight: FontWeight.w600, + ), + ), + ), + ], + ), + ), + ], + ), + ), + ); + } + + Widget _buildHistorySection() { + return SlideTransition( + position: Tween(begin: Offset(0, 0.5), end: Offset.zero).animate( + CurvedAnimation( + parent: _slideController, + curve: Interval(0.3, 1.0, curve: Curves.easeOutCubic), + ), + ), + child: Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Pemenang Kemarin', + style: AppStyle.lg.copyWith( + color: AppColor.textWhite, + fontWeight: FontWeight.w600, + ), + ), + SizedBox(height: 12), + ], + ), + ), + ); + } + + Widget _buildWinnerCard(String number, String name, String date, int index) { + return TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 800 + (index * 200)), + curve: Curves.easeOutCubic, + builder: (context, value, child) { + return Transform.translate( + offset: Offset(0, 30 * (1 - value)), + child: Opacity( + opacity: value, + child: Container( + margin: EdgeInsets.symmetric(horizontal: 20, vertical: 6), + padding: EdgeInsets.all(18), + decoration: BoxDecoration( + color: AppColor.white.withOpacity(0.12), + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: AppColor.white.withOpacity(0.2), + width: 1, + ), + boxShadow: [ + BoxShadow( + color: AppColor.black.withOpacity(0.05), + blurRadius: 15, + offset: Offset(0, 8), + ), + ], + ), + child: Row( + children: [ + // Trophy Icon + Container( + padding: EdgeInsets.all(12), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + AppColor.warning, + AppColor.warning.withOpacity(0.8), + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: AppColor.warning.withOpacity(0.3), + blurRadius: 12, + offset: Offset(0, 4), + ), + ], + ), + child: Icon( + Icons.emoji_events_rounded, + color: AppColor.white, + size: 20, + ), + ), + + SizedBox(width: 16), + + // Winner Info + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + number, + style: AppStyle.md.copyWith( + color: AppColor.white, + fontWeight: FontWeight.w700, + letterSpacing: 2, + ), + ), + SizedBox(height: 4), + Text( + name, + style: AppStyle.sm.copyWith( + color: AppColor.warning, + fontWeight: FontWeight.w600, + ), + ), + SizedBox(height: 2), + Text( + date, + style: AppStyle.xs.copyWith( + color: AppColor.white.withOpacity(0.7), + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ), + + // Winner Badge + Container( + padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: AppColor.success.withOpacity(0.1), + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: AppColor.success.withOpacity(0.3), + width: 1, + ), + ), + child: Text('🏆', style: TextStyle(fontSize: 12)), + ), + ], + ), + ), + ), + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: AppColor.primaryGradient, + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + ), + child: SafeArea( + child: FadeTransition( + opacity: _fadeAnimation, + child: ListView( + physics: BouncingScrollPhysics(), + children: [ + SizedBox(height: 20), + + // Title + _buildTitle(), + + SizedBox(height: 24), + + // Today's Winner Banner + _buildTodayWinnerBanner(), + + SizedBox(height: 24), + + // History Section Title + _buildHistorySection(), + + // Winner History Cards + _buildWinnerCard('138472', 'Budi***', 'Kemarin', 0), + _buildWinnerCard('928374', 'Sari***', '2 hari lalu', 1), + _buildWinnerCard('475829', 'Dono***', '3 hari lalu', 2), + _buildWinnerCard('629384', 'Lisa***', '4 hari lalu', 3), + + SizedBox(height: 20), + ], + ), + ), + ), + ), + ); + } +} + +// Custom painter for celebration particles effect +class CelebrationPainter extends CustomPainter { + final double animationValue; + + CelebrationPainter(this.animationValue); + + @override + void paint(Canvas canvas, Size size) { + final paint = Paint()..style = PaintingStyle.fill; + + // Draw floating particles + for (int i = 0; i < 8; i++) { + final angle = (i * 45) * (3.14159 / 180); + final radius = animationValue * 40; + final x = size.width / 2 + radius * cos(angle); + final y = size.height / 2 + radius * sin(angle); + + paint.color = AppColor.warning.withOpacity(0.3 * animationValue); + canvas.drawCircle(Offset(x, y), 2 * animationValue, paint); + } + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) => true; +} diff --git a/lib/presentation/pages/draw/pages/draw_detail/widgets/bottom_navbar.dart b/lib/presentation/pages/draw/pages/draw_detail/widgets/bottom_navbar.dart new file mode 100644 index 0000000..f9dda29 --- /dev/null +++ b/lib/presentation/pages/draw/pages/draw_detail/widgets/bottom_navbar.dart @@ -0,0 +1,39 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; + +class DrawDetailBottomNavbar extends StatelessWidget { + final TabsRouter tabsRouter; + const DrawDetailBottomNavbar({super.key, required this.tabsRouter}); + + @override + Widget build(BuildContext context) { + return BottomNavigationBar( + currentIndex: tabsRouter.activeIndex, + onTap: (index) { + tabsRouter.setActiveIndex(index); + }, + items: const [ + BottomNavigationBarItem( + icon: Icon(Icons.today), + label: 'Hari Ini', + tooltip: 'Hari Ini', + ), + BottomNavigationBarItem( + icon: Icon(Icons.confirmation_number), + label: 'Nomorku', + tooltip: 'Nomorku', + ), + BottomNavigationBarItem( + icon: Icon(Icons.emoji_events), + label: 'Pemenang', + tooltip: 'Pemenang', + ), + BottomNavigationBarItem( + icon: Icon(Icons.info), + label: 'Hadiah & Info', + tooltip: 'Hadiah & Info', + ), + ], + ); + } +} diff --git a/lib/presentation/router/app_router.dart b/lib/presentation/router/app_router.dart index 3dd92fa..32f0bad 100644 --- a/lib/presentation/router/app_router.dart +++ b/lib/presentation/router/app_router.dart @@ -41,7 +41,15 @@ class AppRouter extends RootStackRouter { // Draw AutoRoute(page: DrawRoute.page), - AutoRoute(page: DrawDetailRoute.page), + AutoRoute( + page: DrawDetailRoute.page, + children: [ + AutoRoute(page: DrawTodayRoute.page), + AutoRoute(page: DrawMyNumberRoute.page), + AutoRoute(page: DrawWinnerRoute.page), + AutoRoute(page: DrawInfoRoute.page), + ], + ), // Voucher AutoRoute(page: VoucherDetailRoute.page), diff --git a/lib/presentation/router/app_router.gr.dart b/lib/presentation/router/app_router.gr.dart index a7606fb..dd0ae48 100644 --- a/lib/presentation/router/app_router.gr.dart +++ b/lib/presentation/router/app_router.gr.dart @@ -9,66 +9,74 @@ // coverage:ignore-file // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'package:auto_route/auto_route.dart' as _i29; +import 'package:auto_route/auto_route.dart' as _i33; import 'package:enaklo/presentation/pages/account/account_my/account_my_page.dart' as _i1; import 'package:enaklo/presentation/pages/account/address/address_page.dart' as _i2; import 'package:enaklo/presentation/pages/account/payment/payment_page.dart' - as _i18; + as _i22; import 'package:enaklo/presentation/pages/auth/create_password/create_password_page.dart' as _i3; -import 'package:enaklo/presentation/pages/auth/login/login_page.dart' as _i8; -import 'package:enaklo/presentation/pages/auth/otp/otp_page.dart' as _i16; +import 'package:enaklo/presentation/pages/auth/login/login_page.dart' as _i12; +import 'package:enaklo/presentation/pages/auth/otp/otp_page.dart' as _i20; import 'package:enaklo/presentation/pages/auth/password/password_page.dart' - as _i17; -import 'package:enaklo/presentation/pages/auth/pin/pin_page.dart' as _i19; + as _i21; +import 'package:enaklo/presentation/pages/auth/pin/pin_page.dart' as _i23; import 'package:enaklo/presentation/pages/auth/register/register_page.dart' - as _i24; -import 'package:enaklo/presentation/pages/draw/draw_page.dart' as _i5; + as _i28; +import 'package:enaklo/presentation/pages/draw/draw_page.dart' as _i7; import 'package:enaklo/presentation/pages/draw/pages/draw_detail/draw_detail_page.dart' as _i4; -import 'package:enaklo/presentation/pages/main/main_page.dart' as _i9; -import 'package:enaklo/presentation/pages/main/pages/home/home_page.dart' - as _i7; -import 'package:enaklo/presentation/pages/main/pages/order/order_page.dart' - as _i15; -import 'package:enaklo/presentation/pages/main/pages/profile/profile_page.dart' - as _i23; -import 'package:enaklo/presentation/pages/main/pages/voucher/voucher_page.dart' - as _i28; -import 'package:enaklo/presentation/pages/merchant/merchant_page.dart' as _i11; -import 'package:enaklo/presentation/pages/merchant/pages/merchant_detail/merchant_detail_page.dart' - as _i10; -import 'package:enaklo/presentation/pages/mini_games/ferris_wheel/ferris_wheel_page.dart' +import 'package:enaklo/presentation/pages/draw/pages/draw_detail/pages/draw_info_page.dart' + as _i5; +import 'package:enaklo/presentation/pages/draw/pages/draw_detail/pages/draw_my_number_page.dart' as _i6; -import 'package:enaklo/presentation/pages/notification/notification_page.dart' - as _i12; -import 'package:enaklo/presentation/pages/onboarding/onboarding_page.dart' - as _i13; -import 'package:enaklo/presentation/pages/order/order_detail/order_detail_page.dart' - as _i14; -import 'package:enaklo/presentation/pages/poin/pages/poin_history_page.dart' - as _i20; -import 'package:enaklo/presentation/pages/poin/pages/product_redeem/product_redeem_page.dart' - as _i22; -import 'package:enaklo/presentation/pages/poin/poin_page.dart' as _i21; -import 'package:enaklo/presentation/pages/reward/reward_page.dart' as _i25; -import 'package:enaklo/presentation/pages/splash/splash_page.dart' as _i26; -import 'package:enaklo/presentation/pages/voucher/voucher_detail/voucher_detail_page.dart' +import 'package:enaklo/presentation/pages/draw/pages/draw_detail/pages/draw_today_page.dart' + as _i8; +import 'package:enaklo/presentation/pages/draw/pages/draw_detail/pages/draw_winner_page.dart' + as _i9; +import 'package:enaklo/presentation/pages/main/main_page.dart' as _i13; +import 'package:enaklo/presentation/pages/main/pages/home/home_page.dart' + as _i11; +import 'package:enaklo/presentation/pages/main/pages/order/order_page.dart' + as _i19; +import 'package:enaklo/presentation/pages/main/pages/profile/profile_page.dart' as _i27; -import 'package:enaklo/sample/sample_data.dart' as _i31; -import 'package:flutter/material.dart' as _i30; +import 'package:enaklo/presentation/pages/main/pages/voucher/voucher_page.dart' + as _i32; +import 'package:enaklo/presentation/pages/merchant/merchant_page.dart' as _i15; +import 'package:enaklo/presentation/pages/merchant/pages/merchant_detail/merchant_detail_page.dart' + as _i14; +import 'package:enaklo/presentation/pages/mini_games/ferris_wheel/ferris_wheel_page.dart' + as _i10; +import 'package:enaklo/presentation/pages/notification/notification_page.dart' + as _i16; +import 'package:enaklo/presentation/pages/onboarding/onboarding_page.dart' + as _i17; +import 'package:enaklo/presentation/pages/order/order_detail/order_detail_page.dart' + as _i18; +import 'package:enaklo/presentation/pages/poin/pages/poin_history_page.dart' + as _i24; +import 'package:enaklo/presentation/pages/poin/pages/product_redeem/product_redeem_page.dart' + as _i26; +import 'package:enaklo/presentation/pages/poin/poin_page.dart' as _i25; +import 'package:enaklo/presentation/pages/reward/reward_page.dart' as _i29; +import 'package:enaklo/presentation/pages/splash/splash_page.dart' as _i30; +import 'package:enaklo/presentation/pages/voucher/voucher_detail/voucher_detail_page.dart' + as _i31; +import 'package:enaklo/sample/sample_data.dart' as _i35; +import 'package:flutter/material.dart' as _i34; /// generated route for /// [_i1.AccountMyPage] -class AccountMyRoute extends _i29.PageRouteInfo { - const AccountMyRoute({List<_i29.PageRouteInfo>? children}) +class AccountMyRoute extends _i33.PageRouteInfo { + const AccountMyRoute({List<_i33.PageRouteInfo>? children}) : super(AccountMyRoute.name, initialChildren: children); static const String name = 'AccountMyRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { return const _i1.AccountMyPage(); @@ -78,13 +86,13 @@ class AccountMyRoute extends _i29.PageRouteInfo { /// generated route for /// [_i2.AddressPage] -class AddressRoute extends _i29.PageRouteInfo { - const AddressRoute({List<_i29.PageRouteInfo>? children}) +class AddressRoute extends _i33.PageRouteInfo { + const AddressRoute({List<_i33.PageRouteInfo>? children}) : super(AddressRoute.name, initialChildren: children); static const String name = 'AddressRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { return const _i2.AddressPage(); @@ -94,13 +102,13 @@ class AddressRoute extends _i29.PageRouteInfo { /// generated route for /// [_i3.CreatePasswordPage] -class CreatePasswordRoute extends _i29.PageRouteInfo { - const CreatePasswordRoute({List<_i29.PageRouteInfo>? children}) +class CreatePasswordRoute extends _i33.PageRouteInfo { + const CreatePasswordRoute({List<_i33.PageRouteInfo>? children}) : super(CreatePasswordRoute.name, initialChildren: children); static const String name = 'CreatePasswordRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { return const _i3.CreatePasswordPage(); @@ -110,128 +118,171 @@ class CreatePasswordRoute extends _i29.PageRouteInfo { /// generated route for /// [_i4.DrawDetailPage] -class DrawDetailRoute extends _i29.PageRouteInfo { - DrawDetailRoute({ - _i30.Key? key, - required _i5.DrawEvent drawEvent, - List<_i29.PageRouteInfo>? children, - }) : super( - DrawDetailRoute.name, - args: DrawDetailRouteArgs(key: key, drawEvent: drawEvent), - initialChildren: children, - ); +class DrawDetailRoute extends _i33.PageRouteInfo { + const DrawDetailRoute({List<_i33.PageRouteInfo>? children}) + : super(DrawDetailRoute.name, initialChildren: children); static const String name = 'DrawDetailRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - final args = data.argsAs(); - return _i4.DrawDetailPage(key: args.key, drawEvent: args.drawEvent); + return const _i4.DrawDetailPage(); }, ); } -class DrawDetailRouteArgs { - const DrawDetailRouteArgs({this.key, required this.drawEvent}); +/// generated route for +/// [_i5.DrawInfoPage] +class DrawInfoRoute extends _i33.PageRouteInfo { + const DrawInfoRoute({List<_i33.PageRouteInfo>? children}) + : super(DrawInfoRoute.name, initialChildren: children); - final _i30.Key? key; + static const String name = 'DrawInfoRoute'; - final _i5.DrawEvent drawEvent; - - @override - String toString() { - return 'DrawDetailRouteArgs{key: $key, drawEvent: $drawEvent}'; - } + static _i33.PageInfo page = _i33.PageInfo( + name, + builder: (data) { + return const _i5.DrawInfoPage(); + }, + ); } /// generated route for -/// [_i5.DrawPage] -class DrawRoute extends _i29.PageRouteInfo { - const DrawRoute({List<_i29.PageRouteInfo>? children}) +/// [_i6.DrawMyNumberPage] +class DrawMyNumberRoute extends _i33.PageRouteInfo { + const DrawMyNumberRoute({List<_i33.PageRouteInfo>? children}) + : super(DrawMyNumberRoute.name, initialChildren: children); + + static const String name = 'DrawMyNumberRoute'; + + static _i33.PageInfo page = _i33.PageInfo( + name, + builder: (data) { + return const _i6.DrawMyNumberPage(); + }, + ); +} + +/// generated route for +/// [_i7.DrawPage] +class DrawRoute extends _i33.PageRouteInfo { + const DrawRoute({List<_i33.PageRouteInfo>? children}) : super(DrawRoute.name, initialChildren: children); static const String name = 'DrawRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i5.DrawPage(); + return const _i7.DrawPage(); }, ); } /// generated route for -/// [_i6.FerrisWheelPage] -class FerrisWheelRoute extends _i29.PageRouteInfo { - const FerrisWheelRoute({List<_i29.PageRouteInfo>? children}) +/// [_i8.DrawTodayPage] +class DrawTodayRoute extends _i33.PageRouteInfo { + const DrawTodayRoute({List<_i33.PageRouteInfo>? children}) + : super(DrawTodayRoute.name, initialChildren: children); + + static const String name = 'DrawTodayRoute'; + + static _i33.PageInfo page = _i33.PageInfo( + name, + builder: (data) { + return const _i8.DrawTodayPage(); + }, + ); +} + +/// generated route for +/// [_i9.DrawWinnerPage] +class DrawWinnerRoute extends _i33.PageRouteInfo { + const DrawWinnerRoute({List<_i33.PageRouteInfo>? children}) + : super(DrawWinnerRoute.name, initialChildren: children); + + static const String name = 'DrawWinnerRoute'; + + static _i33.PageInfo page = _i33.PageInfo( + name, + builder: (data) { + return const _i9.DrawWinnerPage(); + }, + ); +} + +/// generated route for +/// [_i10.FerrisWheelPage] +class FerrisWheelRoute extends _i33.PageRouteInfo { + const FerrisWheelRoute({List<_i33.PageRouteInfo>? children}) : super(FerrisWheelRoute.name, initialChildren: children); static const String name = 'FerrisWheelRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i6.FerrisWheelPage(); + return const _i10.FerrisWheelPage(); }, ); } /// generated route for -/// [_i7.HomePage] -class HomeRoute extends _i29.PageRouteInfo { - const HomeRoute({List<_i29.PageRouteInfo>? children}) +/// [_i11.HomePage] +class HomeRoute extends _i33.PageRouteInfo { + const HomeRoute({List<_i33.PageRouteInfo>? children}) : super(HomeRoute.name, initialChildren: children); static const String name = 'HomeRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i7.HomePage(); + return const _i11.HomePage(); }, ); } /// generated route for -/// [_i8.LoginPage] -class LoginRoute extends _i29.PageRouteInfo { - const LoginRoute({List<_i29.PageRouteInfo>? children}) +/// [_i12.LoginPage] +class LoginRoute extends _i33.PageRouteInfo { + const LoginRoute({List<_i33.PageRouteInfo>? children}) : super(LoginRoute.name, initialChildren: children); static const String name = 'LoginRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i8.LoginPage(); + return const _i12.LoginPage(); }, ); } /// generated route for -/// [_i9.MainPage] -class MainRoute extends _i29.PageRouteInfo { - const MainRoute({List<_i29.PageRouteInfo>? children}) +/// [_i13.MainPage] +class MainRoute extends _i33.PageRouteInfo { + const MainRoute({List<_i33.PageRouteInfo>? children}) : super(MainRoute.name, initialChildren: children); static const String name = 'MainRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i9.MainPage(); + return const _i13.MainPage(); }, ); } /// generated route for -/// [_i10.MerchantDetailPage] -class MerchantDetailRoute extends _i29.PageRouteInfo { +/// [_i14.MerchantDetailPage] +class MerchantDetailRoute extends _i33.PageRouteInfo { MerchantDetailRoute({ - _i30.Key? key, - required _i31.MerchantModel merchant, - List<_i29.PageRouteInfo>? children, + _i34.Key? key, + required _i35.MerchantModel merchant, + List<_i33.PageRouteInfo>? children, }) : super( MerchantDetailRoute.name, args: MerchantDetailRouteArgs(key: key, merchant: merchant), @@ -240,11 +291,11 @@ class MerchantDetailRoute extends _i29.PageRouteInfo { static const String name = 'MerchantDetailRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { final args = data.argsAs(); - return _i10.MerchantDetailPage(key: args.key, merchant: args.merchant); + return _i14.MerchantDetailPage(key: args.key, merchant: args.merchant); }, ); } @@ -252,9 +303,9 @@ class MerchantDetailRoute extends _i29.PageRouteInfo { class MerchantDetailRouteArgs { const MerchantDetailRouteArgs({this.key, required this.merchant}); - final _i30.Key? key; + final _i34.Key? key; - final _i31.MerchantModel merchant; + final _i35.MerchantModel merchant; @override String toString() { @@ -263,60 +314,60 @@ class MerchantDetailRouteArgs { } /// generated route for -/// [_i11.MerchantPage] -class MerchantRoute extends _i29.PageRouteInfo { - const MerchantRoute({List<_i29.PageRouteInfo>? children}) +/// [_i15.MerchantPage] +class MerchantRoute extends _i33.PageRouteInfo { + const MerchantRoute({List<_i33.PageRouteInfo>? children}) : super(MerchantRoute.name, initialChildren: children); static const String name = 'MerchantRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i11.MerchantPage(); + return const _i15.MerchantPage(); }, ); } /// generated route for -/// [_i12.NotificationPage] -class NotificationRoute extends _i29.PageRouteInfo { - const NotificationRoute({List<_i29.PageRouteInfo>? children}) +/// [_i16.NotificationPage] +class NotificationRoute extends _i33.PageRouteInfo { + const NotificationRoute({List<_i33.PageRouteInfo>? children}) : super(NotificationRoute.name, initialChildren: children); static const String name = 'NotificationRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i12.NotificationPage(); + return const _i16.NotificationPage(); }, ); } /// generated route for -/// [_i13.OnboardingPage] -class OnboardingRoute extends _i29.PageRouteInfo { - const OnboardingRoute({List<_i29.PageRouteInfo>? children}) +/// [_i17.OnboardingPage] +class OnboardingRoute extends _i33.PageRouteInfo { + const OnboardingRoute({List<_i33.PageRouteInfo>? children}) : super(OnboardingRoute.name, initialChildren: children); static const String name = 'OnboardingRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i13.OnboardingPage(); + return const _i17.OnboardingPage(); }, ); } /// generated route for -/// [_i14.OrderDetailPage] -class OrderDetailRoute extends _i29.PageRouteInfo { +/// [_i18.OrderDetailPage] +class OrderDetailRoute extends _i33.PageRouteInfo { OrderDetailRoute({ - _i30.Key? key, - required _i15.Order order, - List<_i29.PageRouteInfo>? children, + _i34.Key? key, + required _i19.Order order, + List<_i33.PageRouteInfo>? children, }) : super( OrderDetailRoute.name, args: OrderDetailRouteArgs(key: key, order: order), @@ -325,11 +376,11 @@ class OrderDetailRoute extends _i29.PageRouteInfo { static const String name = 'OrderDetailRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { final args = data.argsAs(); - return _i14.OrderDetailPage(key: args.key, order: args.order); + return _i18.OrderDetailPage(key: args.key, order: args.order); }, ); } @@ -337,9 +388,9 @@ class OrderDetailRoute extends _i29.PageRouteInfo { class OrderDetailRouteArgs { const OrderDetailRouteArgs({this.key, required this.order}); - final _i30.Key? key; + final _i34.Key? key; - final _i15.Order order; + final _i19.Order order; @override String toString() { @@ -348,77 +399,77 @@ class OrderDetailRouteArgs { } /// generated route for -/// [_i15.OrderPage] -class OrderRoute extends _i29.PageRouteInfo { - const OrderRoute({List<_i29.PageRouteInfo>? children}) +/// [_i19.OrderPage] +class OrderRoute extends _i33.PageRouteInfo { + const OrderRoute({List<_i33.PageRouteInfo>? children}) : super(OrderRoute.name, initialChildren: children); static const String name = 'OrderRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i15.OrderPage(); + return const _i19.OrderPage(); }, ); } /// generated route for -/// [_i16.OtpPage] -class OtpRoute extends _i29.PageRouteInfo { - const OtpRoute({List<_i29.PageRouteInfo>? children}) +/// [_i20.OtpPage] +class OtpRoute extends _i33.PageRouteInfo { + const OtpRoute({List<_i33.PageRouteInfo>? children}) : super(OtpRoute.name, initialChildren: children); static const String name = 'OtpRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i16.OtpPage(); + return const _i20.OtpPage(); }, ); } /// generated route for -/// [_i17.PasswordPage] -class PasswordRoute extends _i29.PageRouteInfo { - const PasswordRoute({List<_i29.PageRouteInfo>? children}) +/// [_i21.PasswordPage] +class PasswordRoute extends _i33.PageRouteInfo { + const PasswordRoute({List<_i33.PageRouteInfo>? children}) : super(PasswordRoute.name, initialChildren: children); static const String name = 'PasswordRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i17.PasswordPage(); + return const _i21.PasswordPage(); }, ); } /// generated route for -/// [_i18.PaymentPage] -class PaymentRoute extends _i29.PageRouteInfo { - const PaymentRoute({List<_i29.PageRouteInfo>? children}) +/// [_i22.PaymentPage] +class PaymentRoute extends _i33.PageRouteInfo { + const PaymentRoute({List<_i33.PageRouteInfo>? children}) : super(PaymentRoute.name, initialChildren: children); static const String name = 'PaymentRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i18.PaymentPage(); + return const _i22.PaymentPage(); }, ); } /// generated route for -/// [_i19.PinPage] -class PinRoute extends _i29.PageRouteInfo { +/// [_i23.PinPage] +class PinRoute extends _i33.PageRouteInfo { PinRoute({ - _i30.Key? key, + _i34.Key? key, bool isCreatePin = true, String? title, - List<_i29.PageRouteInfo>? children, + List<_i33.PageRouteInfo>? children, }) : super( PinRoute.name, args: PinRouteArgs(key: key, isCreatePin: isCreatePin, title: title), @@ -427,13 +478,13 @@ class PinRoute extends _i29.PageRouteInfo { static const String name = 'PinRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { final args = data.argsAs( orElse: () => const PinRouteArgs(), ); - return _i19.PinPage( + return _i23.PinPage( key: args.key, isCreatePin: args.isCreatePin, title: args.title, @@ -445,7 +496,7 @@ class PinRoute extends _i29.PageRouteInfo { class PinRouteArgs { const PinRouteArgs({this.key, this.isCreatePin = true, this.title}); - final _i30.Key? key; + final _i34.Key? key; final bool isCreatePin; @@ -458,45 +509,45 @@ class PinRouteArgs { } /// generated route for -/// [_i20.PoinHistoryPage] -class PoinHistoryRoute extends _i29.PageRouteInfo { - const PoinHistoryRoute({List<_i29.PageRouteInfo>? children}) +/// [_i24.PoinHistoryPage] +class PoinHistoryRoute extends _i33.PageRouteInfo { + const PoinHistoryRoute({List<_i33.PageRouteInfo>? children}) : super(PoinHistoryRoute.name, initialChildren: children); static const String name = 'PoinHistoryRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i20.PoinHistoryPage(); + return const _i24.PoinHistoryPage(); }, ); } /// generated route for -/// [_i21.PoinPage] -class PoinRoute extends _i29.PageRouteInfo { - const PoinRoute({List<_i29.PageRouteInfo>? children}) +/// [_i25.PoinPage] +class PoinRoute extends _i33.PageRouteInfo { + const PoinRoute({List<_i33.PageRouteInfo>? children}) : super(PoinRoute.name, initialChildren: children); static const String name = 'PoinRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i21.PoinPage(); + return const _i25.PoinPage(); }, ); } /// generated route for -/// [_i22.ProductRedeemPage] -class ProductRedeemRoute extends _i29.PageRouteInfo { +/// [_i26.ProductRedeemPage] +class ProductRedeemRoute extends _i33.PageRouteInfo { ProductRedeemRoute({ - _i30.Key? key, - required _i21.Product product, - required _i21.PointCard pointCard, - List<_i29.PageRouteInfo>? children, + _i34.Key? key, + required _i25.Product product, + required _i25.PointCard pointCard, + List<_i33.PageRouteInfo>? children, }) : super( ProductRedeemRoute.name, args: ProductRedeemRouteArgs( @@ -509,11 +560,11 @@ class ProductRedeemRoute extends _i29.PageRouteInfo { static const String name = 'ProductRedeemRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { final args = data.argsAs(); - return _i22.ProductRedeemPage( + return _i26.ProductRedeemPage( key: args.key, product: args.product, pointCard: args.pointCard, @@ -529,11 +580,11 @@ class ProductRedeemRouteArgs { required this.pointCard, }); - final _i30.Key? key; + final _i34.Key? key; - final _i21.Product product; + final _i25.Product product; - final _i21.PointCard pointCard; + final _i25.PointCard pointCard; @override String toString() { @@ -542,97 +593,97 @@ class ProductRedeemRouteArgs { } /// generated route for -/// [_i23.ProfilePage] -class ProfileRoute extends _i29.PageRouteInfo { - const ProfileRoute({List<_i29.PageRouteInfo>? children}) +/// [_i27.ProfilePage] +class ProfileRoute extends _i33.PageRouteInfo { + const ProfileRoute({List<_i33.PageRouteInfo>? children}) : super(ProfileRoute.name, initialChildren: children); static const String name = 'ProfileRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i23.ProfilePage(); + return const _i27.ProfilePage(); }, ); } /// generated route for -/// [_i24.RegisterPage] -class RegisterRoute extends _i29.PageRouteInfo { - const RegisterRoute({List<_i29.PageRouteInfo>? children}) +/// [_i28.RegisterPage] +class RegisterRoute extends _i33.PageRouteInfo { + const RegisterRoute({List<_i33.PageRouteInfo>? children}) : super(RegisterRoute.name, initialChildren: children); static const String name = 'RegisterRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i24.RegisterPage(); + return const _i28.RegisterPage(); }, ); } /// generated route for -/// [_i25.RewardPage] -class RewardRoute extends _i29.PageRouteInfo { - const RewardRoute({List<_i29.PageRouteInfo>? children}) +/// [_i29.RewardPage] +class RewardRoute extends _i33.PageRouteInfo { + const RewardRoute({List<_i33.PageRouteInfo>? children}) : super(RewardRoute.name, initialChildren: children); static const String name = 'RewardRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i25.RewardPage(); + return const _i29.RewardPage(); }, ); } /// generated route for -/// [_i26.SplashPage] -class SplashRoute extends _i29.PageRouteInfo { - const SplashRoute({List<_i29.PageRouteInfo>? children}) +/// [_i30.SplashPage] +class SplashRoute extends _i33.PageRouteInfo { + const SplashRoute({List<_i33.PageRouteInfo>? children}) : super(SplashRoute.name, initialChildren: children); static const String name = 'SplashRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i26.SplashPage(); + return const _i30.SplashPage(); }, ); } /// generated route for -/// [_i27.VoucherDetailPage] -class VoucherDetailRoute extends _i29.PageRouteInfo { - const VoucherDetailRoute({List<_i29.PageRouteInfo>? children}) +/// [_i31.VoucherDetailPage] +class VoucherDetailRoute extends _i33.PageRouteInfo { + const VoucherDetailRoute({List<_i33.PageRouteInfo>? children}) : super(VoucherDetailRoute.name, initialChildren: children); static const String name = 'VoucherDetailRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i27.VoucherDetailPage(); + return const _i31.VoucherDetailPage(); }, ); } /// generated route for -/// [_i28.VoucherPage] -class VoucherRoute extends _i29.PageRouteInfo { - const VoucherRoute({List<_i29.PageRouteInfo>? children}) +/// [_i32.VoucherPage] +class VoucherRoute extends _i33.PageRouteInfo { + const VoucherRoute({List<_i33.PageRouteInfo>? children}) : super(VoucherRoute.name, initialChildren: children); static const String name = 'VoucherRoute'; - static _i29.PageInfo page = _i29.PageInfo( + static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i28.VoucherPage(); + return const _i32.VoucherPage(); }, ); }