import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:local_auth/local_auth.dart'; import 'dart:ui'; // Required for BackdropFilter // --- KEEPING ALL ORIGINAL IMPORTS AND CONTROLLERS --- import 'package:sefer_driver/constant/links.dart'; import 'package:sefer_driver/controller/functions/crud.dart'; import 'package:sefer_driver/controller/home/payment/paymob_payout.dart'; import 'package:sefer_driver/views/home/my_wallet/bank_account_egypt.dart'; import 'package:sefer_driver/views/home/my_wallet/payment_history_driver_page.dart'; import 'package:sefer_driver/views/widgets/error_snakbar.dart'; import 'package:sefer_driver/views/widgets/mydialoug.dart'; import 'package:sefer_driver/constant/box_name.dart'; import 'package:sefer_driver/constant/colors.dart'; import 'package:sefer_driver/constant/info.dart'; import 'package:sefer_driver/controller/home/payment/captain_wallet_controller.dart'; import 'package:sefer_driver/main.dart'; import 'package:sefer_driver/views/widgets/elevated_btn.dart'; import 'package:sefer_driver/views/widgets/my_textField.dart'; import '../../../controller/payment/driver_payment_controller.dart'; import 'card_wallet_widget.dart'; import 'points_captain.dart'; import 'transfer_budget_page.dart'; import 'weekly_payment_page.dart'; // --- END OF ORIGINAL IMPORTS --- // --- NEW LIGHT & DYNAMIC DESIGN PALETTE (TWITTER BLUE INSPIRED) --- const kLightBackgroundColor = Color(0xFFF5F8FA); // Off-white const kCardBackgroundColor = Color(0xFFFFFFFF); // Pure white for cards const kPrimaryBlue = Color(0xFF1DA1F2); // Twitter Blue const kSecondaryBlue = Color(0xFFE8F5FE); // Very light blue for accents const kPrimaryTextColor = Color(0xFF14171A); // Almost black const kSecondaryTextColor = Color(0xFF657786); // Gray for subtitles // Accent colors remain the same for status indicators const kRedAccent = Color(0xFFFF4D6D); const kYellowAccent = Color(0xFFFFD166); const kGreenAccent = Color(0xFF06D6A0); class WalletCaptain extends StatelessWidget { WalletCaptain({super.key}); // Controller remains unchanged as requested. final CaptainWalletController captainWalletController = Get.put(CaptainWalletController()); @override Widget build(BuildContext context) { // Logic to refresh data remains unchanged. captainWalletController.refreshCaptainWallet(); // The main scaffold is replaced with a custom-themed one. return Scaffold( backgroundColor: kLightBackgroundColor, appBar: AppBar( title: Text( 'Driver Wallet'.tr, style: const TextStyle( color: kPrimaryTextColor, fontWeight: FontWeight.bold, letterSpacing: 1.2, ), ), backgroundColor: kCardBackgroundColor, elevation: 0.5, centerTitle: true, leading: IconButton( icon: const Icon(Icons.arrow_back_ios, color: kPrimaryBlue), onPressed: () => Get.back(), ), actions: [ IconButton( onPressed: () async { captainWalletController.refreshCaptainWallet(); }, icon: const Icon(Icons.refresh, color: kPrimaryBlue), ), ], ), body: GetBuilder( builder: (controller) { // AnimatedSwitcher provides a smooth transition between loading and content. return AnimatedSwitcher( duration: const Duration(milliseconds: 500), child: controller.isLoading ? _buildLoadingState() : _buildContentState(context, controller), ); }, ), ); } /// Builds the loading state UI with a custom futuristic indicator. Widget _buildLoadingState() { return const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircularProgressIndicator( valueColor: AlwaysStoppedAnimation(kPrimaryBlue), ), SizedBox(height: 20), Text( "Fetching Wallet Data...", style: TextStyle(color: kSecondaryTextColor, fontSize: 16), ), ], ), ); } /// Builds the main content when data is loaded. Widget _buildContentState( BuildContext context, CaptainWalletController controller) { return ListView( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20), children: [ // Each section is separated for clarity and wrapped in an animation widget. _AnimatedFadeIn(delay: 100, child: _buildPointsHeader(controller)), const SizedBox(height: 20), if (double.parse(controller.totalPoints.toString()) < -300) _AnimatedFadeIn( delay: 200, child: _DynamicButton( title: 'Charge your Account'.tr, onPressed: () { // Add your charge account logic here }, gradient: const LinearGradient( colors: [kRedAccent, Color(0xFFF72585)], ), ), ), _AnimatedFadeIn( delay: 300, child: const CardSeferWalletDriver()), // Kept as is. const SizedBox(height: 20), _AnimatedFadeIn(delay: 400, child: _buildBudgetSection(controller)), const SizedBox(height: 30), _AnimatedFadeIn( delay: 500, child: _buildSectionTitle("Daily Promos".tr)), _AnimatedFadeIn(delay: 600, child: _buildPromoSection(controller)), const SizedBox(height: 30), _AnimatedFadeIn(delay: 700, child: _buildPurchaseInstructions()), const SizedBox(height: 16), _AnimatedFadeIn(delay: 800, child: _buildPointsOptions()), const SizedBox(height: 30), _AnimatedFadeIn(delay: 900, child: _buildActionButtons()), ], ); } /// A revolutionary header for displaying total points with dynamic background. Widget _buildPointsHeader(CaptainWalletController controller) { // Logic for color determination remains the same. final double points = double.parse(controller.totalPoints.toString()); final Color indicatorColor = points < -300 ? kRedAccent : points < 0 ? kYellowAccent : kGreenAccent; return GestureDetector( onTap: () { // This functionality is preserved. Get.dialog( CupertinoAlertDialog( title: Text('Info'.tr), content: Text( 'The 300 points equal 300 L.E for you \nSo go and gain your money' .tr, ), actions: [ CupertinoDialogAction( child: Text("OK".tr), onPressed: () => Get.back(), ), ], ), ); }, child: Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( color: kCardBackgroundColor, borderRadius: BorderRadius.circular(20), border: Border.all(color: Colors.grey.shade200, width: 1), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.1), spreadRadius: 5, blurRadius: 10, ) ], ), child: Column( children: [ Text( 'Total Points'.tr, style: const TextStyle( color: kSecondaryTextColor, fontSize: 18, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( controller.totalPoints.toString(), style: TextStyle( color: kPrimaryTextColor, fontSize: 48, fontWeight: FontWeight.bold, ), ), const SizedBox(width: 10), Icon(Icons.diamond_outlined, color: indicatorColor, size: 40), ], ), ], ), ), ); } /// A modern card container for the budget details. Widget _buildBudgetSection(CaptainWalletController controller) { return Card( elevation: 4, shadowColor: Colors.grey.withOpacity(0.2), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), color: kCardBackgroundColor, child: Padding( padding: const EdgeInsets.all(20.0), child: Column( children: [ _buildBudgetRow( icon: Icons.account_balance_wallet_outlined, title: 'Total Budget from trips is'.tr, amount: controller.totalAmount, onTap: () { // Original onTap logic is preserved. Get.snackbar( '${'Total Amount:'.tr} ${controller.totalAmount} ${'L.E'.tr}', 'This amount for all trip I get from Passengers'.tr, backgroundColor: kYellowAccent.withOpacity(0.8), snackPosition: SnackPosition.BOTTOM); }, ), const Divider(color: kLightBackgroundColor, height: 30), _buildBudgetRow( icon: Icons.credit_card, title: 'Total Budget from trips by\nCredit card is '.tr, amount: controller.totalAmountVisa, onTap: () { // Original onTap logic is preserved. Get.snackbar( '${'Total Amount:'.tr} ${controller.totalAmountVisa} ${'L.E'.tr}', 'This amount for all trip I get from Passengers and Collected For me in' .tr + ' ${AppInformation.appName} Wallet'.tr, backgroundColor: kRedAccent.withOpacity(0.8), snackPosition: SnackPosition.BOTTOM); }, ), const SizedBox(height: 20), _DynamicButton( title: 'You can buy points from your budget'.tr, onPressed: () => _showBuyFromBudgetDialog(controller), ), const SizedBox(height: 12), _DynamicButton( title: 'Transfer budget'.tr, onPressed: () => _handleTransferBudget(controller), gradient: LinearGradient( colors: [ kSecondaryTextColor, kSecondaryTextColor.withOpacity(0.7) ], ), ), ], ), ), ); } /// A redesigned row for displaying budget information. Widget _buildBudgetRow( {required IconData icon, required String title, required String amount, required VoidCallback onTap}) { return Row( children: [ Icon(icon, color: kPrimaryBlue, size: 28), const SizedBox(width: 15), Expanded( child: Text( title, style: const TextStyle( color: kSecondaryTextColor, fontSize: 16, fontWeight: FontWeight.w500, ), ), ), GestureDetector( onTap: onTap, child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: kSecondaryBlue, borderRadius: BorderRadius.circular(12), ), child: Text( '$amount ${'L.E'.tr}', style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: kPrimaryTextColor), ), ), ), ], ); } /// A section to display daily promo progress. Widget _buildPromoSection(CaptainWalletController controller) { return Column( children: [ _buildPromoCard( icon: Icons.wb_sunny_outlined, title: 'Morning Promo'.tr, timePromo: 'Morning Promo', count: controller.walletDate['message'][0]['morning_count'], maxCount: 5, description: "this is count of your all trips in the morning promo today from 7:00am-10:00am" .tr, controller: controller, ), const SizedBox(height: 16), _buildPromoCard( icon: Icons.brightness_4_outlined, title: 'Afternoon Promo'.tr, timePromo: 'Afternoon Promo', count: controller.walletDate['message'][0]['afternoon_count'], maxCount: 5, description: "this is count of your all trips in the Afternoon promo today from 3:00pm-6:00 pm" .tr, controller: controller, ), ], ); } /// A redesigned, more visual promo card. Widget _buildPromoCard( {required IconData icon, required String title, required String timePromo, required int count, required int maxCount, required String description, required CaptainWalletController controller}) { double progress = count / maxCount; return GestureDetector( onTap: () { // Original onTap logic is preserved. MyDialog().getDialog(title, description, () async { if (count == 5) { controller.addDriverWalletFromPromo(timePromo, 50); } Get.back(); }); }, child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: kCardBackgroundColor, borderRadius: BorderRadius.circular(15), border: Border.all(color: Colors.grey.shade200), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Icon(icon, color: kPrimaryBlue, size: 24), const SizedBox(width: 10), Text(title, style: const TextStyle( color: kPrimaryTextColor, fontSize: 18, fontWeight: FontWeight.bold)), ], ), Text('$count / $maxCount', style: const TextStyle( color: kSecondaryTextColor, fontSize: 16, fontWeight: FontWeight.w500)), ], ), const SizedBox(height: 12), ClipRRect( borderRadius: BorderRadius.circular(10), child: LinearProgressIndicator( value: progress, minHeight: 10, backgroundColor: kSecondaryBlue, valueColor: const AlwaysStoppedAnimation(kPrimaryBlue), ), ), ], ), ), ); } /// Re-implementation of original purchase instructions with new styling. Widget _buildPurchaseInstructions() { return Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Text( "You can purchase a budget to enable online access through the options listed below." .tr, textAlign: TextAlign.center, style: const TextStyle(color: kSecondaryTextColor, fontSize: 16), ), ); } /// RESTORED: This widget uses the original PointsCaptain widget to ensure payment logic is identical. Widget _buildPointsOptions() { return Container( height: Get.height * 0.19, child: ListView( scrollDirection: Axis.horizontal, children: [ PointsCaptain( kolor: AppColor.greyColor, pricePoint: box.read(BoxName.countryCode) == 'Jordan' ? 5 : 80, countPoint: box.read(BoxName.countryCode) == 'Jordan' ? '3000' : '80', ), PointsCaptain( kolor: AppColor.bronze, pricePoint: box.read(BoxName.countryCode) == 'Jordan' ? 10 : 200, countPoint: box.read(BoxName.countryCode) == 'Jordan' ? '1040' : '210', ), PointsCaptain( kolor: AppColor.goldenBronze, pricePoint: box.read(BoxName.countryCode) == 'Jordan' ? 22 : 400, countPoint: box.read(BoxName.countryCode) == 'Jordan' ? '23000' : '450', ), PointsCaptain( kolor: AppColor.gold, pricePoint: box.read(BoxName.countryCode) == 'Jordan' ? 50 : 1000, countPoint: box.read(BoxName.countryCode) == 'Jordan' ? '55000' : '1100', ), ], ), ); } /// A row of action buttons for navigation. Widget _buildActionButtons() { return Row( children: [ Expanded( child: _DynamicButton( title: 'Payment History'.tr, onPressed: () async { // Original logic is preserved. await Get.put(DriverWalletHistoryController()) .getArchivePayment(); Get.to(() => const PaymentHistoryDriverPage(), transition: Transition.size); }, gradient: LinearGradient( colors: [ kSecondaryTextColor, kSecondaryTextColor.withOpacity(0.7) ], ), ), ), const SizedBox(width: 16), Expanded( child: _DynamicButton( title: 'Weekly Budget'.tr, onPressed: () async { // Original logic is preserved. await Get.put(DriverWalletHistoryController()) .getWeekllyArchivePayment(); Get.to(() => const WeeklyPaymentPage(), transition: Transition.size); }, gradient: LinearGradient( colors: [ kSecondaryTextColor, kSecondaryTextColor.withOpacity(0.7) ], ), ), ), ], ); } /// A helper for creating section titles. Widget _buildSectionTitle(String title) { return Padding( padding: const EdgeInsets.only(bottom: 16.0), child: Text( title, style: const TextStyle( color: kPrimaryTextColor, fontSize: 22, fontWeight: FontWeight.bold), ), ); } /// Handles the complex logic for buying points from budget, including authentication. void _showBuyFromBudgetDialog(CaptainWalletController controller) { Get.defaultDialog( title: 'Pay from my budget'.tr, titleStyle: const TextStyle(color: kPrimaryTextColor), backgroundColor: kCardBackgroundColor, content: Form( key: controller.formKey, child: MyTextForm( // Assuming MyTextForm can be styled or is generic enough controller: controller.amountFromBudgetController, label: '${'You have in account'.tr} ${controller.totalAmountVisa}', hint: '${'You have in account'.tr} ${controller.totalAmountVisa}', type: TextInputType.number, ), ), confirm: _DynamicButton( title: 'Confirm & Pay'.tr, onPressed: () async { // All original logic, including biometric auth, is preserved. bool isAvailable = await LocalAuthentication().isDeviceSupported(); if (isAvailable) { bool didAuthenticate = await LocalAuthentication().authenticate( localizedReason: 'Use Touch ID or Face ID to confirm payment', options: const AuthenticationOptions( biometricOnly: true, sensitiveTransaction: true)); if (didAuthenticate) { if (double.parse(controller.amountFromBudgetController.text) < double.parse(controller.totalAmountVisa)) { await controller.payFromBudget(); } else { Get.back(); mySnackeBarError('Your Budget less than needed'.tr); } } } }, ), cancel: TextButton( onPressed: () => Get.back(), child: Text('Cancel'.tr, style: const TextStyle(color: kSecondaryTextColor)), ), ); } /// Handles the logic for transferring budget, including authentication. void _handleTransferBudget(CaptainWalletController controller) async { bool isAvailable = await LocalAuthentication().isDeviceSupported(); if (isAvailable) { bool didAuthenticate = await LocalAuthentication().authenticate( localizedReason: 'Use Touch ID or Face ID to confirm transfer', options: const AuthenticationOptions( biometricOnly: true, sensitiveTransaction: true)); if (didAuthenticate) { if (double.parse(controller.totalAmountVisa) > 15) { Get.to(() => const TransferBudgetPage()); } else { mySnackeBarError( "You don't have enough money in your Tripz wallet".tr); } } } } } // --- NEW DYNAMIC AND REUSABLE WIDGETS --- /// A custom button with gradient and dynamic feel. class _DynamicButton extends StatelessWidget { final String title; final VoidCallback onPressed; final Gradient? gradient; const _DynamicButton({ required this.title, required this.onPressed, this.gradient, }); @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), gradient: gradient ?? const LinearGradient( colors: [kPrimaryBlue, Color(0xFF1A91DA)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), boxShadow: [ BoxShadow( color: (gradient?.colors.first ?? kPrimaryBlue).withOpacity(0.3), blurRadius: 10, offset: const Offset(0, 5), ), ], ), child: Material( color: Colors.transparent, child: InkWell( onTap: onPressed, borderRadius: BorderRadius.circular(15), child: Padding( padding: const EdgeInsets.symmetric(vertical: 16), child: Center( child: Text( title, style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16, ), ), ), ), ), ), ); } } /// A simple animation widget to fade in content dynamically. class _AnimatedFadeIn extends StatefulWidget { final int delay; final Widget child; const _AnimatedFadeIn({required this.delay, required this.child}); @override State<_AnimatedFadeIn> createState() => _AnimatedFadeInState(); } class _AnimatedFadeInState extends State<_AnimatedFadeIn> { bool _isVisible = false; @override void initState() { super.initState(); Future.delayed(Duration(milliseconds: widget.delay), () { if (mounted) { setState(() => _isVisible = true); } }); } @override Widget build(BuildContext context) { return AnimatedOpacity( duration: const Duration(milliseconds: 500), opacity: _isVisible ? 1.0 : 0.0, child: AnimatedContainer( duration: const Duration(milliseconds: 500), transform: Matrix4.translationValues(0, _isVisible ? 0 : 20, 0), child: widget.child, ), ); } } // --- THE FOLLOWING ORIGINAL CODE IS KEPT FOR CONTEXT AND UNCHANGED AS REQUESTED --- // I did not include the original helper functions like _buildBuyPointsButton because their // logic has been integrated into the new, redesigned widgets above (e.g., inside _buildBudgetSection). // The functions below are external to the main widget and are kept as is. Future addBankCodeEgypt( CaptainWalletController captainWalletController) { return Get.defaultDialog( title: "Insert Account Bank".tr, content: Form( key: captainWalletController.formKeyAccount, child: Column( children: [ Text("Insert Card Bank Details to Receive Your Visa Money Weekly" .tr), MyTextForm( controller: captainWalletController.cardBank, label: "Insert card number".tr, hint: '4123 4567 8910 1235', type: TextInputType.number), const SizedBox( height: 10, ), BankDropdown() ], )), confirm: MyElevatedButton( title: 'Ok'.tr, onPressed: () async { if (captainWalletController.formKeyAccount.currentState! .validate()) { Get.back(); var res = await CRUD().post(link: AppLink.updateAccountBank, payload: { "bankCode": Get.find().selectedBank.toString(), "accountBank": captainWalletController.cardBank.text.toString(), "id": box.read(BoxName.driverID).toString() }); print('res: ${res}'); if (res != 'failure') { mySnackbarSuccess('bank account added succesfly'.tr); } } })); } class MyDropDown1 extends StatelessWidget { @override Widget build(BuildContext context) { Get.put(PaymobPayout()); return GetBuilder(builder: (controller) { return DropdownButton( value: controller.dropdownValue, icon: const Icon(Icons.arrow_drop_down), elevation: 16, style: const TextStyle(color: Colors.deepPurple), underline: Container( height: 2, color: Colors.deepPurpleAccent, ), onChanged: (String? newValue) { controller.dropdownValue = newValue!; controller.update(); }, items: ['etisalat', 'aman', 'orange', 'vodafone'] .map>((String value) { return DropdownMenuItem( value: value, child: Text(value), ); }).toList(), ); }); } }