774 lines
26 KiB
Dart
Executable File
774 lines
26 KiB
Dart
Executable File
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<CaptainWalletController>(
|
|
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<Color>(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: <Widget>[
|
|
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<Color>(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<dynamic> 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<BankController>().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<PaymobPayout>(builder: (controller) {
|
|
return DropdownButton<String>(
|
|
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: <String>['etisalat', 'aman', 'orange', 'vodafone']
|
|
.map<DropdownMenuItem<String>>((String value) {
|
|
return DropdownMenuItem<String>(
|
|
value: value,
|
|
child: Text(value),
|
|
);
|
|
}).toList(),
|
|
);
|
|
});
|
|
}
|
|
}
|