Initial commit for driver_tripz
This commit is contained in:
@@ -29,249 +29,6 @@ import 'package:flutter/cupertino.dart';
|
||||
|
||||
import 'device_compatibility_page.dart';
|
||||
|
||||
// class CupertinoDrawerCaptain extends StatelessWidget {
|
||||
// final ImageController imageController = Get.put(ImageController());
|
||||
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// return CupertinoPageScaffold(
|
||||
// navigationBar: CupertinoNavigationBar(
|
||||
// middle: Text('Menu'.tr),
|
||||
// ),
|
||||
// child: SafeArea(
|
||||
// child: CustomScrollView(
|
||||
// slivers: [
|
||||
// const SliverToBoxAdapter(child: const UserAccountHeader()),
|
||||
// SliverList(
|
||||
// delegate: SliverChildListDelegate([
|
||||
// _buildDivider(),
|
||||
// _buildDrawerItem(
|
||||
// icon: CupertinoIcons.money_dollar,
|
||||
// text: 'Wallet'.tr,
|
||||
// onTap: () => Get.to(() => WalletCaptain()),
|
||||
// ),
|
||||
// _buildDivider(),
|
||||
// _buildDrawerItem(
|
||||
// icon: CupertinoIcons.person,
|
||||
// text: 'Profile'.tr,
|
||||
// onTap: () => Get.to(() => ProfileCaptain()),
|
||||
// ),
|
||||
// _buildDivider(),
|
||||
// _buildDrawerItem(
|
||||
// icon: CupertinoIcons.clock,
|
||||
// text: 'History of Trip'.tr,
|
||||
// onTap: () => Get.to(() => const HistoryCaptain()),
|
||||
// ),
|
||||
// _buildDivider(),
|
||||
// _buildDrawerItem(
|
||||
// icon: CupertinoIcons.car_detailed,
|
||||
// text: 'Available for rides'.tr,
|
||||
// onTap: () => Get.to(() => const AvailableRidesPage()),
|
||||
// ),
|
||||
// _buildDivider(),
|
||||
// _buildDrawerItem(
|
||||
// icon: CupertinoIcons.bell,
|
||||
// text: 'Notifications'.tr,
|
||||
// onTap: () => Get.to(() => const NotificationCaptain()),
|
||||
// ),
|
||||
// _buildDivider(),
|
||||
// _buildDrawerItem(
|
||||
// icon: CupertinoIcons.question_circle,
|
||||
// text: 'Helping Center'.tr,
|
||||
// onTap: () => Get.to(() => HelpCaptain()),
|
||||
// ),
|
||||
// _buildDivider(),
|
||||
// _buildDrawerItem(
|
||||
// icon: CupertinoIcons.share,
|
||||
// text: 'Share App'.tr,
|
||||
// onTap: () => Get.to(() => InviteScreen()),
|
||||
// ),
|
||||
// _buildDivider(),
|
||||
// _buildDrawerItem(
|
||||
// icon: CupertinoIcons.wrench,
|
||||
// text: "Maintenance Center".tr,
|
||||
// onTap: () => Get.to(() => MaintainCenterPage()),
|
||||
// ),
|
||||
// _buildDivider(),
|
||||
// _buildDrawerItem(
|
||||
// icon:
|
||||
// CupertinoIcons.heart, // Updated icon to represent health
|
||||
// text: "Health Insurance".tr, // Updated English text
|
||||
// onTap: () => Get.to(() => AssuranceHealthPage()),
|
||||
// ),
|
||||
// _buildDivider(),
|
||||
// _buildDrawerItem(
|
||||
// icon: CupertinoIcons.mail,
|
||||
// text: "Contact Us".tr,
|
||||
// onTap: () => Get.to(() => ContactUsPage()),
|
||||
// ),
|
||||
// _buildDivider(),
|
||||
// _buildDrawerItem(
|
||||
// icon:
|
||||
// Icons.play_circle_filled, // Icon representing video play
|
||||
// text: 'Videos Tutorials'.tr,
|
||||
// onTap: () => Get.to(() => VideoListPage()),
|
||||
// ),
|
||||
// _buildDivider(),
|
||||
// _buildDrawerItem(
|
||||
// icon: Icons.star, // Another option with a filled star icon
|
||||
// text: "Rate Our App".tr,
|
||||
// onTap: () => Get.to(() => RatingScreen()),
|
||||
// ),
|
||||
// _buildDivider(),
|
||||
// _buildDrawerItem(
|
||||
// icon: CupertinoIcons.settings,
|
||||
// text: 'Settings'.tr,
|
||||
// onTap: () => Get.to(() => const SettingsCaptain()),
|
||||
// ),
|
||||
// _buildDivider(),
|
||||
// _buildDrawerItem(
|
||||
// icon: CupertinoIcons.square_arrow_right,
|
||||
// text: 'Sign Out'.tr,
|
||||
// onTap: () => Get.to(() => const LogoutCaptain()),
|
||||
// ),
|
||||
// _buildDivider(),
|
||||
// ]),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
||||
// Widget _buildDivider() {
|
||||
// return const Divider(
|
||||
// thickness: 1,
|
||||
// height: 1,
|
||||
// color: CupertinoColors.systemGrey4,
|
||||
// );
|
||||
// }
|
||||
|
||||
// Widget _buildDrawerItem({
|
||||
// required IconData icon,
|
||||
// required String text,
|
||||
// required VoidCallback onTap,
|
||||
// }) {
|
||||
// return CupertinoButton(
|
||||
// onPressed: onTap,
|
||||
// child: Row(
|
||||
// children: [
|
||||
// Icon(icon, color: CupertinoColors.activeBlue),
|
||||
// const SizedBox(width: 10),
|
||||
// Text(text, style: const TextStyle(color: CupertinoColors.label)),
|
||||
// const Spacer(),
|
||||
// const Icon(CupertinoIcons.right_chevron,
|
||||
// color: CupertinoColors.systemGrey),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
// class UserAccountHeader extends StatelessWidget {
|
||||
// const UserAccountHeader({super.key});
|
||||
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// return Container(
|
||||
// padding: const EdgeInsets.all(16),
|
||||
// decoration: const BoxDecoration(
|
||||
// gradient: LinearGradient(
|
||||
// colors: [AppColor.blueColor, AppColor.twitterColor],
|
||||
// begin: Alignment.topLeft,
|
||||
// end: Alignment.bottomRight,
|
||||
// ),
|
||||
// ),
|
||||
// child: Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// GetBuilder<ImageController>(
|
||||
// builder: (imageController) {
|
||||
// return Stack(
|
||||
// children: [
|
||||
// imageController.isloading
|
||||
// ? const CupertinoActivityIndicator()
|
||||
// : Container(
|
||||
// width: 100,
|
||||
// height: 100,
|
||||
// decoration: BoxDecoration(
|
||||
// shape: BoxShape.circle,
|
||||
// image: DecorationImage(
|
||||
// fit: BoxFit.cover,
|
||||
// image: NetworkImage(
|
||||
// '${AppLink.seferCairoServer}/portrate_captain_image/${box.read(BoxName.driverID)}.jpg',
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// Positioned(
|
||||
// right: 0,
|
||||
// top: 0,
|
||||
// child: CupertinoButton(
|
||||
// onPressed: () {
|
||||
// imageController.choosImagePicture(
|
||||
// AppLink.uploadImage1, 'portrait');
|
||||
// },
|
||||
// child: const Icon(CupertinoIcons.pencil_circle_fill,
|
||||
// color: CupertinoColors.white),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
// const SizedBox(height: 10),
|
||||
// Text(
|
||||
// '${box.read(BoxName.nameDriver).toString().split(' ')[0]} ${box.read(BoxName.nameDriver).toString().split(' ')[1]}',
|
||||
// style: const TextStyle(
|
||||
// color: CupertinoColors.white,
|
||||
// fontSize: 18,
|
||||
// fontWeight: FontWeight.bold),
|
||||
// ),
|
||||
// const SizedBox(height: 5),
|
||||
// Text(
|
||||
// box.read(BoxName.emailDriver),
|
||||
// style: const TextStyle(color: CupertinoColors.white, fontSize: 14),
|
||||
// ),
|
||||
// const SizedBox(height: 10),
|
||||
// Row(
|
||||
// children: [
|
||||
// Text(
|
||||
// Get.find<HomeCaptainController>().rating.toString(),
|
||||
// style: const TextStyle(
|
||||
// color: CupertinoColors.systemYellow, fontSize: 16),
|
||||
// ),
|
||||
// const SizedBox(width: 5),
|
||||
// // You might want to replace this with a Cupertino-style rating widget
|
||||
// // For now, we'll use text to represent stars
|
||||
// // const Text('★★★★★',
|
||||
// // style: TextStyle(color: CupertinoColors.systemYellow)),
|
||||
|
||||
// Container(
|
||||
// padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 1),
|
||||
// color: AppColor.greenColor,
|
||||
// child: RatingBar.builder(
|
||||
// initialRating: double.parse(
|
||||
// Get.find<HomeCaptainController>().rating.toString()),
|
||||
// minRating: 1,
|
||||
// direction: Axis.horizontal,
|
||||
// itemCount: 5,
|
||||
// itemSize: 20,
|
||||
// itemPadding: const EdgeInsets.symmetric(horizontal: 2),
|
||||
// itemBuilder: (context, _) => const Icon(
|
||||
// Icons.star,
|
||||
// color: Colors.amber,
|
||||
// ),
|
||||
// onRatingUpdate: (rating) {},
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
class CupertinoDrawerCaptain extends StatelessWidget {
|
||||
final ImageController imageController = Get.put(ImageController());
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,54 +1,278 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:sefer_driver/constant/colors.dart';
|
||||
import 'package:sefer_driver/constant/style.dart';
|
||||
import 'package:sefer_driver/views/widgets/my_scafold.dart';
|
||||
import 'package:sefer_driver/views/widgets/mycircular.dart';
|
||||
|
||||
import '../../../controller/payment/driver_payment_controller.dart';
|
||||
|
||||
// --- DESIGN PALETTE IS NOW UPDATED TO USE AppColor ---
|
||||
const kLightBackgroundColor = Color(0xFFF5F8FA);
|
||||
const kCardBackgroundColor = AppColor.secondaryColor; // Using AppColor
|
||||
const kPrimaryBlue = AppColor.primaryColor; // Using AppColor
|
||||
const kPrimaryTextColor = Color(0xFF14171A);
|
||||
const kSecondaryTextColor = Color(0xFF657786);
|
||||
const kPositiveAmountColor = AppColor.greenColor; // Using AppColor
|
||||
const kNegativeAmountColor = AppColor.redColor; // Using AppColor
|
||||
|
||||
class PaymentHistoryDriverPage extends StatelessWidget {
|
||||
const PaymentHistoryDriverPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Controller initialization remains the same.
|
||||
Get.put(DriverWalletHistoryController());
|
||||
return MyScafolld(
|
||||
title: 'Payment History'.tr,
|
||||
body: [
|
||||
GetBuilder<DriverWalletHistoryController>(
|
||||
builder: (controller) => controller.isLoading
|
||||
? const MyCircularProgressIndicator()
|
||||
: ListView.builder(
|
||||
itemCount: controller.archive.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
var list = controller.archive[index];
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: double.parse(list['amount']) < 0
|
||||
? AppColor.redColor.withOpacity(.4)
|
||||
: AppColor.greenColor.withOpacity(.4)),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
list['amount'],
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
list['created_at'],
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: kLightBackgroundColor,
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
'Payment History'.tr,
|
||||
style: const TextStyle(
|
||||
color: kPrimaryTextColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
backgroundColor: kCardBackgroundColor,
|
||||
elevation: 0.5,
|
||||
centerTitle: true,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back_ios, color: kPrimaryBlue),
|
||||
onPressed: () => Get.back(),
|
||||
),
|
||||
),
|
||||
body: GetBuilder<DriverWalletHistoryController>(
|
||||
builder: (controller) {
|
||||
// Smooth transition between loading and content states.
|
||||
return AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
child: controller.isLoading
|
||||
? _buildLoadingState()
|
||||
: _buildContentState(controller),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Builds the loading state UI.
|
||||
Widget _buildLoadingState() {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation<Color>(kPrimaryBlue),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Text(
|
||||
"Loading History...".tr,
|
||||
style: TextStyle(color: kSecondaryTextColor, fontSize: 16),
|
||||
),
|
||||
],
|
||||
isleading: true);
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Builds the main content when data is available.
|
||||
Widget _buildContentState(DriverWalletHistoryController controller) {
|
||||
if (controller.archive.isEmpty) {
|
||||
return _buildEmptyState();
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
itemCount: controller.archive.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
var transaction = controller.archive[index];
|
||||
// Animated entry for each card
|
||||
return _AnimatedListItem(
|
||||
index: index,
|
||||
child: _HistoryCard(transaction: transaction),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// A user-friendly message for when there are no transactions.
|
||||
Widget _buildEmptyState() {
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.history_toggle_off,
|
||||
size: 80,
|
||||
color: Colors.grey.shade300,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
'No History Found'.tr,
|
||||
style: const TextStyle(
|
||||
color: kPrimaryTextColor,
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Your entire transaction history will be displayed here.'.tr,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
color: kSecondaryTextColor,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A custom widget for a single history transaction card.
|
||||
class _HistoryCard extends StatelessWidget {
|
||||
final Map<String, dynamic> transaction;
|
||||
|
||||
const _HistoryCard({required this.transaction});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Determine if the amount is positive or negative
|
||||
final double amount =
|
||||
double.tryParse(transaction['amount'] ?? '0.0') ?? 0.0;
|
||||
final bool isPositive = amount >= 0;
|
||||
|
||||
// Safely parse and format the date
|
||||
String formattedDate = 'No Date';
|
||||
try {
|
||||
final date = DateTime.parse(transaction['created_at']);
|
||||
formattedDate = DateFormat('MMM d, yyyy hh:mm a').format(date);
|
||||
} catch (e) {
|
||||
// Keep the original string if parsing fails
|
||||
formattedDate = transaction['created_at'] ?? 'Invalid Date';
|
||||
}
|
||||
|
||||
final Color amountColor =
|
||||
isPositive ? kPositiveAmountColor : kNegativeAmountColor;
|
||||
final IconData amountIcon =
|
||||
isPositive ? Icons.arrow_upward : Icons.arrow_downward;
|
||||
final String title = isPositive ? 'Credit'.tr : 'Debit'.tr;
|
||||
|
||||
return Card(
|
||||
margin: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
elevation: 2,
|
||||
shadowColor: Colors.grey.withOpacity(0.1),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Row(
|
||||
children: [
|
||||
// Icon
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: amountColor.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Icon(amountIcon, color: amountColor, size: 28),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
// Title and Date
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
color: kPrimaryTextColor,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
formattedDate,
|
||||
style: const TextStyle(
|
||||
color: kSecondaryTextColor,
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Amount
|
||||
Text(
|
||||
'${isPositive ? '+' : ''}${transaction['amount']} ${'L.E'.tr}',
|
||||
style: TextStyle(
|
||||
color: amountColor,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A simple animation widget to fade in list items.
|
||||
class _AnimatedListItem extends StatefulWidget {
|
||||
final int index;
|
||||
final Widget child;
|
||||
|
||||
const _AnimatedListItem({required this.index, required this.child});
|
||||
|
||||
@override
|
||||
State<_AnimatedListItem> createState() => _AnimatedListItemState();
|
||||
}
|
||||
|
||||
class _AnimatedListItemState extends State<_AnimatedListItem>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
late Animation<double> _animation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 400),
|
||||
);
|
||||
_animation = Tween<double>(begin: 0.0, end: 1.0).animate(
|
||||
CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Curves.easeOut,
|
||||
),
|
||||
);
|
||||
// Stagger the animation based on the item index
|
||||
Future.delayed(Duration(milliseconds: widget.index * 75), () {
|
||||
if (mounted) {
|
||||
_controller.forward();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FadeTransition(
|
||||
opacity: _animation,
|
||||
child: SlideTransition(
|
||||
position: Tween<Offset>(
|
||||
begin: const Offset(0, 0.2),
|
||||
end: Offset.zero,
|
||||
).animate(_controller),
|
||||
child: widget.child,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,141 +1,297 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sefer_driver/constant/colors.dart';
|
||||
import 'package:sefer_driver/constant/style.dart';
|
||||
import 'package:sefer_driver/views/widgets/my_scafold.dart';
|
||||
import 'package:sefer_driver/views/widgets/mycircular.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:sefer_driver/constant/colors.dart';
|
||||
import 'package:sefer_driver/controller/payment/driver_payment_controller.dart';
|
||||
|
||||
import '../../../controller/payment/driver_payment_controller.dart';
|
||||
// --- 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
|
||||
const kGreenAccent = Color(0xFF17BF63); // Green for income
|
||||
|
||||
class WeeklyPaymentPage extends StatelessWidget {
|
||||
const WeeklyPaymentPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Controller initialization remains the same.
|
||||
Get.put(DriverWalletHistoryController());
|
||||
return MyScafolld(
|
||||
title: 'Payment History'.tr,
|
||||
body: [
|
||||
GetBuilder<DriverWalletHistoryController>(
|
||||
builder: (controller) => controller.isLoading
|
||||
? const MyCircularProgressIndicator()
|
||||
: Column(
|
||||
children: [
|
||||
Container(
|
||||
width: Get.width * .8,
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
controller.weeklyList.isEmpty
|
||||
? '0'
|
||||
: controller.weeklyList[0]
|
||||
['totalAmount']
|
||||
.toString(),
|
||||
style: AppStyle.number,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
' Total weekly is '.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10, vertical: 5),
|
||||
child: SizedBox(
|
||||
height: Get.height * .75,
|
||||
child: controller.weeklyList.isNotEmpty
|
||||
? ListView.builder(
|
||||
itemCount: controller.weeklyList.length,
|
||||
itemBuilder:
|
||||
(BuildContext context, int index) {
|
||||
var list = controller.weeklyList[index];
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(2.0),
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Column(
|
||||
children: [
|
||||
Card(
|
||||
elevation: 2,
|
||||
color: list['paymentMethod'] ==
|
||||
'visa'
|
||||
? AppColor.blueColor
|
||||
: AppColor.secondaryColor,
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
list['paymentMethod'] ==
|
||||
'Remainder'
|
||||
? 'Remainder'.tr
|
||||
: list['paymentMethod'] ==
|
||||
'fromBudget'
|
||||
? 'fromBudget'.tr
|
||||
: list[
|
||||
'paymentMethod'],
|
||||
style: AppStyle.title,
|
||||
),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Card(
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.all(
|
||||
8.0),
|
||||
child: Text(
|
||||
list['amount'],
|
||||
style: AppStyle.number,
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
DateFormat(
|
||||
'yyyy-MM-dd hh:mm a')
|
||||
.format(DateTime.parse(
|
||||
list[
|
||||
'dateUpdated'])),
|
||||
style: AppStyle.number,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
: const SizedBox(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: AppColor.secondaryColor,
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
'Weekly Payments'.tr,
|
||||
style: const TextStyle(
|
||||
color: AppColor.blueColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
backgroundColor: kCardBackgroundColor,
|
||||
elevation: 0.5,
|
||||
centerTitle: true,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back_ios, color: kPrimaryBlue),
|
||||
onPressed: () => Get.back(),
|
||||
),
|
||||
),
|
||||
body: GetBuilder<DriverWalletHistoryController>(
|
||||
builder: (controller) {
|
||||
// Smooth transition between loading and content states.
|
||||
return AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
child: controller.isLoading
|
||||
? _buildLoadingState()
|
||||
: _buildContentState(controller),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Builds the loading state UI.
|
||||
Widget _buildLoadingState() {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation<Color>(kPrimaryBlue),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Text(
|
||||
"Fetching Weekly Data...".tr,
|
||||
style: TextStyle(color: kSecondaryTextColor, fontSize: 16),
|
||||
),
|
||||
],
|
||||
isleading: true);
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Builds the main content when data is available.
|
||||
Widget _buildContentState(DriverWalletHistoryController controller) {
|
||||
if (controller.weeklyList.isEmpty) {
|
||||
return _buildEmptyState();
|
||||
}
|
||||
|
||||
return ListView(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
children: [
|
||||
_buildTotalSummaryCard(controller),
|
||||
const SizedBox(height: 24),
|
||||
_buildSectionTitle('Transaction Details'.tr),
|
||||
const SizedBox(height: 8),
|
||||
_buildTransactionList(controller),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// A prominent card to display the total weekly amount.
|
||||
Widget _buildTotalSummaryCard(DriverWalletHistoryController controller) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(24),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [kPrimaryBlue, kPrimaryBlue.withOpacity(0.8)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: kPrimaryBlue.withOpacity(0.3),
|
||||
blurRadius: 12,
|
||||
offset: const Offset(0, 6),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Total Weekly Earnings'.tr,
|
||||
style: const TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'${controller.weeklyList.isEmpty ? '0' : controller.weeklyList[0]['totalAmount'].toString()} ${'L.E'.tr}',
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 40,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Builds the list of transaction cards.
|
||||
Widget _buildTransactionList(DriverWalletHistoryController controller) {
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: controller.weeklyList.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
var transaction = controller.weeklyList[index];
|
||||
return _TransactionCard(transaction: transaction);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// A user-friendly message for when there are no transactions.
|
||||
Widget _buildEmptyState() {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.receipt_long_outlined,
|
||||
size: 80,
|
||||
color: Colors.grey.shade300,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
'No Transactions Yet'.tr,
|
||||
style: const TextStyle(
|
||||
color: kPrimaryTextColor,
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Your weekly payment history will appear here.'.tr,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
color: kSecondaryTextColor,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// A helper for creating styled section titles.
|
||||
Widget _buildSectionTitle(String title) {
|
||||
return Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
color: kPrimaryTextColor,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A custom widget for a single transaction card for better code organization.
|
||||
class _TransactionCard extends StatelessWidget {
|
||||
final Map<String, dynamic> transaction;
|
||||
|
||||
const _TransactionCard({required this.transaction});
|
||||
|
||||
/// Helper to get descriptive details for each payment method.
|
||||
({IconData icon, String title, Color color}) _getPaymentDetails(
|
||||
String paymentMethod) {
|
||||
switch (paymentMethod) {
|
||||
case 'visa':
|
||||
return (
|
||||
icon: Icons.credit_card,
|
||||
title: 'Visa Payout'.tr,
|
||||
color: kPrimaryBlue
|
||||
);
|
||||
case 'fromBudget':
|
||||
return (
|
||||
icon: Icons.arrow_upward,
|
||||
title: 'Points Purchase'.tr,
|
||||
color: Colors.orange
|
||||
);
|
||||
case 'Remainder':
|
||||
return (
|
||||
icon: Icons.account_balance_wallet_outlined,
|
||||
title: 'Cash Balance'.tr,
|
||||
color: kGreenAccent
|
||||
);
|
||||
default:
|
||||
return (
|
||||
icon: Icons.receipt_long,
|
||||
title: paymentMethod.tr,
|
||||
color: kSecondaryTextColor
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final details = _getPaymentDetails(transaction['paymentMethod']);
|
||||
final date = DateTime.parse(transaction['dateUpdated']);
|
||||
final formattedDate = DateFormat('MMM d, yyyy').format(date);
|
||||
final formattedTime = DateFormat('hh:mm a').format(date);
|
||||
|
||||
return Card(
|
||||
margin: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
elevation: 2,
|
||||
shadowColor: Colors.grey.withOpacity(0.1),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Row(
|
||||
children: [
|
||||
// Icon
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: details.color.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Icon(details.icon, color: details.color, size: 28),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
// Title and Date
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
details.title,
|
||||
style: const TextStyle(
|
||||
color: kPrimaryTextColor,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'$formattedDate at $formattedTime',
|
||||
style: const TextStyle(
|
||||
color: kSecondaryTextColor,
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Amount
|
||||
Text(
|
||||
'${transaction['amount']} ${'L.E'.tr}',
|
||||
style: const TextStyle(
|
||||
color: kPrimaryTextColor,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user