add new featurs like new stat page

This commit is contained in:
Hamza-Ayed
2026-05-08 22:44:55 +03:00
parent efbc921273
commit 8f555691b9
33 changed files with 1194 additions and 585 deletions

View File

@@ -1,19 +1,23 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart';
class FinanceDesignSystem { class FinanceDesignSystem {
// --- Colors --- // --- Colors ---
static const Color primaryDark = Color(0xFF0A0E21); static Color get primaryDark => Get.isDarkMode ? const Color(0xFFE0E0E0) : const Color(0xFF0A0E21);
static const Color accentBlue = Color(0xFF3D5AFE); static Color get accentBlue => const Color(0xFF3D5AFE);
static const Color successGreen = Color(0xFF00C853); static Color get successGreen => const Color(0xFF00C853);
static const Color dangerRed = Color(0xFFD50000); static Color get dangerRed => const Color(0xFFD50000);
static const Color backgroundColor = Color(0xFFF6F8FA); static Color get backgroundColor => Get.isDarkMode ? const Color(0xFF0A0E21) : const Color(0xFFF6F8FA);
static const Color cardColor = Color(0xFFFFFFFF); static Color get cardColor => Get.isDarkMode ? const Color(0xFF1E1E2E) : const Color(0xFFFFFFFF);
static const Color textSecondary = Color(0xFF757575); static Color get textSecondary => Get.isDarkMode ? Colors.white70 : const Color(0xFF757575);
static const Color textMuted = Color(0xFFBDBDBD); static Color get textMuted => Get.isDarkMode ? Colors.white38 : const Color(0xFFBDBDBD);
static Color get borderColor => Get.isDarkMode ? Colors.white10 : Colors.grey.withOpacity(0.1);
// --- Gradients --- // --- Gradients ---
static const LinearGradient balanceGradient = LinearGradient( static LinearGradient get balanceGradient => LinearGradient(
colors: [Color(0xFF0A0E21), Color(0xFF1A237E)], colors: Get.isDarkMode
? [const Color(0xFF1E1E2E), const Color(0xFF2A2A3E)]
: [const Color(0xFF0A0E21), const Color(0xFF1A237E)],
begin: Alignment.topLeft, begin: Alignment.topLeft,
end: Alignment.bottomRight, end: Alignment.bottomRight,
); );
@@ -34,19 +38,19 @@ class FinanceDesignSystem {
static const double verticalSectionPadding = 24.0; static const double verticalSectionPadding = 24.0;
// --- Text Styles --- // --- Text Styles ---
static const TextStyle balanceStyle = TextStyle( static TextStyle get balanceStyle => const TextStyle(
fontSize: 32, fontSize: 32,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.white, color: Colors.white,
); );
static const TextStyle headingStyle = TextStyle( static TextStyle get headingStyle => TextStyle(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: primaryDark, color: primaryDark,
); );
static const TextStyle subHeadingStyle = TextStyle( static TextStyle get subHeadingStyle => TextStyle(
fontSize: 14, fontSize: 14,
color: textSecondary, color: textSecondary,
); );

View File

@@ -532,7 +532,7 @@ Download the Intaleq app now and enjoy your ride!
String message = '${'*Intaleq DRIVER CODE*'.tr}\n\n' String message = '${'*Intaleq DRIVER CODE*'.tr}\n\n'
'${"Use this code in registration".tr}\n' '${"Use this code in registration".tr}\n'
'${"To get a gift for both".tr}\n\n' '${"To get a gift for both".tr}\n\n'
'${"The period of this code is 1 hour".tr}\n\n' '${"The period of this code is 24 hours".tr}\n\n'
'${'before'.tr} *${d['message']['expirationTime'].toString()}*\n\n' '${'before'.tr} *${d['message']['expirationTime'].toString()}*\n\n'
'_*${d['message']['inviteCode'].toString()}*_\n\n' '_*${d['message']['inviteCode'].toString()}*_\n\n'
'${"Install our app:".tr}\n' '${"Install our app:".tr}\n'
@@ -581,7 +581,7 @@ Download the Intaleq app now and enjoy your ride!
String message = '${'*Intaleq APP CODE*'.tr}\n\n' String message = '${'*Intaleq APP CODE*'.tr}\n\n'
'${"Use this code in registration".tr}\n\n' '${"Use this code in registration".tr}\n\n'
'${"To get a gift for both".tr}\n\n' '${"To get a gift for both".tr}\n\n'
'${"The period of this code is 1 hour".tr}\n\n' '${"The period of this code is 24 hours".tr}\n\n'
'${'before'.tr} *${d['message']['expirationTime'].toString()}*\n\n' '${'before'.tr} *${d['message']['expirationTime'].toString()}*\n\n'
'_*${d['message']['inviteCode'].toString()}*_\n\n' '_*${d['message']['inviteCode'].toString()}*_\n\n'
'${"Install our app:".tr}\n' '${"Install our app:".tr}\n'

View File

@@ -218,22 +218,34 @@ class ChallengesController extends GetxController {
} }
} }
// Fetch weekly aggregate for weekly challenges // 2. Fetch weekly earnings from PAYMENT server
var weeklyRes = await CRUD().get( var weeklyEarningsRes = await CRUD().getWallet(
link: AppLink.getDriverWeekPaymentMove,
payload: {'driverID': box.read(BoxName.driverID).toString()},
);
double weeklyEarnings = 0;
if (weeklyEarningsRes != null && weeklyEarningsRes != 'failure') {
var data = jsonDecode(weeklyEarningsRes);
if (data['message'] is List && data['message'].isNotEmpty) {
weeklyEarnings = double.tryParse(data['message'][0]['totalAmount']?.toString() ?? '0') ?? 0;
}
}
// 3. Fetch weekly trips and hours from RIDES server (avoiding earnings join)
var weeklyAggregateRes = await CRUD().get(
link: AppLink.getWeeklyAggregate, link: AppLink.getWeeklyAggregate,
payload: {'driver_id': box.read(BoxName.driverID).toString()}, payload: {'driver_id': box.read(BoxName.driverID).toString()},
); );
int weeklyTrips = 0; int weeklyTrips = 0;
double weeklyEarnings = 0;
double weeklyHours = 0; double weeklyHours = 0;
if (weeklyRes != null && weeklyRes != 'failure') { if (weeklyAggregateRes != null && weeklyAggregateRes != 'failure') {
var data = jsonDecode(weeklyRes); var data = jsonDecode(weeklyAggregateRes);
if (data['message'] is List) { if (data['message'] is List) {
for (var day in data['message']) { for (var day in data['message']) {
weeklyTrips += int.tryParse(day['trips']?.toString() ?? '0') ?? 0; weeklyTrips += int.tryParse(day['trips']?.toString() ?? '0') ?? 0;
weeklyEarnings += double.tryParse(day['earnings']?.toString() ?? '0') ?? 0;
weeklyHours += double.tryParse(day['hours']?.toString() ?? '0') ?? 0; weeklyHours += double.tryParse(day['hours']?.toString() ?? '0') ?? 0;
} }
} }

View File

@@ -32,8 +32,7 @@ class StatisticsController extends GetxController {
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
fetchWeeklyData(); reloadData();
fetchMonthlyData();
} }
void changeTab(int tab) { void changeTab(int tab) {
@@ -89,12 +88,13 @@ class StatisticsController extends GetxController {
monthlyEarnings = (data['message'] as List) monthlyEarnings = (data['message'] as List)
.map((e) => MonthlyPriceDriverModel.fromJson(e)) .map((e) => MonthlyPriceDriverModel.fromJson(e))
.toList(); .toList();
monthlyTotalEarnings = monthlyEarnings.fold(0, (s, d) => s + d.pricePerDay); monthlyTotalEarnings =
monthlyEarnings.fold(0, (s, d) => s + d.pricePerDay);
// أفضل يوم // أفضل يوم
if (monthlyEarnings.isNotEmpty) { if (monthlyEarnings.isNotEmpty) {
var best = monthlyEarnings.reduce((a, b) => var best = monthlyEarnings
a.pricePerDay > b.pricePerDay ? a : b); .reduce((a, b) => a.pricePerDay > b.pricePerDay ? a : b);
bestDay = best.day.toString(); bestDay = best.day.toString();
bestDayEarnings = best.pricePerDay; bestDayEarnings = best.pricePerDay;
} }
@@ -127,7 +127,8 @@ class StatisticsController extends GetxController {
monthlyDuration = (data['message'] as List) monthlyDuration = (data['message'] as List)
.map((e) => MonthlyDataModel.fromJson(e)) .map((e) => MonthlyDataModel.fromJson(e))
.toList(); .toList();
monthlyTotalHours = monthlyDuration.fold(0, (s, d) => s + d.totalDuration.toDouble()); monthlyTotalHours =
monthlyDuration.fold(0, (s, d) => s + d.totalDuration.toDouble());
} }
} }
} catch (e) { } catch (e) {
@@ -157,9 +158,26 @@ class StatisticsController extends GetxController {
return days[weekday - 1]; return days[weekday - 1];
} }
Future<void> refresh() async { bool _isFetching = false;
await fetchWeeklyData();
await fetchMonthlyData(); Future<void> reloadData() async {
if (_isFetching) return;
_isFetching = true;
isLoading = true;
update();
try {
debugPrint('📊 [Statistics] Reloading data...');
await fetchWeeklyData();
await fetchMonthlyData();
debugPrint('📊 [Statistics] Data reload complete.');
} catch (e) {
debugPrint('❌ [Statistics] Error reloading data: $e');
} finally {
_isFetching = false;
isLoading = false;
update();
}
} }
} }
@@ -180,7 +198,8 @@ class DayStat {
}); });
factory DayStat.fromJson(Map<String, dynamic> json) { factory DayStat.fromJson(Map<String, dynamic> json) {
final date = DateTime.tryParse(json['day']?.toString() ?? '') ?? DateTime.now(); final date =
DateTime.tryParse(json['day']?.toString() ?? '') ?? DateTime.now();
const dayNames = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; const dayNames = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
return DayStat( return DayStat(
date: date, date: date,

View File

@@ -201,7 +201,79 @@ class MyTranslation extends Translations {
"Average of Hours of": "متوسط ساعات", "Average of Hours of": "متوسط ساعات",
"Awaiting response...": "عم نستنى الرد...", "Awaiting response...": "عم نستنى الرد...",
"Awfar Car": "سيارة أوفر", "Awfar Car": "سيارة أوفر",
"Back": "رجوع", "Mon": "الاثنين",
"Tue": "الثلاثاء",
"Wed": "الأربعاء",
"Thu": "الخميس",
"Fri": "الجمعة",
"Sat": "السبت",
"Sun": "الأحد",
"The price must be over than": "السعر لازم يكون أكثر من",
"Driver Level": "مستوى السائق",
"Next Level:": "المستوى التالي:",
"Points": "نقطة",
"Maximum Level Reached!": "وصلت لأعلى مستوى!",
"Basic features": "ميزات أساسية",
"Standard support": "دعم قياسي",
"Priority medium": "أولوية متوسطة",
"Silver badge": "وسام فضي",
"-1% commission": "خصم 1% من العمولة",
"High priority": "أولوية عالية",
"Gold badge": "وسام ذهبي",
"-2% commission": "خصم 2% من العمولة",
"VIP first": "أولوية VIP",
"Diamond badge": "وسام ألماسي",
"-5% commission": "خصم 5% من العمولة",
"Priority support": "دعم فني ذو أولوية",
"Daily Goal": "الهدف اليومي",
"Edit": "تعديل",
"Set Goal": "تحديد هدف",
"Goal Achieved!": "تم تحقيق الهدف!",
"Remaining:": "المتبقي:",
"Set Daily Goal": "تحديد الهدف اليومي",
"How much do you want to earn today?": "كم تريد أن تربح اليوم؟",
"Save": "حفظ",
"Cancel": "إلغاء",
"Today Overview": "نظرة عامة على اليوم",
"Online Duration": "مدة التواجد",
"Refused": "المرفوضة",
"Score": "التقييم",
"Max Speed": "أعلى سرعة",
"Hard Brakes": "الفرامل المفاجئة",
"Driving Behavior": "سلوك القيادة",
"Excellent": "ممتاز",
"Good": "جيد",
"Needs Improvement": "يحتاج تحسين",
"Achievements": "الإنجازات",
"Day Streak": "سلسلة الأيام",
"Rating": "التقييم",
"Referrals": "الإحالات",
"First Trip": "أول رحلة",
"Complete your first trip": "أكمل أول رحلة لك",
"Road Warrior": "محارب الطريق",
"Complete 50 trips": "أكمل 50 رحلة",
"Century Rider": "سائق المئة",
"Complete 100 trips": "أكمل 100 رحلة",
"Road Legend": "أسطورة الطريق",
"Complete 500 trips": "أكمل 500 رحلة",
"Five Star Driver": "سائق 5 نجوم",
"Maintain 5.0 rating": "حافظ على تقييم 5.0",
"Weekly Streak": "سلسلة أسبوعية",
"Work 7 consecutive days": "اعمل 7 أيام متتالية",
"Monthly Streak": "سلسلة شهرية",
"Work 30 consecutive days": "اعمل 30 يوم متتالي",
"Social Butterfly": "الفراشة الاجتماعية",
"Refer 5 drivers": "ادعُ 5 سائقين",
"Weekly Earnings": "الأرباح الأسبوعية",
"Monthly Report": "التقرير الشهري",
"Best Day": "أفضل يوم",
"No data yet": "لا توجد بيانات بعد",
"h": "ساعة",
"Trip": "رحلة",
"Rides": "رحلات",
"Hours": "ساعات",
"Total Trips": "إجمالي الرحلات",
"Total Earnings": "إجمالي الأرباح",
"Back to other sign-in options": "Back to other sign-in options":
"الرجوع لخيارات تسجيل الدخول التانية", "الرجوع لخيارات تسجيل الدخول التانية",
"Bahrain": "البحرين", "Bahrain": "البحرين",
@@ -1511,7 +1583,24 @@ class MyTranslation extends Translations {
"The payment was approved.": "تمت الموافقة على الدفع.", "The payment was approved.": "تمت الموافقة على الدفع.",
"The payment was not approved. Please try again.": "The payment was not approved. Please try again.":
"ما انقبل الدفع. تفضل جرّب مرة تانية.", "ما انقبل الدفع. تفضل جرّب مرة تانية.",
"The period of this code is 1 hour": "مدة هالكود ساعة وحدة", "The period of this code is 24 hours": "صلاحية هذا الكود هي 24 ساعة",
"Trips": "الرحلات",
"Challenges": "التحديات",
"My Schedule": "جدولي",
"Leaderboard": "لوحة المتصدرين",
"Daily Challenges": "التحديات اليومية",
"Weekly Challenges": "التحديات الأسبوعية",
"Claim Reward": "استلام المكافأة",
"Claimed": "تم الاستلام",
"Earnings": "الأرباح",
"You": "أنت",
"Weekly Plan": "الخطة الأسبوعية",
"Work Days": "أيام العمل",
"Day Off": "يوم عطلة",
"Helping Center": "مركز المساعدة",
"Invite Driver": "دعوة سائق",
"Available for rides": "متاح للرحلات",
"History of Trip": "سجل الرحلات",
"The price may increase if the route changes.": "The price may increase if the route changes.":
"السعر ممكن يزيد إذا تغيّر الطريق.", "السعر ممكن يزيد إذا تغيّر الطريق.",
"The price must be over than": "السعر لازم يكون أكثر من", "The price must be over than": "السعر لازم يكون أكثر من",
@@ -2477,7 +2566,8 @@ class MyTranslation extends Translations {
"Go Now": "اذهب الآن", "Go Now": "اذهب الآن",
"Selected Location": "الموقع المحدد", "Selected Location": "الموقع المحدد",
"Add Balance": "إضافة رصيد", "Add Balance": "إضافة رصيد",
"Select how you want to charge your account": "اختر كيف تريد شحن حسابك", "Select how you want to charge your account":
"اختر كيف تريد شحن حسابك",
"Recharge Balance Packages": "باقات شحن الرصيد", "Recharge Balance Packages": "باقات شحن الرصيد",
"Select Payment Method": "اختر طريقة الدفع", "Select Payment Method": "اختر طريقة الدفع",
"Amount to charge:": "المبلغ المطلوب شحنه:", "Amount to charge:": "المبلغ المطلوب شحنه:",
@@ -2495,7 +2585,8 @@ class MyTranslation extends Translations {
"for": "بـ", "for": "بـ",
"Points": "نقاط", "Points": "نقاط",
"Pay from my budget": "الدفع من الرصيد المتاح", "Pay from my budget": "الدفع من الرصيد المتاح",
"Use Touch ID or Face ID to confirm payment": "استخدم بصمة الإصبع أو الوجه لتأكيد الدفع", "Use Touch ID or Face ID to confirm payment":
"استخدم بصمة الإصبع أو الوجه لتأكيد الدفع",
"Your Budget less than needed": "رصيدك أقل من المطلوب", "Your Budget less than needed": "رصيدك أقل من المطلوب",
"Available Balance": "الرصيد المتاح", "Available Balance": "الرصيد المتاح",
"Total Rides": "إجمالي الرحلات", "Total Rides": "إجمالي الرحلات",
@@ -2512,7 +2603,8 @@ class MyTranslation extends Translations {
"Driver Balance": "رصيد السائق", "Driver Balance": "رصيد السائق",
"Pay from my budget": "الدفع من الرصيد المتاح", "Pay from my budget": "الدفع من الرصيد المتاح",
"You have in account": "لديك في الحساب", "You have in account": "لديك في الحساب",
"Select how you want to charge your account": "اختر كيف تريد شحن حسابك", "Select how you want to charge your account":
"اختر كيف تريد شحن حسابك",
"Add Balance": "إضافة رصيد", "Add Balance": "إضافة رصيد",
"SYP": "ل.س", "SYP": "ل.س",
"Your completed trips will appear here": "ستظهر رحلاتك المكتملة هنا", "Your completed trips will appear here": "ستظهر رحلاتك المكتملة هنا",

View File

@@ -25,7 +25,10 @@ class SettingController extends GetxController {
isDarkMode = !isDarkMode; isDarkMode = !isDarkMode;
box.write('isDarkMode', isDarkMode); box.write('isDarkMode', isDarkMode);
// Update the theme using the LocaleController to ensure correct fonts are used // Switch theme instantly across the app
Get.changeThemeMode(isDarkMode ? ThemeMode.dark : ThemeMode.light);
// Update the theme using the LocaleController to ensure correct fonts/colors are refreshed
if (Get.isRegistered<LocaleController>()) { if (Get.isRegistered<LocaleController>()) {
Get.find<LocaleController>().refreshTheme(); Get.find<LocaleController>().refreshTheme();
} }

View File

@@ -56,10 +56,54 @@
"What are the order details we provide to you?": "", "What are the order details we provide to you?": "",
"Toggle Traffic": "", "Toggle Traffic": "",
"General Authority For Supply Commodities": "", "General Authority For Supply Commodities": "",
"Error fetching rides. Please try again.": "", "Please enter your first name.": "الرجاء إدخال اسمك الأول",
"Please enter Your Email.": "", "Health Insurance": "التأمين الصحي",
"Health Insurance": "", "Invite Driver": "دعوة سائق",
"Please enter your first name.": "", "Leaderboard": "قائمة المتصدرين",
"Challenges": "التحديات",
"My Schedule": "جدولي",
"Statistics": "الإحصائيات",
"Balance": "الرصيد",
"History of Trip": "سجل الرحلات",
"Available for rides": "متاح للرحلات",
"Notifications": "التنبيهات",
"Helping Center": "مركز المساعدة",
"Is device compatible": "هل الجهاز متوافق؟",
"Privacy Policy": "سياسة الخصوصية",
"Daily Challenges": "تحديات يومية",
"Weekly Challenges": "تحديات أسبوعية",
"Invite Rider": "دعوة راكب",
"Referral Code": "كود الإحالة",
"Referral Center": "مركز الإحالة",
"Share": "مشاركة",
"WhatsApp": "واتساب",
"Share via": "مشاركة عبر",
"How It Works": "كيف يعمل",
"Share your code": "شارك كودك",
"Friend signs up": "تسجيل الصديق",
"Both earn rewards": "كلاكما يربح",
"Bonus at 10 trips": "مكافأة عند 10 رحلات",
"Send your referral code to friends": "أرسل كود الإحالة لأصدقائك",
"They register using your code": "يسجلون باستخدام كودك",
"You get 100 pts, they get 50 pts": "تحصل على 100 نقطة، وهم يحصلون على 50",
"Extra 200 pts when they complete 10 trips": "200 نقطة إضافية عند إكمالهم 10 رحلات",
"Driver Invitations": "دعوات السائقين",
"Passenger Invitations": "دعوات الركاب",
"Code copied!": "تم نسخ الكود!",
"Your Referral Code": "كود الإحالة الخاص بك",
"Share this code to earn rewards": "شارك هذا الكود لربح المكافآت",
"Profile": "الملف الشخصي",
"Settings": "الإعدادات",
"Contact Us": "اتصل بنا",
"Videos Tutorials": "الفيديوهات التعليمية",
"Rate Our App": "قيم تطبيقنا",
"About Us": "من نحن",
"Sign Out": "تسجيل الخروج",
"Claimed": "تم الاستلام",
"Claim Reward": "احصل على المكافأة",
"Active": "نشط",
"Rewards": "المكافآت",
"Total Invites": "إجمالي الدعوات",
"Payment Method": "", "Payment Method": "",
"wallet_credited_message": "", "wallet_credited_message": "",
"similar": "", "similar": "",

View File

@@ -12,17 +12,18 @@ class ChallengesPage extends StatelessWidget {
return Scaffold( return Scaffold(
backgroundColor: FinanceDesignSystem.backgroundColor, backgroundColor: FinanceDesignSystem.backgroundColor,
body: GetBuilder<ChallengesController>(builder: (cc) { body: GetBuilder<ChallengesController>(builder: (cc) {
if (cc.isLoading) if (cc.isLoading) {
return const Center( return Center(
child: CircularProgressIndicator( child: CircularProgressIndicator(
color: FinanceDesignSystem.primaryDark)); color: FinanceDesignSystem.primaryDark));
}
return CustomScrollView( return CustomScrollView(
physics: const BouncingScrollPhysics(), physics: const BouncingScrollPhysics(),
slivers: [ slivers: [
SliverAppBar( SliverAppBar(
expandedHeight: 160, expandedHeight: 160,
pinned: true, pinned: true,
backgroundColor: const Color(0xFF1A237E), backgroundColor: Get.isDarkMode ? FinanceDesignSystem.primaryDark : const Color(0xFF1A237E),
leading: IconButton( leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new_rounded, icon: const Icon(Icons.arrow_back_ios_new_rounded,
color: Colors.white, size: 20), color: Colors.white, size: 20),
@@ -36,22 +37,22 @@ class ChallengesPage extends StatelessWidget {
flexibleSpace: FlexibleSpaceBar( flexibleSpace: FlexibleSpaceBar(
centerTitle: true, centerTitle: true,
title: Text('Challenges'.tr, title: Text('Challenges'.tr,
style: const TextStyle( style: TextStyle(
color: Colors.white, color: Colors.white,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 18)), fontSize: 18)),
background: Stack(fit: StackFit.expand, children: [ background: Stack(fit: StackFit.expand, children: [
Container( Container(
decoration: const BoxDecoration( decoration: BoxDecoration(
gradient: LinearGradient(colors: [ gradient: LinearGradient(colors: Get.isDarkMode
Color(0xFF0A0E21), ? [FinanceDesignSystem.primaryDark, const Color(0xFF1E1E2E)]
Color(0xFF1A237E) : [const Color(0xFF0A0E21), const Color(0xFF1A237E)]
]))), ))),
Positioned( Positioned(
right: -30, right: -30,
top: -10, top: -10,
child: Icon(Icons.bolt_rounded, child: Icon(Icons.bolt_rounded,
size: 160, color: Colors.white.withOpacity(0.04))), size: 160, color: Colors.white.withValues(alpha: 0.04))),
]), ]),
), ),
), ),
@@ -92,10 +93,10 @@ class ChallengesPage extends StatelessWidget {
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration( decoration: BoxDecoration(
color: FinanceDesignSystem.accentBlue.withOpacity(0.1), color: FinanceDesignSystem.accentBlue.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(20)), borderRadius: BorderRadius.circular(20)),
child: Text('$done/$total', child: Text('$done/$total',
style: const TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: FinanceDesignSystem.accentBlue)), color: FinanceDesignSystem.accentBlue)),
@@ -112,11 +113,11 @@ class ChallengesPage extends StatelessWidget {
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius), borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius),
border: c.isCompleted border: c.isCompleted
? Border.all(color: c.color.withOpacity(0.3), width: 1.5) ? Border.all(color: c.color.withValues(alpha: 0.3), width: 1.5)
: null, : null,
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Colors.black.withOpacity(0.03), color: Colors.black.withValues(alpha: 0.03),
blurRadius: 10, blurRadius: 10,
offset: const Offset(0, 4)) offset: const Offset(0, 4))
], ],
@@ -127,7 +128,7 @@ class ChallengesPage extends StatelessWidget {
width: 44, width: 44,
height: 44, height: 44,
decoration: BoxDecoration( decoration: BoxDecoration(
color: c.color.withOpacity(0.12), color: c.color.withValues(alpha: 0.12),
borderRadius: BorderRadius.circular(12)), borderRadius: BorderRadius.circular(12)),
child: Icon(c.icon, color: c.color, size: 22), child: Icon(c.icon, color: c.color, size: 22),
), ),
@@ -143,12 +144,12 @@ class ChallengesPage extends StatelessWidget {
color: FinanceDesignSystem.primaryDark)), color: FinanceDesignSystem.primaryDark)),
Text(isAr ? c.descriptionAr : c.descriptionEn, Text(isAr ? c.descriptionAr : c.descriptionEn,
style: style:
TextStyle(fontSize: 11, color: Colors.grey.shade500)), TextStyle(fontSize: 11, color: FinanceDesignSystem.textSecondary)),
])), ])),
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color(0xFFFFD700).withOpacity(0.15), color: const Color(0xFFFFD700).withValues(alpha: 0.15),
borderRadius: BorderRadius.circular(12)), borderRadius: BorderRadius.circular(12)),
child: Text('+${c.reward}', child: Text('+${c.reward}',
style: const TextStyle( style: const TextStyle(
@@ -164,7 +165,7 @@ class ChallengesPage extends StatelessWidget {
style: TextStyle( style: TextStyle(
fontSize: 11, fontSize: 11,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Colors.grey.shade600)), color: FinanceDesignSystem.textSecondary)),
Text('${(c.progress * 100).toStringAsFixed(0)}%', Text('${(c.progress * 100).toStringAsFixed(0)}%',
style: TextStyle( style: TextStyle(
fontSize: 11, fontWeight: FontWeight.bold, color: c.color)), fontSize: 11, fontWeight: FontWeight.bold, color: c.color)),
@@ -174,7 +175,7 @@ class ChallengesPage extends StatelessWidget {
Container( Container(
height: 8, height: 8,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.grey.shade100, color: FinanceDesignSystem.backgroundColor,
borderRadius: BorderRadius.circular(4))), borderRadius: BorderRadius.circular(4))),
LayoutBuilder( LayoutBuilder(
builder: (ctx, cons) => AnimatedContainer( builder: (ctx, cons) => AnimatedContainer(
@@ -184,7 +185,7 @@ class ChallengesPage extends StatelessWidget {
width: cons.maxWidth * c.progress, width: cons.maxWidth * c.progress,
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: LinearGradient( gradient: LinearGradient(
colors: [c.color, c.color.withOpacity(0.6)]), colors: [c.color, c.color.withValues(alpha: 0.6)]),
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(4),
), ),
)), )),
@@ -212,11 +213,11 @@ class ChallengesPage extends StatelessWidget {
const SizedBox(height: 8), const SizedBox(height: 8),
Center( Center(
child: Row(mainAxisSize: MainAxisSize.min, children: [ child: Row(mainAxisSize: MainAxisSize.min, children: [
const Icon(Icons.check_circle_rounded, Icon(Icons.check_circle_rounded,
color: FinanceDesignSystem.successGreen, size: 16), color: FinanceDesignSystem.successGreen, size: 16),
const SizedBox(width: 4), const SizedBox(width: 4),
Text('Claimed'.tr, Text('Claimed'.tr,
style: const TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: FinanceDesignSystem.successGreen)), color: FinanceDesignSystem.successGreen)),

View File

@@ -12,121 +12,251 @@ class LeaderboardPage extends StatelessWidget {
return Scaffold( return Scaffold(
backgroundColor: FinanceDesignSystem.backgroundColor, backgroundColor: FinanceDesignSystem.backgroundColor,
body: GetBuilder<LeaderboardController>(builder: (lc) { body: GetBuilder<LeaderboardController>(builder: (lc) {
if (lc.isLoading) return const Center(child: CircularProgressIndicator(color: FinanceDesignSystem.primaryDark)); if (lc.isLoading) {
return CustomScrollView(physics: const BouncingScrollPhysics(), slivers: [ return Center(
SliverAppBar( child: CircularProgressIndicator(
expandedHeight: 200, pinned: true, color: FinanceDesignSystem.primaryDark));
backgroundColor: const Color(0xFF0A0E21), }
leading: IconButton(icon: const Icon(Icons.arrow_back_ios_new_rounded, color: Colors.white, size: 20), onPressed: () => Get.back()), return CustomScrollView(
flexibleSpace: FlexibleSpaceBar( physics: const BouncingScrollPhysics(),
centerTitle: true, slivers: [
title: Text('Leaderboard'.tr, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 18)), SliverAppBar(
background: Stack(fit: StackFit.expand, children: [ expandedHeight: 200,
Container(decoration: const BoxDecoration(gradient: LinearGradient(colors: [Color(0xFF0A0E21), Color(0xFFB71C1C)]))), pinned: true,
Positioned(right: -40, top: -20, child: Icon(Icons.leaderboard_rounded, size: 180, color: Colors.white.withOpacity(0.04))), backgroundColor: Get.isDarkMode
// Top 3 podium ? FinanceDesignSystem.primaryDark
if (lc.currentLeaderboard.length >= 3) Positioned(bottom: 50, left: 0, right: 0, child: _buildPodium(lc)), : const Color(0xFF0A0E21),
]), leading: IconButton(
), icon: const Icon(Icons.arrow_back_ios_new_rounded,
), color: Colors.white, size: 20),
// Tab bar onPressed: () => Get.back()),
SliverToBoxAdapter(child: Container( flexibleSpace: FlexibleSpaceBar(
margin: const EdgeInsets.fromLTRB(16, 16, 16, 0), centerTitle: true,
padding: const EdgeInsets.all(4), title: Text('Leaderboard'.tr,
decoration: BoxDecoration(color: Colors.grey.shade100, borderRadius: BorderRadius.circular(14)), style: const TextStyle(
child: Row(children: [ color: Colors.white,
_tab('Trips'.tr, Icons.local_taxi_rounded, 0, lc), fontWeight: FontWeight.bold,
_tab('Earnings'.tr, Icons.monetization_on_rounded, 1, lc), fontSize: 18)),
]), background: Stack(fit: StackFit.expand, children: [
)), Container(
// List decoration: const BoxDecoration(
SliverPadding(padding: const EdgeInsets.fromLTRB(16, 16, 16, 40), sliver: SliverList( gradient: LinearGradient(colors: [
delegate: SliverChildBuilderDelegate( Color(0xFF0A0E21),
(ctx, i) { Color(0xFFB71C1C)
if (i >= lc.currentLeaderboard.length) return null; ]))),
return _buildRow(lc.currentLeaderboard[i], lc.selectedTab == 1); Positioned(
}, right: -40,
childCount: lc.currentLeaderboard.length, top: -20,
), child: Icon(Icons.leaderboard_rounded,
)), size: 180, color: Colors.white.withValues(alpha: 0.04))),
]); // Top 3 podium
if (lc.currentLeaderboard.length >= 3)
Positioned(
bottom: 50,
left: 0,
right: 0,
child: _buildPodium(lc)),
]),
),
),
// Tab bar
SliverToBoxAdapter(
child: Container(
margin: const EdgeInsets.fromLTRB(16, 16, 16, 0),
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: FinanceDesignSystem.backgroundColor.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(14)),
child: Row(children: [
_tab('Trips'.tr, Icons.local_taxi_rounded, 0, lc),
_tab('Earnings'.tr, Icons.monetization_on_rounded, 1, lc),
]),
)),
// List
SliverPadding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 40),
sliver: SliverList(
delegate: SliverChildBuilderDelegate(
(ctx, i) {
if (i >= lc.currentLeaderboard.length) return null;
return _buildRow(
lc.currentLeaderboard[i], lc.selectedTab == 1);
},
childCount: lc.currentLeaderboard.length,
),
)),
]);
}), }),
); );
} }
Widget _buildPodium(LeaderboardController lc) { Widget _buildPodium(LeaderboardController lc) {
final top3 = lc.currentLeaderboard.take(3).toList(); final top3 = lc.currentLeaderboard.take(3).toList();
return Row(mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, children: [ return Row(
if (top3.length > 1) _podiumItem(top3[1], 2, 50, const Color(0xFFC0C0C0)), mainAxisAlignment: MainAxisAlignment.center,
if (top3.isNotEmpty) _podiumItem(top3[0], 1, 70, const Color(0xFFFFD700)), crossAxisAlignment: CrossAxisAlignment.end,
if (top3.length > 2) _podiumItem(top3[2], 3, 35, const Color(0xFFCD7F32)), children: [
]); if (top3.length > 1)
_podiumItem(top3[1], 2, 50, const Color(0xFFC0C0C0)),
if (top3.isNotEmpty)
_podiumItem(top3[0], 1, 70, const Color(0xFFFFD700)),
if (top3.length > 2)
_podiumItem(top3[2], 3, 35, const Color(0xFFCD7F32)),
]);
} }
Widget _podiumItem(LeaderboardEntry e, int rank, double height, Color color) { Widget _podiumItem(LeaderboardEntry e, int rank, double height, Color color) {
return Padding(padding: const EdgeInsets.symmetric(horizontal: 8), child: Column(mainAxisSize: MainAxisSize.min, children: [ return Padding(
CircleAvatar(radius: rank == 1 ? 22 : 18, backgroundColor: color.withOpacity(0.3), padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text(_getRankEmoji(rank), style: TextStyle(fontSize: rank == 1 ? 22 : 16))), child: Column(mainAxisSize: MainAxisSize.min, children: [
const SizedBox(height: 4), CircleAvatar(
Text(e.name.length > 8 ? '${e.name.substring(0, 8)}...' : e.name, radius: rank == 1 ? 22 : 18,
style: TextStyle(color: Colors.white, fontSize: 10, fontWeight: e.isCurrentUser ? FontWeight.bold : FontWeight.normal)), backgroundColor: color.withValues(alpha: 0.3),
])); child: Text(_getRankEmoji(rank),
style: TextStyle(fontSize: rank == 1 ? 22 : 16))),
const SizedBox(height: 4),
Text(e.name.length > 8 ? '${e.name.substring(0, 8)}...' : e.name,
style: TextStyle(
color: Colors.white,
fontSize: 10,
fontWeight:
e.isCurrentUser ? FontWeight.bold : FontWeight.normal)),
]));
} }
Widget _tab(String label, IconData icon, int idx, LeaderboardController lc) { Widget _tab(String label, IconData icon, int idx, LeaderboardController lc) {
final selected = lc.selectedTab == idx; final selected = lc.selectedTab == idx;
return Expanded(child: GestureDetector( return Expanded(
child: GestureDetector(
onTap: () => lc.changeTab(idx), onTap: () => lc.changeTab(idx),
child: AnimatedContainer( child: AnimatedContainer(
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
padding: const EdgeInsets.symmetric(vertical: 10), padding: const EdgeInsets.symmetric(vertical: 10),
decoration: BoxDecoration(color: selected ? Colors.white : Colors.transparent, borderRadius: BorderRadius.circular(10), decoration: BoxDecoration(
boxShadow: selected ? [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 5)] : null), color:
selected ? FinanceDesignSystem.cardColor : Colors.transparent,
borderRadius: BorderRadius.circular(10),
boxShadow: selected
? [
BoxShadow(
color: Colors.black.withValues(alpha: 0.05), blurRadius: 5)
]
: null),
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [ child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Icon(icon, size: 16, color: selected ? FinanceDesignSystem.primaryDark : Colors.grey), Icon(icon,
size: 16,
color: selected ? FinanceDesignSystem.primaryDark : Colors.grey),
const SizedBox(width: 6), const SizedBox(width: 6),
Text(label, style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: selected ? FinanceDesignSystem.primaryDark : Colors.grey)), Text(label,
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
color: selected
? FinanceDesignSystem.primaryDark
: Colors.grey)),
]), ]),
), ),
)); ));
} }
Widget _buildRow(LeaderboardEntry e, bool isEarnings) { Widget _buildRow(LeaderboardEntry e, bool isEarnings) {
final rankColor = e.rank == 1 ? const Color(0xFFFFD700) : e.rank == 2 ? const Color(0xFFC0C0C0) : e.rank == 3 ? const Color(0xFFCD7F32) : Colors.grey.shade400; final rankColor = e.rank == 1
? const Color(0xFFFFD700)
: e.rank == 2
? const Color(0xFFC0C0C0)
: e.rank == 3
? const Color(0xFFCD7F32)
: Colors.grey.shade400;
return Container( return Container(
margin: const EdgeInsets.only(bottom: 8), margin: const EdgeInsets.only(bottom: 8),
padding: const EdgeInsets.all(14), padding: const EdgeInsets.all(14),
decoration: BoxDecoration( decoration: BoxDecoration(
color: e.isCurrentUser ? FinanceDesignSystem.accentBlue.withOpacity(0.08) : Colors.white, color: e.isCurrentUser
? FinanceDesignSystem.accentBlue.withValues(alpha: 0.08)
: FinanceDesignSystem.cardColor,
borderRadius: BorderRadius.circular(14), borderRadius: BorderRadius.circular(14),
border: e.isCurrentUser ? Border.all(color: FinanceDesignSystem.accentBlue.withOpacity(0.3), width: 1.5) : null, border: e.isCurrentUser
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.02), blurRadius: 8, offset: const Offset(0, 3))], ? Border.all(
color: FinanceDesignSystem.accentBlue.withValues(alpha: 0.3),
width: 1.5)
: null,
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.02),
blurRadius: 8,
offset: const Offset(0, 3))
],
), ),
child: Row(children: [ child: Row(children: [
// Rank // Rank
Container(width: 32, height: 32, decoration: BoxDecoration(color: rankColor.withOpacity(0.15), borderRadius: BorderRadius.circular(8)), Container(
child: Center(child: e.rank <= 3 width: 32,
? Text(_getRankEmoji(e.rank), style: const TextStyle(fontSize: 16)) height: 32,
: Text('${e.rank}', style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold, color: rankColor)))), decoration: BoxDecoration(
color: rankColor.withValues(alpha: 0.15),
borderRadius: BorderRadius.circular(8)),
child: Center(
child: e.rank <= 3
? Text(_getRankEmoji(e.rank),
style: const TextStyle(fontSize: 16))
: Text('${e.rank}',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: rankColor)))),
const SizedBox(width: 12), const SizedBox(width: 12),
// Avatar // Avatar
CircleAvatar(radius: 18, backgroundColor: Colors.grey.shade200, child: Text(e.name.isNotEmpty ? e.name[0] : '?', style: TextStyle(fontWeight: FontWeight.bold, color: Colors.grey.shade600))), CircleAvatar(
radius: 18,
backgroundColor: FinanceDesignSystem.backgroundColor,
child: Text(e.name.isNotEmpty ? e.name[0] : '?',
style: TextStyle(
fontWeight: FontWeight.bold,
color: FinanceDesignSystem.textSecondary))),
const SizedBox(width: 12), const SizedBox(width: 12),
// Name // Name
Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded(
child:
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Row(children: [ Row(children: [
Text(e.name, style: TextStyle(fontSize: 13, fontWeight: e.isCurrentUser ? FontWeight.bold : FontWeight.w500, color: FinanceDesignSystem.primaryDark)), Text(e.name,
if (e.isCurrentUser) ...[const SizedBox(width: 6), style: TextStyle(
Container(padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration(color: FinanceDesignSystem.accentBlue, borderRadius: BorderRadius.circular(6)), fontSize: 13,
child: Text('You'.tr, style: const TextStyle(fontSize: 8, fontWeight: FontWeight.bold, color: Colors.white)))], fontWeight:
e.isCurrentUser ? FontWeight.bold : FontWeight.w500,
color: FinanceDesignSystem.primaryDark)),
if (e.isCurrentUser) ...[
const SizedBox(width: 6),
Container(
padding:
const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: FinanceDesignSystem.accentBlue,
borderRadius: BorderRadius.circular(6)),
child: Text('You'.tr,
style: const TextStyle(
fontSize: 8,
fontWeight: FontWeight.bold,
color: Colors.white)))
],
]), ]),
])), ])),
// Value // Value
Text(isEarnings ? '${e.value.toStringAsFixed(0)} ${'SYP'.tr}' : '${e.value.toInt()} ${'Rides'.tr}', Text(
style: TextStyle(fontSize: 13, fontWeight: FontWeight.w800, color: FinanceDesignSystem.primaryDark)), isEarnings
? '${e.value.toStringAsFixed(0)} ${'SYP'.tr}'
: '${e.value.toInt()} ${'Rides'.tr}',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w800,
color: FinanceDesignSystem.primaryDark)),
]), ]),
); );
} }
String _getRankEmoji(int rank) => rank == 1 ? '🥇' : rank == 2 ? '🥈' : '🥉'; String _getRankEmoji(int rank) => rank == 1
? '🥇'
: rank == 2
? '🥈'
: '🥉';
} }

View File

@@ -16,7 +16,11 @@ class ReferralCenterPage extends StatelessWidget {
return Scaffold( return Scaffold(
backgroundColor: FinanceDesignSystem.backgroundColor, backgroundColor: FinanceDesignSystem.backgroundColor,
body: GetBuilder<ReferralController>(builder: (rc) { body: GetBuilder<ReferralController>(builder: (rc) {
if (rc.isLoading) return const Center(child: CircularProgressIndicator(color: FinanceDesignSystem.primaryDark)); if (rc.isLoading) {
return Center(
child: CircularProgressIndicator(
color: FinanceDesignSystem.primaryDark));
}
return CustomScrollView(physics: const BouncingScrollPhysics(), slivers: [ return CustomScrollView(physics: const BouncingScrollPhysics(), slivers: [
// ═══ Header ═══ // ═══ Header ═══
SliverAppBar( SliverAppBar(
@@ -28,7 +32,7 @@ class ReferralCenterPage extends StatelessWidget {
title: Text('Referral Center'.tr, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 18)), title: Text('Referral Center'.tr, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 18)),
background: Stack(fit: StackFit.expand, children: [ background: Stack(fit: StackFit.expand, children: [
Container(decoration: const BoxDecoration(gradient: LinearGradient(colors: [Color(0xFF0A0E21), Color(0xFF311B92)]))), Container(decoration: const BoxDecoration(gradient: LinearGradient(colors: [Color(0xFF0A0E21), Color(0xFF311B92)]))),
Positioned(right: -50, bottom: -30, child: Icon(Icons.share_rounded, size: 200, color: Colors.white.withOpacity(0.03))), Positioned(right: -50, bottom: -30, child: Icon(Icons.share_rounded, size: 200, color: Colors.white.withValues(alpha: 0.03))),
// Stats in header // Stats in header
Positioned(bottom: 60, left: 24, right: 24, child: Row(children: [ Positioned(bottom: 60, left: 24, right: 24, child: Row(children: [
_headerStat('${rc.totalReferrals}', 'Total Invites'.tr), _headerStat('${rc.totalReferrals}', 'Total Invites'.tr),
@@ -72,7 +76,7 @@ class ReferralCenterPage extends StatelessWidget {
Widget _headerStat(String value, String label) { Widget _headerStat(String value, String label) {
return Expanded(child: Column(children: [ return Expanded(child: Column(children: [
Text(value, style: const TextStyle(fontSize: 22, fontWeight: FontWeight.w900, color: Colors.white)), Text(value, style: const TextStyle(fontSize: 22, fontWeight: FontWeight.w900, color: Colors.white)),
Text(label, style: TextStyle(fontSize: 10, color: Colors.white.withOpacity(0.6))), Text(label, style: TextStyle(fontSize: 10, color: Colors.white.withValues(alpha: 0.6))),
])); ]));
} }
@@ -82,14 +86,14 @@ class ReferralCenterPage extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: const LinearGradient(colors: [Color(0xFF1A237E), Color(0xFF311B92)]), gradient: const LinearGradient(colors: [Color(0xFF1A237E), Color(0xFF311B92)]),
borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius), borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius),
boxShadow: [BoxShadow(color: const Color(0xFF311B92).withOpacity(0.3), blurRadius: 15, offset: const Offset(0, 8))], boxShadow: [BoxShadow(color: const Color(0xFF311B92).withValues(alpha: 0.3), blurRadius: 15, offset: const Offset(0, 8))],
), ),
child: Column(children: [ child: Column(children: [
Text('Your Referral Code'.tr, style: TextStyle(color: Colors.white.withOpacity(0.7), fontSize: 14)), Text('Your Referral Code'.tr, style: TextStyle(color: Colors.white.withValues(alpha: 0.7), fontSize: 14)),
const SizedBox(height: 12), const SizedBox(height: 12),
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
decoration: BoxDecoration(color: Colors.white.withOpacity(0.15), borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.white.withOpacity(0.2))), decoration: BoxDecoration(color: Colors.white.withValues(alpha: 0.15), borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.white.withValues(alpha: 0.2))),
child: Row(mainAxisSize: MainAxisSize.min, children: [ child: Row(mainAxisSize: MainAxisSize.min, children: [
Text(rc.referralCode, style: const TextStyle(fontSize: 24, fontWeight: FontWeight.w900, color: Colors.white, letterSpacing: 3)), Text(rc.referralCode, style: const TextStyle(fontSize: 24, fontWeight: FontWeight.w900, color: Colors.white, letterSpacing: 3)),
const SizedBox(width: 12), const SizedBox(width: 12),
@@ -97,14 +101,14 @@ class ReferralCenterPage extends StatelessWidget {
onTap: () { rc.copyCode(); mySnackbarSuccess('Code copied!'.tr); }, onTap: () { rc.copyCode(); mySnackbarSuccess('Code copied!'.tr); },
child: Container( child: Container(
padding: const EdgeInsets.all(6), padding: const EdgeInsets.all(6),
decoration: BoxDecoration(color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(8)), decoration: BoxDecoration(color: Colors.white.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(8)),
child: const Icon(Icons.copy_rounded, color: Colors.white, size: 18), child: const Icon(Icons.copy_rounded, color: Colors.white, size: 18),
), ),
), ),
]), ]),
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
Text('Share this code to earn rewards'.tr, style: TextStyle(color: Colors.white.withOpacity(0.5), fontSize: 12)), Text('Share this code to earn rewards'.tr, style: TextStyle(color: Colors.white.withValues(alpha: 0.5), fontSize: 12)),
]), ]),
); );
} }
@@ -130,7 +134,7 @@ class ReferralCenterPage extends StatelessWidget {
onTap: onTap, onTap: onTap,
child: Container( child: Container(
padding: const EdgeInsets.symmetric(vertical: 14), padding: const EdgeInsets.symmetric(vertical: 14),
decoration: BoxDecoration(color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(14)), decoration: BoxDecoration(color: color.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(14)),
child: Column(children: [ child: Column(children: [
Icon(icon, color: color, size: 24), Icon(icon, color: color, size: 24),
const SizedBox(height: 6), const SizedBox(height: 6),
@@ -144,9 +148,9 @@ class ReferralCenterPage extends StatelessWidget {
return Container( return Container(
padding: const EdgeInsets.all(20), padding: const EdgeInsets.all(20),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius), decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 10, offset: const Offset(0, 4))]), boxShadow: [BoxShadow(color: Colors.black.withValues(alpha: 0.03), blurRadius: 10, offset: const Offset(0, 4))]),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text('How It Works'.tr, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: FinanceDesignSystem.primaryDark)), Text('How It Works'.tr, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: FinanceDesignSystem.primaryDark)),
const SizedBox(height: 16), const SizedBox(height: 16),
_step('1', 'Share your code'.tr, 'Send your referral code to friends'.tr, const Color(0xFF2196F3)), _step('1', 'Share your code'.tr, 'Send your referral code to friends'.tr, const Color(0xFF2196F3)),
_step('2', 'Friend signs up'.tr, 'They register using your code'.tr, const Color(0xFFFF9800)), _step('2', 'Friend signs up'.tr, 'They register using your code'.tr, const Color(0xFFFF9800)),
@@ -158,12 +162,12 @@ class ReferralCenterPage extends StatelessWidget {
Widget _step(String num, String title, String desc, Color color) { Widget _step(String num, String title, String desc, Color color) {
return Padding(padding: const EdgeInsets.only(bottom: 12), child: Row(children: [ return Padding(padding: const EdgeInsets.only(bottom: 12), child: Row(children: [
Container(width: 32, height: 32, decoration: BoxDecoration(color: color.withOpacity(0.15), borderRadius: BorderRadius.circular(8)), Container(width: 32, height: 32, decoration: BoxDecoration(color: color.withValues(alpha: 0.15), borderRadius: BorderRadius.circular(8)),
child: Center(child: Text(num, style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: color))), child: Center(child: Text(num, style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: color))),
), ),
const SizedBox(width: 12), const SizedBox(width: 12),
Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(title, style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: FinanceDesignSystem.primaryDark)), Text(title, style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: FinanceDesignSystem.primaryDark)),
Text(desc, style: TextStyle(fontSize: 11, color: Colors.grey.shade500)), Text(desc, style: TextStyle(fontSize: 11, color: Colors.grey.shade500)),
])), ])),
])); ]));
@@ -174,9 +178,9 @@ class ReferralCenterPage extends StatelessWidget {
margin: const EdgeInsets.only(bottom: 10), margin: const EdgeInsets.only(bottom: 10),
padding: const EdgeInsets.all(14), padding: const EdgeInsets.all(14),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(14), decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(14),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.02), blurRadius: 8, offset: const Offset(0, 3))]), boxShadow: [BoxShadow(color: Colors.black.withValues(alpha: 0.02), blurRadius: 8, offset: const Offset(0, 3))]),
child: Row(children: [ child: Row(children: [
Container(width: 40, height: 40, decoration: BoxDecoration(color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(10)), Container(width: 40, height: 40, decoration: BoxDecoration(color: color.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(10)),
child: Icon(r.type == 'driver' ? Icons.local_taxi_rounded : Icons.person_rounded, color: color, size: 20)), child: Icon(r.type == 'driver' ? Icons.local_taxi_rounded : Icons.person_rounded, color: color, size: 20)),
const SizedBox(width: 12), const SizedBox(width: 12),
Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
@@ -186,8 +190,8 @@ class ReferralCenterPage extends StatelessWidget {
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration( decoration: BoxDecoration(
color: r.status == 'active' ? FinanceDesignSystem.successGreen.withOpacity(0.1) color: r.status == 'active' ? FinanceDesignSystem.successGreen.withValues(alpha: 0.1)
: r.status == 'registered' ? FinanceDesignSystem.accentBlue.withOpacity(0.1) : Colors.grey.shade100, : r.status == 'registered' ? FinanceDesignSystem.accentBlue.withValues(alpha: 0.1) : Colors.grey.shade100,
borderRadius: BorderRadius.circular(8)), borderRadius: BorderRadius.circular(8)),
child: Text(r.status.tr, style: TextStyle(fontSize: 10, fontWeight: FontWeight.w600, child: Text(r.status.tr, style: TextStyle(fontSize: 10, fontWeight: FontWeight.w600,
color: r.status == 'active' ? FinanceDesignSystem.successGreen color: r.status == 'active' ? FinanceDesignSystem.successGreen

View File

@@ -18,7 +18,7 @@ class HistoryCaptain extends StatelessWidget {
body: GetBuilder<HistoryCaptainController>( body: GetBuilder<HistoryCaptainController>(
builder: (controller) { builder: (controller) {
if (controller.isloading) { if (controller.isloading) {
return const Center( return Center(
child: CircularProgressIndicator( child: CircularProgressIndicator(
color: FinanceDesignSystem.primaryDark), color: FinanceDesignSystem.primaryDark),
); );
@@ -49,7 +49,7 @@ class HistoryCaptain extends StatelessWidget {
fit: StackFit.expand, fit: StackFit.expand,
children: [ children: [
Container( Container(
decoration: const BoxDecoration( decoration: BoxDecoration(
gradient: FinanceDesignSystem.balanceGradient, gradient: FinanceDesignSystem.balanceGradient,
), ),
), ),
@@ -59,7 +59,7 @@ class HistoryCaptain extends StatelessWidget {
child: Icon( child: Icon(
Icons.history_rounded, Icons.history_rounded,
size: 200, size: 200,
color: Colors.white.withOpacity(0.05), color: Colors.white.withValues(alpha: 0.05),
), ),
), ),
Column( Column(
@@ -77,7 +77,7 @@ class HistoryCaptain extends StatelessWidget {
Text( Text(
'Total Rides'.tr, 'Total Rides'.tr,
style: TextStyle( style: TextStyle(
color: Colors.white.withOpacity(0.7), color: Colors.white.withValues(alpha: 0.7),
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
@@ -203,7 +203,7 @@ class _TripHistoryCard extends StatelessWidget {
borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius), borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Colors.black.withOpacity(0.04), color: Colors.black.withValues(alpha: 0.04),
blurRadius: 15, blurRadius: 15,
offset: const Offset(0, 8), offset: const Offset(0, 8),
), ),
@@ -227,10 +227,10 @@ class _TripHistoryCard extends StatelessWidget {
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
decoration: BoxDecoration( decoration: BoxDecoration(
color: FinanceDesignSystem.primaryDark color: FinanceDesignSystem.primaryDark
.withOpacity(0.05), .withValues(alpha: 0.05),
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
child: const Icon( child: Icon(
Icons.receipt_long_rounded, Icons.receipt_long_rounded,
color: FinanceDesignSystem.primaryDark, color: FinanceDesignSystem.primaryDark,
size: 20, size: 20,
@@ -242,7 +242,7 @@ class _TripHistoryCard extends StatelessWidget {
children: [ children: [
Text( Text(
'${'OrderId'.tr} #${trip['order_id']}', '${'OrderId'.tr} #${trip['order_id']}',
style: const TextStyle( style: TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 15, fontSize: 15,
color: FinanceDesignSystem.primaryDark, color: FinanceDesignSystem.primaryDark,
@@ -269,14 +269,14 @@ class _TripHistoryCard extends StatelessWidget {
children: [ children: [
Column( Column(
children: [ children: [
const Icon(Icons.circle, Icon(Icons.circle,
size: 12, color: FinanceDesignSystem.accentBlue), size: 12, color: FinanceDesignSystem.accentBlue),
Container( Container(
width: 2, width: 2,
height: 20, height: 20,
color: Colors.grey.shade200, color: Colors.grey.shade200,
), ),
const Icon(Icons.location_on_rounded, Icon(Icons.location_on_rounded,
size: 14, color: FinanceDesignSystem.dangerRed), size: 14, color: FinanceDesignSystem.dangerRed),
], ],
), ),
@@ -315,7 +315,7 @@ class _TripHistoryCard extends StatelessWidget {
children: [ children: [
Text( Text(
'${trip['price']} ${'SYP'.tr}', '${trip['price']} ${'SYP'.tr}',
style: const TextStyle( style: TextStyle(
fontWeight: FontWeight.w900, fontWeight: FontWeight.w900,
fontSize: 16, fontSize: 16,
color: FinanceDesignSystem.primaryDark, color: FinanceDesignSystem.primaryDark,
@@ -381,10 +381,10 @@ class _TripHistoryCard extends StatelessWidget {
end: Alignment.bottomRight, end: Alignment.bottomRight,
), ),
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
border: Border.all(color: color.withOpacity(0.3), width: 1), border: Border.all(color: color.withValues(alpha: 0.3), width: 1),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: color.withOpacity(0.1), color: color.withValues(alpha: 0.1),
blurRadius: 4, blurRadius: 4,
offset: const Offset(0, 2), offset: const Offset(0, 2),
), ),

View File

@@ -106,10 +106,10 @@ class AppDrawer extends StatelessWidget {
color: Colors.cyan, color: Colors.cyan,
onTap: () => Get.to(() => HelpCaptain())), onTap: () => Get.to(() => HelpCaptain())),
DrawerItem( DrawerItem(
title: 'Referral Center'.tr, title: 'Invite Driver'.tr,
icon: Icons.card_giftcard_rounded, icon: Icons.person_add_rounded,
color: Colors.indigo, color: Colors.indigo,
onTap: () => Get.to(() => ReferralCenterPage())), onTap: () => Get.to(() => InviteScreen())),
// DrawerItem( // DrawerItem(
// title: 'Maintenance Center'.tr, // title: 'Maintenance Center'.tr,
// icon: Icons.build, // icon: Icons.build,
@@ -227,7 +227,7 @@ class _DrawerItemTile extends StatelessWidget {
leading: Container( leading: Container(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: item.color.withOpacity(0.1), color: item.color.withValues(alpha: 0.1),
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: Icon(item.icon, color: item.color, size: 24), child: Icon(item.icon, color: item.color, size: 24),
@@ -240,13 +240,13 @@ class _DrawerItemTile extends StatelessWidget {
?.copyWith(fontWeight: FontWeight.w500), ?.copyWith(fontWeight: FontWeight.w500),
), ),
onTap: () { onTap: () {
Get.back(); // لإغلاق القائمة عند الضغط Navigator.pop(context); // لإغلاق القائمة عند الضغط بشكل آمن
Future.delayed(const Duration(milliseconds: 250), () { Future.delayed(const Duration(milliseconds: 250), () {
item.onTap(); // الانتقال للصفحة بعد تأخير بسيط لإظهار الأنيميشن item.onTap(); // الانتقال للصفحة بعد تأخير بسيط لإظهار الأنيميشن
}); });
}, },
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
splashColor: item.color.withOpacity(0.2), splashColor: item.color.withValues(alpha: 0.2),
), ),
); );
} }
@@ -327,7 +327,7 @@ class UserHeader extends StatelessWidget {
shape: BoxShape.circle, shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 2), border: Border.all(color: Colors.white, width: 2),
boxShadow: [ boxShadow: [
BoxShadow(color: Colors.black.withOpacity(0.3), blurRadius: 5) BoxShadow(color: Colors.black.withValues(alpha: 0.3), blurRadius: 5)
], ],
), ),
child: controller.isloading child: controller.isloading
@@ -377,19 +377,22 @@ class UserHeader extends StatelessWidget {
), ),
), ),
otherAccountsPictures: [ otherAccountsPictures: [
Row( SizedBox(
mainAxisSize: MainAxisSize.min, width: 60,
children: [ child: Row(
Text( mainAxisAlignment: MainAxisAlignment.end,
homeCaptainController.rating.toString(), children: [
style: const TextStyle( Text(
color: Colors.white, homeCaptainController.rating.toString(),
fontWeight: FontWeight.bold, style: const TextStyle(
fontSize: 16), color: Colors.white,
), fontWeight: FontWeight.bold,
const SizedBox(width: 4), fontSize: 14),
const Icon(Icons.star, color: Colors.amber, size: 20), ),
], const SizedBox(width: 2),
const Icon(Icons.star, color: Colors.amber, size: 16),
],
),
), ),
], ],
decoration: BoxDecoration( decoration: BoxDecoration(

View File

@@ -299,37 +299,38 @@ class _MapView extends StatelessWidget {
return GetBuilder<HomeCaptainController>( return GetBuilder<HomeCaptainController>(
builder: (ctrl) { builder: (ctrl) {
if (ctrl.isLoading) return const MyCircularProgressIndicator(); if (ctrl.isLoading) return const MyCircularProgressIndicator();
final s = Get.find<SettingController>();
return GetBuilder<LocationController>( return GetBuilder<SettingController>(
builder: (loc) => IntaleqMap( builder: (s) => GetBuilder<LocationController>(
apiKey: Env.mapSaasKey, builder: (loc) => IntaleqMap(
onMapCreated: ctrl.onMapCreated, apiKey: Env.mapSaasKey,
minMaxZoomPreference: const MinMaxZoomPreference(6, 18), onMapCreated: ctrl.onMapCreated,
initialCameraPosition: CameraPosition( minMaxZoomPreference: const MinMaxZoomPreference(6, 18),
target: (loc.myLocation.latitude == 0 || initialCameraPosition: CameraPosition(
loc.myLocation.latitude.isNaN) target: (loc.myLocation.latitude == 0 ||
? ctrl.myLocation loc.myLocation.latitude.isNaN)
: loc.myLocation, ? ctrl.myLocation
zoom: 15, : loc.myLocation,
zoom: 15,
),
mapType:
s.isMapDarkMode ? IntaleqMapType.normal : IntaleqMapType.light,
polygons: ctrl.heatmapPolygons,
markers: {
Marker(
markerId: MarkerId('MyLocation'.tr),
position: loc.myLocation,
rotation: loc.heading,
flat: true,
anchor: const Offset(0.5, 0.5),
icon: ctrl.carIcon,
)
},
myLocationButtonEnabled: false,
myLocationEnabled: false,
compassEnabled: false,
zoomControlsEnabled: false,
), ),
mapType:
s.isMapDarkMode ? IntaleqMapType.normal : IntaleqMapType.light,
polygons: ctrl.heatmapPolygons,
markers: {
Marker(
markerId: MarkerId('MyLocation'.tr),
position: loc.myLocation,
rotation: loc.heading,
flat: true,
anchor: const Offset(0.5, 0.5),
icon: ctrl.carIcon,
)
},
myLocationButtonEnabled: false,
myLocationEnabled: false,
compassEnabled: false,
zoomControlsEnabled: false,
), ),
); );
}, },

View File

@@ -12,9 +12,9 @@ class SchedulePage extends StatelessWidget {
return Scaffold( return Scaffold(
backgroundColor: FinanceDesignSystem.backgroundColor, backgroundColor: FinanceDesignSystem.backgroundColor,
appBar: AppBar( appBar: AppBar(
title: Text('My Schedule'.tr, style: const TextStyle(fontWeight: FontWeight.bold, color: FinanceDesignSystem.primaryDark)), title: Text('My Schedule'.tr, style: TextStyle(fontWeight: FontWeight.bold, color: FinanceDesignSystem.primaryDark)),
backgroundColor: Colors.transparent, elevation: 0, centerTitle: true, backgroundColor: Colors.transparent, elevation: 0, centerTitle: true,
leading: IconButton(icon: const Icon(Icons.arrow_back_ios_new_rounded, color: FinanceDesignSystem.primaryDark, size: 20), onPressed: () => Get.back()), leading: IconButton(icon: Icon(Icons.arrow_back_ios_new_rounded, color: FinanceDesignSystem.primaryDark, size: 20), onPressed: () => Get.back()),
), ),
body: GetBuilder<ScheduleController>(builder: (sc) { body: GetBuilder<ScheduleController>(builder: (sc) {
return SingleChildScrollView( return SingleChildScrollView(
@@ -29,14 +29,14 @@ class SchedulePage extends StatelessWidget {
), ),
child: Row(children: [ child: Row(children: [
Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text('Weekly Plan'.tr, style: TextStyle(color: Colors.white.withOpacity(0.7), fontSize: 14)), Text('Weekly Plan'.tr, style: TextStyle(color: Colors.white.withValues(alpha: 0.7), fontSize: 14)),
const SizedBox(height: 8), const SizedBox(height: 8),
Text('${sc.totalWeeklyHours.toStringAsFixed(1)}h', style: const TextStyle(fontSize: 32, fontWeight: FontWeight.w900, color: Colors.white)), Text('${sc.totalWeeklyHours.toStringAsFixed(1)}h', style: const TextStyle(fontSize: 32, fontWeight: FontWeight.w900, color: Colors.white)),
Text('${sc.activeDays} ${'Days'.tr}', style: TextStyle(color: Colors.white.withOpacity(0.6), fontSize: 13)), Text('${sc.activeDays} ${'Days'.tr}', style: TextStyle(color: Colors.white.withValues(alpha: 0.6), fontSize: 13)),
])), ])),
Container( Container(
padding: const EdgeInsets.all(14), padding: const EdgeInsets.all(14),
decoration: BoxDecoration(color: Colors.white.withOpacity(0.15), borderRadius: BorderRadius.circular(14)), decoration: BoxDecoration(color: Colors.white.withValues(alpha: 0.15), borderRadius: BorderRadius.circular(14)),
child: const Icon(Icons.calendar_today_rounded, color: Colors.white, size: 28), child: const Icon(Icons.calendar_today_rounded, color: Colors.white, size: 28),
), ),
]), ]),
@@ -61,7 +61,7 @@ class SchedulePage extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: slot.isActive ? Colors.white : Colors.grey.shade50, color: slot.isActive ? Colors.white : Colors.grey.shade50,
borderRadius: BorderRadius.circular(14), borderRadius: BorderRadius.circular(14),
boxShadow: slot.isActive ? [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 8, offset: const Offset(0, 3))] : null, boxShadow: slot.isActive ? [BoxShadow(color: Colors.black.withValues(alpha: 0.03), blurRadius: 8, offset: const Offset(0, 3))] : null,
), ),
child: Row(children: [ child: Row(children: [
// Toggle // Toggle
@@ -71,7 +71,7 @@ class SchedulePage extends StatelessWidget {
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
width: 44, height: 44, width: 44, height: 44,
decoration: BoxDecoration( decoration: BoxDecoration(
color: slot.isActive ? FinanceDesignSystem.accentBlue.withOpacity(0.1) : Colors.grey.shade200, color: slot.isActive ? FinanceDesignSystem.accentBlue.withValues(alpha: 0.1) : Colors.grey.shade200,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
child: Center(child: Text( child: Center(child: Text(
@@ -102,7 +102,7 @@ class SchedulePage extends StatelessWidget {
Switch( Switch(
value: slot.isActive, value: slot.isActive,
onChanged: (_) => sc.toggleDay(slot.dayOfWeek), onChanged: (_) => sc.toggleDay(slot.dayOfWeek),
activeColor: FinanceDesignSystem.accentBlue, activeThumbColor: FinanceDesignSystem.accentBlue,
), ),
]), ]),
); );

View File

@@ -1,8 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:sefer_driver/constant/colors.dart';
import 'package:sefer_driver/constant/style.dart';
import 'package:sefer_driver/constant/finance_design_system.dart'; import 'package:sefer_driver/constant/finance_design_system.dart';
import 'package:sefer_driver/views/widgets/mycircular.dart'; import 'package:sefer_driver/views/widgets/mycircular.dart';
import '../../../controller/payment/driver_payment_controller.dart'; import '../../../controller/payment/driver_payment_controller.dart';
@@ -19,12 +17,12 @@ class PaymentHistoryDriverPage extends StatelessWidget {
backgroundColor: FinanceDesignSystem.backgroundColor, backgroundColor: FinanceDesignSystem.backgroundColor,
appBar: AppBar( appBar: AppBar(
title: Text('Payment History'.tr, title: Text('Payment History'.tr,
style: const TextStyle(fontWeight: FontWeight.bold, color: FinanceDesignSystem.primaryDark)), style: TextStyle(fontWeight: FontWeight.bold, color: FinanceDesignSystem.primaryDark)),
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
elevation: 0, elevation: 0,
centerTitle: true, centerTitle: true,
leading: IconButton( leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new_rounded, color: FinanceDesignSystem.primaryDark, size: 20), icon: Icon(Icons.arrow_back_ios_new_rounded, color: FinanceDesignSystem.primaryDark, size: 20),
onPressed: () => Get.back(), onPressed: () => Get.back(),
), ),
), ),

View File

@@ -3,8 +3,6 @@ import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:local_auth/local_auth.dart'; import 'package:local_auth/local_auth.dart';
import 'package:sefer_driver/constant/colors.dart';
import 'package:sefer_driver/constant/style.dart';
import 'package:sefer_driver/controller/home/payment/captain_wallet_controller.dart'; import 'package:sefer_driver/controller/home/payment/captain_wallet_controller.dart';
import 'package:sefer_driver/controller/payment/payment_controller.dart'; import 'package:sefer_driver/controller/payment/payment_controller.dart';
import 'package:sefer_driver/controller/payment/smsPaymnet/payment_services.dart'; import 'package:sefer_driver/controller/payment/smsPaymnet/payment_services.dart';
@@ -45,7 +43,7 @@ class PointsCaptain extends StatelessWidget {
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
elevation: 4, elevation: 4,
shadowColor: kolor.withOpacity(0.3), shadowColor: kolor.withValues(alpha: 0.3),
child: InkWell( child: InkWell(
onTap: () => _showPaymentOptions(context), onTap: () => _showPaymentOptions(context),
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
@@ -58,11 +56,12 @@ class PointsCaptain extends StatelessWidget {
begin: Alignment.topLeft, begin: Alignment.topLeft,
end: Alignment.bottomRight, end: Alignment.bottomRight,
colors: [ colors: [
kolor.withOpacity(0.05), kolor.withValues(alpha: 0.05),
Colors.white, Colors.white,
], ],
), ),
border: Border.all(color: kolor.withOpacity(0.2), width: 1.5), border:
Border.all(color: kolor.withValues(alpha: 0.2), width: 1.5),
), ),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@@ -70,7 +69,7 @@ class PointsCaptain extends StatelessWidget {
Container( Container(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
decoration: BoxDecoration( decoration: BoxDecoration(
color: kolor.withOpacity(0.1), color: kolor.withValues(alpha: 0.1),
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: Icon(Icons.account_balance_wallet_rounded, child: Icon(Icons.account_balance_wallet_rounded,
@@ -79,7 +78,7 @@ class PointsCaptain extends StatelessWidget {
const SizedBox(height: 10), const SizedBox(height: 10),
Text( Text(
'$countPoint ${'SYP'.tr}', '$countPoint ${'SYP'.tr}',
style: const TextStyle( style: TextStyle(
fontWeight: FontWeight.w900, fontWeight: FontWeight.w900,
fontSize: 15, fontSize: 15,
color: FinanceDesignSystem.primaryDark, color: FinanceDesignSystem.primaryDark,
@@ -110,9 +109,9 @@ class PointsCaptain extends StatelessWidget {
maxHeight: MediaQuery.of(context).size.height * 0.8, maxHeight: MediaQuery.of(context).size.height * 0.8,
), ),
padding: const EdgeInsets.fromLTRB(24, 24, 24, 32), padding: const EdgeInsets.fromLTRB(24, 24, 24, 32),
decoration: const BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(32)), borderRadius: const BorderRadius.vertical(top: Radius.circular(32)),
), ),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
@@ -131,8 +130,7 @@ class PointsCaptain extends StatelessWidget {
], ],
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
Text( Text("${'Amount to charge:'.tr} $countPoint ${'SYP'.tr}",
"${'Amount to charge:'.tr} $countPoint ${'SYP'.tr}",
style: FinanceDesignSystem.subHeadingStyle), style: FinanceDesignSystem.subHeadingStyle),
const SizedBox(height: 24), const SizedBox(height: 24),
_buildPaymentMethodTile( _buildPaymentMethodTile(
@@ -211,7 +209,7 @@ class PointsCaptain extends StatelessWidget {
borderRadius: BorderRadius.circular(14), borderRadius: BorderRadius.circular(14),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: color.withOpacity(0.1), color: color.withValues(alpha: 0.1),
blurRadius: 10, blurRadius: 10,
offset: const Offset(0, 4), offset: const Offset(0, 4),
), ),
@@ -227,7 +225,7 @@ class PointsCaptain extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text(title, Text(title,
style: const TextStyle( style: TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 16, fontSize: 16,
color: FinanceDesignSystem.primaryDark)), color: FinanceDesignSystem.primaryDark)),
@@ -285,8 +283,7 @@ class PaymentScreen extends StatefulWidget {
final String countPrice; final String countPrice;
const PaymentScreen( const PaymentScreen(
{required this.iframeUrl, Key? key, required this.countPrice}) {required this.iframeUrl, super.key, required this.countPrice});
: super(key: key);
@override @override
State<PaymentScreen> createState() => _PaymentScreenState(); State<PaymentScreen> createState() => _PaymentScreenState();
@@ -439,8 +436,7 @@ class PaymentScreenWallet extends StatefulWidget {
final String countPrice; final String countPrice;
const PaymentScreenWallet( const PaymentScreenWallet(
{required this.iframeUrl, Key? key, required this.countPrice}) {required this.iframeUrl, super.key, required this.countPrice});
: super(key: key);
@override @override
State<PaymentScreenWallet> createState() => _PaymentScreenWalletState(); State<PaymentScreenWallet> createState() => _PaymentScreenWalletState();
@@ -472,7 +468,7 @@ class _PaymentScreenWalletState extends State<PaymentScreenWallet> {
} }
Future<void> _fetchPaymentStatus() async { Future<void> _fetchPaymentStatus() async {
final String userId = '+963' + box.read(BoxName.phoneWallet); final String userId = '+963${box.read(BoxName.phoneWallet)}';
await Future.delayed(const Duration(seconds: 2)); await Future.delayed(const Duration(seconds: 2));
try { try {

View File

@@ -36,20 +36,20 @@ class WalletCaptainRefactored extends StatelessWidget {
backgroundColor: FinanceDesignSystem.backgroundColor, backgroundColor: FinanceDesignSystem.backgroundColor,
appBar: AppBar( appBar: AppBar(
title: Text('Driver Balance'.tr, title: Text('Driver Balance'.tr,
style: const TextStyle( style: TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: FinanceDesignSystem.primaryDark)), color: FinanceDesignSystem.primaryDark)),
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
elevation: 0, elevation: 0,
centerTitle: true, centerTitle: true,
leading: IconButton( leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new_rounded, icon: Icon(Icons.arrow_back_ios_new_rounded,
color: FinanceDesignSystem.primaryDark, size: 20), color: FinanceDesignSystem.primaryDark, size: 20),
onPressed: () => Get.back(), onPressed: () => Get.back(),
), ),
actions: [ actions: [
IconButton( IconButton(
icon: const Icon(Icons.refresh_rounded, icon: Icon(Icons.refresh_rounded,
color: FinanceDesignSystem.primaryDark), color: FinanceDesignSystem.primaryDark),
onPressed: () => controller.refreshCaptainWallet(), onPressed: () => controller.refreshCaptainWallet(),
tooltip: 'Refresh'.tr, tooltip: 'Refresh'.tr,
@@ -204,7 +204,7 @@ class WalletCaptainRefactored extends StatelessWidget {
Get.to(() => const PaymentHistoryDriverPage()); Get.to(() => const PaymentHistoryDriverPage());
}, },
child: Text('View All'.tr, child: Text('View All'.tr,
style: const TextStyle( style: TextStyle(
color: FinanceDesignSystem.accentBlue, color: FinanceDesignSystem.accentBlue,
fontWeight: FontWeight.bold)), fontWeight: FontWeight.bold)),
), ),
@@ -255,9 +255,9 @@ class WalletCaptainRefactored extends StatelessWidget {
Get.bottomSheet( Get.bottomSheet(
Container( Container(
padding: const EdgeInsets.all(24), padding: const EdgeInsets.all(24),
decoration: const BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(24)), borderRadius: const BorderRadius.vertical(top: Radius.circular(24)),
), ),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@@ -272,9 +272,10 @@ class WalletCaptainRefactored extends StatelessWidget {
leading: Container( leading: Container(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
decoration: BoxDecoration( decoration: BoxDecoration(
color: FinanceDesignSystem.accentBlue.withOpacity(0.1), color:
FinanceDesignSystem.accentBlue.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(12)), borderRadius: BorderRadius.circular(12)),
child: const Icon(Icons.account_balance_wallet_rounded, child: Icon(Icons.account_balance_wallet_rounded,
color: FinanceDesignSystem.accentBlue), color: FinanceDesignSystem.accentBlue),
), ),
title: Text("Pay from my budget".tr), title: Text("Pay from my budget".tr),

View File

@@ -1,9 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:sefer_driver/constant/colors.dart'; import 'package:get/get.dart';
import 'package:sefer_driver/constant/style.dart';
import 'package:sefer_driver/constant/finance_design_system.dart'; import 'package:sefer_driver/constant/finance_design_system.dart';
import 'package:sefer_driver/views/widgets/mycircular.dart'; import 'package:sefer_driver/views/widgets/mycircular.dart';
import '../../../controller/payment/driver_payment_controller.dart'; import '../../../controller/payment/driver_payment_controller.dart';
@@ -20,12 +17,15 @@ class WeeklyPaymentPage extends StatelessWidget {
backgroundColor: FinanceDesignSystem.backgroundColor, backgroundColor: FinanceDesignSystem.backgroundColor,
appBar: AppBar( appBar: AppBar(
title: Text('Weekly Summary'.tr, title: Text('Weekly Summary'.tr,
style: const TextStyle(fontWeight: FontWeight.bold, color: FinanceDesignSystem.primaryDark)), style: TextStyle(
fontWeight: FontWeight.bold,
color: FinanceDesignSystem.primaryDark)),
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
elevation: 0, elevation: 0,
centerTitle: true, centerTitle: true,
leading: IconButton( leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new_rounded, color: FinanceDesignSystem.primaryDark, size: 20), icon: Icon(Icons.arrow_back_ios_new_rounded,
color: FinanceDesignSystem.primaryDark, size: 20),
onPressed: () => Get.back(), onPressed: () => Get.back(),
), ),
), ),
@@ -45,9 +45,11 @@ class WeeklyPaymentPage extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: 20), padding: const EdgeInsets.symmetric(horizontal: 20),
child: Row( child: Row(
children: [ children: [
Text('Transactions this week'.tr, style: FinanceDesignSystem.headingStyle), Text('Transactions this week'.tr,
style: FinanceDesignSystem.headingStyle),
const Spacer(), const Spacer(),
Icon(Icons.list_rounded, color: Colors.grey.shade400, size: 20), Icon(Icons.list_rounded,
color: Colors.grey.shade400, size: 20),
], ],
), ),
), ),
@@ -61,7 +63,9 @@ class WeeklyPaymentPage extends StatelessWidget {
itemCount: controller.weeklyList.length, itemCount: controller.weeklyList.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
final tx = controller.weeklyList[index]; final tx = controller.weeklyList[index];
final double amount = double.tryParse(tx['amount']?.toString() ?? '0') ?? 0; final double amount = double.tryParse(
tx['amount']?.toString() ?? '0') ??
0;
return AnimationConfiguration.staggeredList( return AnimationConfiguration.staggeredList(
position: index, position: index,
duration: const Duration(milliseconds: 250), duration: const Duration(milliseconds: 250),
@@ -69,10 +73,12 @@ class WeeklyPaymentPage extends StatelessWidget {
verticalOffset: 25, verticalOffset: 25,
child: FadeInAnimation( child: FadeInAnimation(
child: TransactionPreviewItem( child: TransactionPreviewItem(
title: amount >= 0 ? 'Credit'.tr : 'Debit'.tr, title:
amount >= 0 ? 'Credit'.tr : 'Debit'.tr,
subtitle: tx['dateUpdated'] ?? '', subtitle: tx['dateUpdated'] ?? '',
amount: amount.abs().toStringAsFixed(0), amount: amount.abs().toStringAsFixed(0),
date: tx['dateUpdated']?.split(' ')[0] ?? '', date:
tx['dateUpdated']?.split(' ')[0] ?? '',
type: amount >= 0 ? 'credit' : 'debit', type: amount >= 0 ? 'credit' : 'debit',
method: tx['paymentMethod'], method: tx['paymentMethod'],
onTap: () {}, onTap: () {},
@@ -95,7 +101,7 @@ class WeeklyPaymentPage extends StatelessWidget {
final totalAmount = controller.weeklyList.isEmpty final totalAmount = controller.weeklyList.isEmpty
? '0.00' ? '0.00'
: controller.weeklyList[0]['totalAmount']?.toString() ?? '0.00'; : controller.weeklyList[0]['totalAmount']?.toString() ?? '0.00';
final double earnings = double.tryParse(totalAmount) ?? 0; final double earnings = double.tryParse(totalAmount) ?? 0;
final int trips = controller.weeklyList.length; final int trips = controller.weeklyList.length;
final double commission = earnings * 0.15; // Example 15% final double commission = earnings * 0.15; // Example 15%
@@ -109,7 +115,7 @@ class WeeklyPaymentPage extends StatelessWidget {
borderRadius: BorderRadius.circular(24), borderRadius: BorderRadius.circular(24),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: FinanceDesignSystem.primaryDark.withOpacity(0.3), color: FinanceDesignSystem.primaryDark.withValues(alpha: 0.3),
blurRadius: 20, blurRadius: 20,
offset: const Offset(0, 8), offset: const Offset(0, 8),
), ),
@@ -118,17 +124,24 @@ class WeeklyPaymentPage extends StatelessWidget {
child: Column( child: Column(
children: [ children: [
Text('Total Weekly Earnings'.tr, Text('Total Weekly Earnings'.tr,
style: TextStyle(color: Colors.white.withOpacity(0.8), fontSize: 14)), style: TextStyle(
color: Colors.white.withValues(alpha: 0.8), fontSize: 14)),
const SizedBox(height: 8), const SizedBox(height: 8),
Text('${earnings.toStringAsFixed(0)} SYP', Text('${earnings.toStringAsFixed(0)} SYP',
style: const TextStyle(color: Colors.white, fontSize: 36, fontWeight: FontWeight.bold)), style: const TextStyle(
color: Colors.white,
fontSize: 36,
fontWeight: FontWeight.bold)),
const SizedBox(height: 24), const SizedBox(height: 24),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
_buildStatItem('Total Trips'.tr, trips.toString(), Icons.directions_car_rounded), _buildStatItem('Total Trips'.tr, trips.toString(),
_buildStatItem('Commission'.tr, '${commission.toStringAsFixed(0)}', Icons.percent_rounded), Icons.directions_car_rounded),
_buildStatItem('Net Profit'.tr, '${netProfit.toStringAsFixed(0)}', Icons.account_balance_rounded), _buildStatItem('Commission'.tr, commission.toStringAsFixed(0),
Icons.percent_rounded),
_buildStatItem('Net Profit'.tr, netProfit.toStringAsFixed(0),
Icons.account_balance_rounded),
], ],
), ),
], ],
@@ -141,12 +154,20 @@ class WeeklyPaymentPage extends StatelessWidget {
children: [ children: [
Container( Container(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
decoration: BoxDecoration(color: Colors.white.withOpacity(0.1), borderRadius: BorderRadius.circular(10)), decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(10)),
child: Icon(icon, color: Colors.white, size: 18), child: Icon(icon, color: Colors.white, size: 18),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
Text(value, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 14)), Text(value,
Text(label, style: TextStyle(color: Colors.white.withOpacity(0.6), fontSize: 10)), style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 14)),
Text(label,
style: TextStyle(
color: Colors.white.withValues(alpha: 0.6), fontSize: 10)),
], ],
); );
} }
@@ -159,18 +180,27 @@ class WeeklyPaymentPage extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.02), blurRadius: 10)], boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.02), blurRadius: 10)
],
), ),
child: Row( child: Row(
children: [ children: [
IconButton(icon: const Icon(Icons.chevron_left_rounded), onPressed: () {}), IconButton(
icon: const Icon(Icons.chevron_left_rounded), onPressed: () {}),
Expanded( Expanded(
child: Center( child: Center(
child: Text('Dec 15 - Dec 21, 2024'.tr, child: Text('Dec 15 - Dec 21, 2024'.tr,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 14, color: FinanceDesignSystem.primaryDark)), style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: FinanceDesignSystem.primaryDark)),
), ),
), ),
IconButton(icon: const Icon(Icons.chevron_right_rounded), onPressed: () {}), IconButton(
icon: const Icon(Icons.chevron_right_rounded),
onPressed: () {}),
], ],
), ),
), ),
@@ -184,7 +214,9 @@ class WeeklyPaymentPage extends StatelessWidget {
children: [ children: [
Icon(Icons.bar_chart_rounded, size: 64, color: Colors.grey.shade300), Icon(Icons.bar_chart_rounded, size: 64, color: Colors.grey.shade300),
const SizedBox(height: 16), const SizedBox(height: 16),
Text('No transactions this week'.tr, style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.grey)), Text('No transactions this week'.tr,
style: const TextStyle(
fontWeight: FontWeight.bold, color: Colors.grey)),
], ],
), ),
); );

View File

@@ -40,7 +40,7 @@ class FinancialSummaryCard extends StatelessWidget {
borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius), borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Colors.black.withOpacity(0.03), color: Colors.black.withValues(alpha: 0.03),
blurRadius: 10, blurRadius: 10,
offset: const Offset(0, 4), offset: const Offset(0, 4),
), ),
@@ -51,7 +51,7 @@ class FinancialSummaryCard extends StatelessWidget {
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemCount: items.length, itemCount: items.length,
separatorBuilder: (context, index) => separatorBuilder: (context, index) =>
Divider(color: Colors.grey.withOpacity(0.1), height: 24), Divider(color: Colors.grey.withValues(alpha: 0.1), height: 24),
itemBuilder: (context, index) { itemBuilder: (context, index) {
final item = items[index]; final item = items[index];
return Row( return Row(
@@ -59,7 +59,7 @@ class FinancialSummaryCard extends StatelessWidget {
Container( Container(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
decoration: BoxDecoration( decoration: BoxDecoration(
color: item.color.withOpacity(0.1), color: item.color.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
), ),
child: Icon(item.icon, color: item.color, size: 20), child: Icon(item.icon, color: item.color, size: 20),
@@ -71,7 +71,7 @@ class FinancialSummaryCard extends StatelessWidget {
children: [ children: [
Text( Text(
item.label, item.label,
style: const TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: FinanceDesignSystem.primaryDark, color: FinanceDesignSystem.primaryDark,
@@ -93,7 +93,7 @@ class FinancialSummaryCard extends StatelessWidget {
children: [ children: [
Text( Text(
"${item.amount} ${'SYP'.tr}", "${item.amount} ${'SYP'.tr}",
style: const TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: FinanceDesignSystem.primaryDark, color: FinanceDesignSystem.primaryDark,

View File

@@ -50,7 +50,7 @@ class PromoGamificationCard extends StatelessWidget {
children: [ children: [
Text( Text(
title, title,
style: const TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: FinanceDesignSystem.primaryDark, color: FinanceDesignSystem.primaryDark,

View File

@@ -96,7 +96,7 @@ class _ActionItem extends StatelessWidget {
const SizedBox(height: 8), const SizedBox(height: 8),
Text( Text(
label, label,
style: const TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: FinanceDesignSystem.primaryDark, color: FinanceDesignSystem.primaryDark,

View File

@@ -59,7 +59,7 @@ class TransactionPreviewItem extends StatelessWidget {
children: [ children: [
Text( Text(
title, title,
style: const TextStyle( style: TextStyle(
fontSize: 15, fontSize: 15,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: FinanceDesignSystem.primaryDark, color: FinanceDesignSystem.primaryDark,

View File

@@ -15,27 +15,36 @@ class BehaviorPage extends StatelessWidget {
return Scaffold( return Scaffold(
backgroundColor: FinanceDesignSystem.backgroundColor, backgroundColor: FinanceDesignSystem.backgroundColor,
appBar: AppBar( appBar: AppBar(
title: Text('Driver Behavior'.tr, style: const TextStyle(fontWeight: FontWeight.bold, color: FinanceDesignSystem.primaryDark)), title: Text('Driver Behavior'.tr,
style: TextStyle(
fontWeight: FontWeight.bold,
color: FinanceDesignSystem.primaryDark)),
centerTitle: true, centerTitle: true,
backgroundColor: FinanceDesignSystem.cardColor, backgroundColor: FinanceDesignSystem.cardColor,
elevation: 0, elevation: 0,
iconTheme: const IconThemeData(color: FinanceDesignSystem.primaryDark), iconTheme: IconThemeData(color: FinanceDesignSystem.primaryDark),
), ),
body: Obx(() { body: Obx(() {
if (controller.isLoading.value) { if (controller.isLoading.value) {
return const Center(child: CircularProgressIndicator(color: FinanceDesignSystem.accentBlue)); return Center(
child: CircularProgressIndicator(
color: FinanceDesignSystem.accentBlue));
} }
double score = controller.overallScore.value; double score = controller.overallScore.value;
bool isExcellent = score >= 90; bool isExcellent = score >= 90;
bool isGood = score >= 75 && score < 90; bool isGood = score >= 75 && score < 90;
Color statusColor = isExcellent ? Colors.green : (isGood ? Colors.orange : Colors.red); Color statusColor =
String statusText = isExcellent ? 'Excellent'.tr : (isGood ? 'Good'.tr : 'Needs Improvement'.tr); isExcellent ? Colors.green : (isGood ? Colors.orange : Colors.red);
String statusText = isExcellent
? 'Excellent'.tr
: (isGood ? 'Good'.tr : 'Needs Improvement'.tr);
return CustomScrollView( return CustomScrollView(
slivers: [ slivers: [
SliverPadding( SliverPadding(
padding: const EdgeInsets.all(FinanceDesignSystem.horizontalPadding), padding:
const EdgeInsets.all(FinanceDesignSystem.horizontalPadding),
sliver: SliverList( sliver: SliverList(
delegate: SliverChildListDelegate([ delegate: SliverChildListDelegate([
// Overall Score Card // Overall Score Card
@@ -44,11 +53,17 @@ class BehaviorPage extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: FinanceDesignSystem.cardColor, color: FinanceDesignSystem.cardColor,
borderRadius: BorderRadius.circular(24), borderRadius: BorderRadius.circular(24),
boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 10, offset: Offset(0, 4))], boxShadow: const [
BoxShadow(
color: Colors.black12,
blurRadius: 10,
offset: Offset(0, 4))
],
), ),
child: Column( child: Column(
children: [ children: [
Icon(Icons.shield_rounded, size: 48, color: statusColor), Icon(Icons.shield_rounded,
size: 48, color: statusColor),
const SizedBox(height: 16), const SizedBox(height: 16),
Text( Text(
"Overall Behavior Score".tr, "Overall Behavior Score".tr,
@@ -65,33 +80,41 @@ class BehaviorPage extends StatelessWidget {
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6), padding: const EdgeInsets.symmetric(
horizontal: 16, vertical: 6),
decoration: BoxDecoration( decoration: BoxDecoration(
color: statusColor.withValues(alpha: 0.1), color: statusColor.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
), ),
child: Text( child: Text(
statusText, statusText,
style: TextStyle(color: statusColor, fontWeight: FontWeight.bold), style: TextStyle(
color: statusColor,
fontWeight: FontWeight.bold),
), ),
), ),
], ],
), ),
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
Text("Last 10 Trips".tr, style: FinanceDesignSystem.headingStyle), Text("Last 10 Trips".tr,
style: FinanceDesignSystem.headingStyle),
const SizedBox(height: 16), const SizedBox(height: 16),
]), ]),
), ),
), ),
SliverPadding( SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: FinanceDesignSystem.horizontalPadding), padding: const EdgeInsets.symmetric(
horizontal: FinanceDesignSystem.horizontalPadding),
sliver: SliverList( sliver: SliverList(
delegate: SliverChildBuilderDelegate( delegate: SliverChildBuilderDelegate(
(context, index) { (context, index) {
var trip = controller.lastTrips[index]; var trip = controller.lastTrips[index];
double tripScore = double.tryParse(trip['behavior_score'].toString()) ?? 0; double tripScore =
Color tColor = tripScore >= 90 ? Colors.green : (tripScore >= 75 ? Colors.orange : Colors.red); double.tryParse(trip['behavior_score'].toString()) ?? 0;
Color tColor = tripScore >= 90
? Colors.green
: (tripScore >= 75 ? Colors.orange : Colors.red);
return Container( return Container(
margin: const EdgeInsets.only(bottom: 12), margin: const EdgeInsets.only(bottom: 12),
@@ -118,7 +141,8 @@ class BehaviorPage extends StatelessWidget {
), ),
title: Text( title: Text(
"Trip ID: ${trip['trip_id']}", "Trip ID: ${trip['trip_id']}",
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16), style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 16),
), ),
subtitle: Padding( subtitle: Padding(
padding: const EdgeInsets.only(top: 8.0), padding: const EdgeInsets.only(top: 8.0),
@@ -126,9 +150,16 @@ class BehaviorPage extends StatelessWidget {
spacing: 12, spacing: 12,
runSpacing: 8, runSpacing: 8,
children: [ children: [
_buildBadge(Icons.speed, "${trip['max_speed']} km/h", Colors.blue), _buildBadge(Icons.speed,
_buildBadge(Icons.warning_amber_rounded, "${trip['hard_brakes']} ${'Hard Brakes'.tr}", Colors.orange), "${trip['max_speed']} km/h", Colors.blue),
_buildBadge(Icons.map_rounded, "${trip['total_distance']} km", Colors.purple), _buildBadge(
Icons.warning_amber_rounded,
"${trip['hard_brakes']} ${'Hard Brakes'.tr}",
Colors.orange),
_buildBadge(
Icons.map_rounded,
"${trip['total_distance']} km",
Colors.purple),
], ],
), ),
), ),
@@ -137,9 +168,14 @@ class BehaviorPage extends StatelessWidget {
children: [ children: [
Text( Text(
"${tripScore.toStringAsFixed(0)}", "${tripScore.toStringAsFixed(0)}",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20, color: tColor), style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
color: tColor),
), ),
Text('Score'.tr, style: const TextStyle(fontSize: 10, color: Colors.grey)), Text('Score'.tr,
style: const TextStyle(
fontSize: 10, color: Colors.grey)),
], ],
), ),
), ),
@@ -168,7 +204,9 @@ class BehaviorPage extends StatelessWidget {
children: [ children: [
Icon(icon, size: 14, color: color), Icon(icon, size: 14, color: color),
const SizedBox(width: 4), const SizedBox(width: 4),
Text(label, style: TextStyle(fontSize: 12, color: color, fontWeight: FontWeight.w600)), Text(label,
style: TextStyle(
fontSize: 12, color: color, fontWeight: FontWeight.w600)),
], ],
), ),
); );

View File

@@ -16,8 +16,7 @@ class StatisticsDashboard extends StatelessWidget {
final GamificationController gamController = final GamificationController gamController =
Get.put(GamificationController()); Get.put(GamificationController());
final StatisticsController statsController = final StatisticsController statsController = Get.put(StatisticsController());
Get.put(StatisticsController());
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -25,154 +24,160 @@ class StatisticsDashboard extends StatelessWidget {
backgroundColor: FinanceDesignSystem.backgroundColor, backgroundColor: FinanceDesignSystem.backgroundColor,
body: GetBuilder<GamificationController>( body: GetBuilder<GamificationController>(
builder: (gc) { builder: (gc) {
if (gc.isLoading) { return GetBuilder<StatisticsController>(
return const Center( builder: (sc) {
child: CircularProgressIndicator( if (gc.isLoading || sc.isLoading) {
color: FinanceDesignSystem.primaryDark), return Center(
); child: CircularProgressIndicator(
} color: FinanceDesignSystem.primaryDark),
);
}
return CustomScrollView( return CustomScrollView(
physics: const BouncingScrollPhysics(), physics: const BouncingScrollPhysics(),
slivers: [ slivers: [
// ═══════ App Bar ═══════ // ═══════ App Bar ═══════
SliverAppBar( SliverAppBar(
expandedHeight: 200, expandedHeight: 200,
pinned: true, pinned: true,
stretch: true, stretch: true,
backgroundColor: FinanceDesignSystem.primaryDark, backgroundColor: Get.isDarkMode
leading: IconButton( ? FinanceDesignSystem.primaryDark
icon: const Icon(Icons.arrow_back_ios_new_rounded, : const Color(0xFF0A0E21),
color: Colors.white, size: 20), leading: IconButton(
onPressed: () => Get.back(), icon: const Icon(Icons.arrow_back_ios_new_rounded,
), color: Colors.white, size: 20),
actions: [ onPressed: () => Get.back(),
IconButton(
icon: const Icon(Icons.refresh_rounded,
color: Colors.white),
onPressed: () => gc.fetchGamificationData(),
),
],
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
title: Text(
'Statistics'.tr,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 18,
), ),
), actions: [
background: Stack( IconButton(
fit: StackFit.expand, icon: const Icon(Icons.refresh_rounded,
children: [ color: Colors.white),
Container( onPressed: () => gc.fetchGamificationData(),
decoration: const BoxDecoration(
gradient: FinanceDesignSystem.balanceGradient,
),
),
// أيقونة زخرفية
Positioned(
right: -40,
top: -20,
child: Icon(
Icons.bar_chart_rounded,
size: 200,
color: Colors.white.withOpacity(0.04),
),
),
Positioned(
left: -30,
bottom: 20,
child: Icon(
Icons.emoji_events_rounded,
size: 120,
color: Colors.white.withOpacity(0.03),
),
),
// بطاقة المستوى في الهيدر
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(height: 40),
Text(
gc.currentLevel.emoji,
style: const TextStyle(fontSize: 40),
),
const SizedBox(height: 4),
Text(
Get.locale?.languageCode == 'ar'
? gc.currentLevel.nameAr
: gc.currentLevel.nameEn,
style: TextStyle(
color: Colors.white.withOpacity(0.9),
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 2),
Text(
'${gc.unlockedCount}/${gc.totalAchievements} ${'Achievements'.tr}',
style: TextStyle(
color: Colors.white.withOpacity(0.5),
fontSize: 12,
),
),
],
),
), ),
], ],
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
title: Text(
'Statistics'.tr,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
background: Stack(
fit: StackFit.expand,
children: [
Container(
decoration: BoxDecoration(
gradient: FinanceDesignSystem.balanceGradient,
),
),
// أيقونة زخرفية
Positioned(
right: -40,
top: -20,
child: Icon(
Icons.bar_chart_rounded,
size: 200,
color: Colors.white.withOpacity(0.04),
),
),
Positioned(
left: -30,
bottom: 20,
child: Icon(
Icons.emoji_events_rounded,
size: 120,
color: Colors.white.withOpacity(0.03),
),
),
// بطاقة المستوى في الهيدر
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(height: 40),
Text(
gc.currentLevel.emoji,
style: const TextStyle(fontSize: 40),
),
const SizedBox(height: 4),
Text(
Get.locale?.languageCode == 'ar'
? gc.currentLevel.nameAr
: gc.currentLevel.nameEn,
style: TextStyle(
color: Colors.white.withOpacity(0.9),
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 2),
Text(
'${gc.unlockedCount}/${gc.totalAchievements} ${'Achievements'.tr}',
style: TextStyle(
color: Colors.white.withOpacity(0.5),
fontSize: 12,
),
),
],
),
),
],
),
),
), ),
),
),
// ═══════ المحتوى ═══════ // ═══════ المحتوى ═══════
SliverPadding( SliverPadding(
padding: const EdgeInsets.fromLTRB(16, 24, 16, 40), padding: const EdgeInsets.fromLTRB(16, 24, 16, 40),
sliver: SliverList( sliver: SliverList(
delegate: SliverChildListDelegate([ delegate: SliverChildListDelegate([
// 1. بطاقات الإحصائيات الأربعة // 1. بطاقات الإحصائيات الأربعة
_buildSummaryCards(gc), _buildSummaryCards(gc),
const SizedBox( const SizedBox(
height: FinanceDesignSystem.verticalSectionPadding), height: FinanceDesignSystem.verticalSectionPadding),
// 2. الهدف اليومي // 2. الهدف اليومي
DailyGoalWidget(controller: gc), DailyGoalWidget(controller: gc),
const SizedBox( const SizedBox(
height: FinanceDesignSystem.verticalSectionPadding), height: FinanceDesignSystem.verticalSectionPadding),
// 3. تقدم المستوى // 3. تقدم المستوى
LevelProgressWidget(controller: gc), LevelProgressWidget(controller: gc),
const SizedBox( const SizedBox(
height: FinanceDesignSystem.verticalSectionPadding), height: FinanceDesignSystem.verticalSectionPadding),
// 4. إحصائيات اليوم // 4. إحصائيات اليوم
TodayChartWidget(), TodayChartWidget(),
const SizedBox( const SizedBox(
height: FinanceDesignSystem.verticalSectionPadding), height: FinanceDesignSystem.verticalSectionPadding),
// 5. الرسم البياني الأسبوعي // 5. الرسم البياني الأسبوعي
const WeeklyChartWidget(), const WeeklyChartWidget(),
const SizedBox( const SizedBox(
height: FinanceDesignSystem.verticalSectionPadding), height: FinanceDesignSystem.verticalSectionPadding),
// 6. التقرير الشهري // 6. التقرير الشهري
const MonthlyChartWidget(), const MonthlyChartWidget(),
const SizedBox( const SizedBox(
height: FinanceDesignSystem.verticalSectionPadding), height: FinanceDesignSystem.verticalSectionPadding),
// 7. تقييم سلوك القيادة // 7. تقييم سلوك القيادة
_buildBehaviorSection(gc), _buildBehaviorSection(gc),
const SizedBox( const SizedBox(
height: FinanceDesignSystem.verticalSectionPadding), height: FinanceDesignSystem.verticalSectionPadding),
// 8. الإنجازات // 8. الإنجازات
_buildAchievementsSection(gc), _buildAchievementsSection(gc),
]), ]),
), ),
), ),
], ],
);
},
); );
}, },
), ),
@@ -221,21 +226,27 @@ class StatisticsDashboard extends StatelessWidget {
Widget _buildBehaviorSection(GamificationController gc) { Widget _buildBehaviorSection(GamificationController gc) {
bool isExcellent = gc.behaviorScore >= 90; bool isExcellent = gc.behaviorScore >= 90;
bool isGood = gc.behaviorScore >= 75 && gc.behaviorScore < 90; bool isGood = gc.behaviorScore >= 75 && gc.behaviorScore < 90;
Color statusColor = isExcellent
? Colors.green
: isGood ? Colors.orange : Colors.red;
String statusText = isExcellent Color statusColor = isExcellent
? 'Excellent'.tr ? Colors.green
: isGood ? 'Good'.tr : 'Needs Improvement'.tr; : isGood
? Colors.orange
: Colors.red;
String statusText = isExcellent
? 'Excellent'.tr
: isGood
? 'Good'.tr
: 'Needs Improvement'.tr;
return Container( return Container(
padding: const EdgeInsets.all(20), padding: const EdgeInsets.all(20),
decoration: BoxDecoration( decoration: BoxDecoration(
color: FinanceDesignSystem.cardColor, color: FinanceDesignSystem.cardColor,
borderRadius: BorderRadius.circular(24), borderRadius: BorderRadius.circular(24),
boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 10, offset: Offset(0, 4))], boxShadow: const [
BoxShadow(color: Colors.black12, blurRadius: 10, offset: Offset(0, 4))
],
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -245,13 +256,16 @@ class StatisticsDashboard extends StatelessWidget {
children: [ children: [
Row( Row(
children: [ children: [
const Icon(Icons.shield_rounded, color: FinanceDesignSystem.accentBlue), Icon(Icons.shield_rounded,
color: FinanceDesignSystem.accentBlue),
const SizedBox(width: 8), const SizedBox(width: 8),
Text('Driving Behavior'.tr, style: FinanceDesignSystem.headingStyle), Text('Driving Behavior'.tr,
style: FinanceDesignSystem.headingStyle),
], ],
), ),
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), padding:
const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration( decoration: BoxDecoration(
color: statusColor.withOpacity(0.1), color: statusColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
@@ -306,7 +320,11 @@ class StatisticsDashboard extends StatelessWidget {
); );
} }
Widget _behaviorStatItem({required String title, required String value, required IconData icon, required Color color}) { Widget _behaviorStatItem(
{required String title,
required String value,
required IconData icon,
required Color color}) {
return Column( return Column(
children: [ children: [
Container( Container(
@@ -318,18 +336,22 @@ class StatisticsDashboard extends StatelessWidget {
child: Icon(icon, color: color, size: 24), child: Icon(icon, color: color, size: 24),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
Text(value, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16, color: FinanceDesignSystem.primaryDark)), Text(value,
Text(title, style: const TextStyle(fontSize: 12, color: FinanceDesignSystem.textSecondary)), style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
color: FinanceDesignSystem.primaryDark)),
Text(title,
style: TextStyle(
fontSize: 12, color: FinanceDesignSystem.textSecondary)),
], ],
); );
} }
// ═══════ قسم الإنجازات ═══════ // ═══════ قسم الإنجازات ═══════
Widget _buildAchievementsSection(GamificationController gc) { Widget _buildAchievementsSection(GamificationController gc) {
final unlockedAch = final unlockedAch = gc.achievements.where((a) => a.isUnlocked).toList();
gc.achievements.where((a) => a.isUnlocked).toList(); final lockedAch = gc.achievements.where((a) => !a.isUnlocked).toList();
final lockedAch =
gc.achievements.where((a) => !a.isUnlocked).toList();
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -346,7 +368,7 @@ class StatisticsDashboard extends StatelessWidget {
), ),
child: Text( child: Text(
'${gc.unlockedCount}/${gc.totalAchievements}', '${gc.unlockedCount}/${gc.totalAchievements}',
style: const TextStyle( style: TextStyle(
color: FinanceDesignSystem.accentBlue, color: FinanceDesignSystem.accentBlue,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 12, fontSize: 12,
@@ -397,9 +419,8 @@ class StatisticsDashboard extends StatelessWidget {
width: 50, width: 50,
height: 50, height: 50,
decoration: BoxDecoration( decoration: BoxDecoration(
color: unlocked color:
? ach.color.withOpacity(0.15) unlocked ? ach.color.withOpacity(0.15) : Colors.grey.shade200,
: Colors.grey.shade200,
borderRadius: BorderRadius.circular(14), borderRadius: BorderRadius.circular(14),
), ),
child: Icon( child: Icon(

View File

@@ -13,7 +13,7 @@ class DailyGoalWidget extends StatelessWidget {
return Container( return Container(
padding: const EdgeInsets.all(20), padding: const EdgeInsets.all(20),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: FinanceDesignSystem.cardColor,
borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius), borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
@@ -55,17 +55,17 @@ class DailyGoalWidget extends StatelessWidget {
children: [ children: [
Text( Text(
'Daily Goal'.tr, 'Daily Goal'.tr,
style: const TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: FinanceDesignSystem.primaryDark, color: FinanceDesignSystem.primaryDark,
), ),
), ),
Text( Text(
'الهدف اليومي'.tr, 'Daily Goal'.tr,
style: TextStyle( style: TextStyle(
fontSize: 11, fontSize: 11,
color: Colors.grey.shade500, color: FinanceDesignSystem.textSecondary,
), ),
), ),
], ],
@@ -80,13 +80,11 @@ class DailyGoalWidget extends StatelessWidget {
padding: padding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 6), const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.grey.shade100, color: FinanceDesignSystem.backgroundColor,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
child: Text( child: Text(
controller.dailyGoal > 0 controller.dailyGoal > 0 ? 'Edit'.tr : 'Set Goal'.tr,
? 'Edit'.tr
: 'Set Goal'.tr,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@@ -121,7 +119,7 @@ class DailyGoalWidget extends StatelessWidget {
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Colors.grey.shade400, color: FinanceDesignSystem.textMuted,
), ),
), ),
], ],
@@ -135,7 +133,7 @@ class DailyGoalWidget extends StatelessWidget {
height: 12, height: 12,
width: double.infinity, width: double.infinity,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.grey.shade100, color: FinanceDesignSystem.backgroundColor,
borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(6),
), ),
), ),
@@ -197,7 +195,7 @@ class DailyGoalWidget extends StatelessWidget {
const SizedBox(width: 4), const SizedBox(width: 4),
Text( Text(
'Goal Achieved!'.tr, 'Goal Achieved!'.tr,
style: const TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: FinanceDesignSystem.successGreen, color: FinanceDesignSystem.successGreen,
@@ -210,7 +208,7 @@ class DailyGoalWidget extends StatelessWidget {
'${'Remaining:'.tr} ${(controller.dailyGoal - controller.dailyEarnings).clamp(0, double.infinity).toStringAsFixed(0)} ${'SYP'.tr}', '${'Remaining:'.tr} ${(controller.dailyGoal - controller.dailyEarnings).clamp(0, double.infinity).toStringAsFixed(0)} ${'SYP'.tr}',
style: TextStyle( style: TextStyle(
fontSize: 11, fontSize: 11,
color: Colors.grey.shade500, color: FinanceDesignSystem.textSecondary,
), ),
), ),
], ],
@@ -228,6 +226,7 @@ class DailyGoalWidget extends StatelessWidget {
); );
Get.defaultDialog( Get.defaultDialog(
backgroundColor: FinanceDesignSystem.cardColor,
title: 'Set Daily Goal'.tr, title: 'Set Daily Goal'.tr,
titleStyle: FinanceDesignSystem.headingStyle, titleStyle: FinanceDesignSystem.headingStyle,
content: Column( content: Column(
@@ -252,13 +251,11 @@ class DailyGoalWidget extends StatelessWidget {
suffixText: 'SYP'.tr, suffixText: 'SYP'.tr,
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: borderSide: BorderSide(color: FinanceDesignSystem.borderColor),
BorderSide(color: Colors.grey.shade300),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: borderSide: BorderSide(color: FinanceDesignSystem.accentBlue),
const BorderSide(color: FinanceDesignSystem.accentBlue),
), ),
), ),
), ),
@@ -270,7 +267,8 @@ class DailyGoalWidget extends StatelessWidget {
return ActionChip( return ActionChip(
label: Text('$goal'), label: Text('$goal'),
labelStyle: const TextStyle(fontSize: 12), labelStyle: const TextStyle(fontSize: 12),
backgroundColor: FinanceDesignSystem.accentBlue.withOpacity(0.1), backgroundColor:
FinanceDesignSystem.accentBlue.withOpacity(0.1),
side: BorderSide.none, side: BorderSide.none,
onPressed: () { onPressed: () {
textController.text = goal.toString(); textController.text = goal.toString();
@@ -291,16 +289,15 @@ class DailyGoalWidget extends StatelessWidget {
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: FinanceDesignSystem.accentBlue, backgroundColor: FinanceDesignSystem.accentBlue,
foregroundColor: Colors.white, foregroundColor: Colors.white,
shape: RoundedRectangleBorder( shape:
borderRadius: BorderRadius.circular(12)), RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 12), padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 12),
), ),
child: Text('Save'.tr), child: Text('Save'.tr),
), ),
cancel: TextButton( cancel: TextButton(
onPressed: () => Get.back(), onPressed: () => Get.back(),
child: Text('Cancel'.tr, child: Text('Cancel'.tr, style: const TextStyle(color: Colors.grey)),
style: const TextStyle(color: Colors.grey)),
), ),
); );
} }

View File

@@ -17,8 +17,12 @@ class LevelProgressWidget extends StatelessWidget {
padding: const EdgeInsets.all(20), padding: const EdgeInsets.all(20),
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: LinearGradient( gradient: LinearGradient(
colors: [level.color.withOpacity(0.08), level.gradientEnd.withOpacity(0.04)], colors: [
begin: Alignment.topLeft, end: Alignment.bottomRight, level.color.withOpacity(0.08),
level.gradientEnd.withOpacity(0.04)
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
), ),
borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius), borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius),
border: Border.all(color: level.color.withOpacity(0.2), width: 1.5), border: Border.all(color: level.color.withOpacity(0.2), width: 1.5),
@@ -29,17 +33,27 @@ class LevelProgressWidget extends StatelessWidget {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text('Driver Level'.tr, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: FinanceDesignSystem.primaryDark)), Text('Driver Level'.tr,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: FinanceDesignSystem.primaryDark)),
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8), padding:
const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: LinearGradient(colors: [level.color, level.gradientEnd]), gradient:
LinearGradient(colors: [level.color, level.gradientEnd]),
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
), ),
child: Row(mainAxisSize: MainAxisSize.min, children: [ child: Row(mainAxisSize: MainAxisSize.min, children: [
Text(level.emoji, style: const TextStyle(fontSize: 16)), Text(level.emoji, style: const TextStyle(fontSize: 16)),
const SizedBox(width: 6), const SizedBox(width: 6),
Text(isAr ? level.nameAr : level.nameEn, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 13)), Text(isAr ? level.nameAr : level.nameEn,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 13)),
]), ]),
), ),
], ],
@@ -50,42 +64,94 @@ class LevelProgressWidget extends StatelessWidget {
final lvl = DriverLevels.all[i]; final lvl = DriverLevels.all[i];
final isCurrent = lvl.id == level.id; final isCurrent = lvl.id == level.id;
final isPast = DriverLevels.all.indexOf(level) > i; final isPast = DriverLevels.all.indexOf(level) > i;
return Expanded(child: Container( return Expanded(
margin: const EdgeInsets.symmetric(horizontal: 2), height: 8, child: Container(
margin: const EdgeInsets.symmetric(horizontal: 2),
height: 8,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isCurrent ? lvl.color : isPast ? lvl.color.withOpacity(0.6) : Colors.grey.shade200, color: isCurrent
? lvl.color
: isPast
? lvl.color.withOpacity(0.6)
: FinanceDesignSystem.backgroundColor,
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(4),
), ),
)); ));
}), }),
), ),
const SizedBox(height: 6), const SizedBox(height: 6),
Row(children: DriverLevels.all.map((l) => Expanded(child: Text(l.emoji, textAlign: TextAlign.center, style: TextStyle(fontSize: l.id == level.id ? 16 : 12)))).toList()), Row(
children: DriverLevels.all
.map((l) => Expanded(
child: Text(l.emoji,
textAlign: TextAlign.center,
style:
TextStyle(fontSize: l.id == level.id ? 16 : 12))))
.toList()),
const SizedBox(height: 16), const SizedBox(height: 16),
if (next != null) ...[ if (next != null) ...[
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text('${'Next Level:'.tr} ${isAr ? next.nameAr : next.nameEn}', style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: Colors.grey.shade700)), Text('${'Next Level:'.tr} ${isAr ? next.nameAr : next.nameEn}',
Text('${(controller.progressToNext * 100).toStringAsFixed(0)}%', style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold, color: level.color)), style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: FinanceDesignSystem.textSecondary)),
Text('${(controller.progressToNext * 100).toStringAsFixed(0)}%',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: level.color)),
]), ]),
const SizedBox(height: 8), const SizedBox(height: 8),
Stack(children: [ Stack(children: [
Container(height: 10, decoration: BoxDecoration(color: Colors.grey.shade100, borderRadius: BorderRadius.circular(5))), Container(
LayoutBuilder(builder: (ctx, c) => AnimatedContainer( height: 10,
duration: const Duration(milliseconds: 800), curve: Curves.easeOutCubic, height: 10, decoration: BoxDecoration(
width: c.maxWidth * controller.progressToNext, color: FinanceDesignSystem.backgroundColor,
decoration: BoxDecoration(gradient: LinearGradient(colors: [level.color, level.gradientEnd]), borderRadius: BorderRadius.circular(5)), borderRadius: BorderRadius.circular(5))),
)), LayoutBuilder(
builder: (ctx, c) => AnimatedContainer(
duration: const Duration(milliseconds: 800),
curve: Curves.easeOutCubic,
height: 10,
width: c.maxWidth * controller.progressToNext,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [level.color, level.gradientEnd]),
borderRadius: BorderRadius.circular(5)),
)),
]), ]),
const SizedBox(height: 6), const SizedBox(height: 6),
Text('${controller.totalPoints} / ${next.minPoints} ${'Points'.tr}', style: TextStyle(fontSize: 11, color: Colors.grey.shade500, fontFamily: 'digit')), Text('${controller.totalPoints} / ${next.minPoints} ${'Points'.tr}',
style: TextStyle(
fontSize: 11,
color: FinanceDesignSystem.textMuted,
fontFamily: 'digit')),
] else ] else
Center(child: Text('🏆 ${'Maximum Level Reached!'.tr}', style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: level.color))), Center(
child: Text('🏆 ${'Maximum Level Reached!'.tr}',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: level.color))),
const SizedBox(height: 16), const SizedBox(height: 16),
Wrap(spacing: 6, runSpacing: 6, children: level.perks.map((p) => Container( Wrap(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), spacing: 6,
decoration: BoxDecoration(color: level.color.withOpacity(0.1), borderRadius: BorderRadius.circular(12)), runSpacing: 6,
child: Text(p.tr, style: TextStyle(fontSize: 10, fontWeight: FontWeight.w600, color: level.color.withOpacity(0.8))), children: level.perks
)).toList()), .map((p) => Container(
padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 5),
decoration: BoxDecoration(
color: level.color.withOpacity(0.1),
borderRadius: BorderRadius.circular(12)),
child: Text(p.tr,
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w600,
color: level.color.withOpacity(0.8))),
))
.toList()),
], ],
), ),
); );

View File

@@ -14,63 +14,114 @@ class MonthlyChartWidget extends StatelessWidget {
return Container( return Container(
padding: const EdgeInsets.all(20), padding: const EdgeInsets.all(20),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: FinanceDesignSystem.cardColor,
borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius), borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 10, offset: const Offset(0, 4))], boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.03),
blurRadius: 10,
offset: const Offset(0, 4))
],
), ),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ child:
Text('Monthly Report'.tr, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: FinanceDesignSystem.primaryDark)), Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text('Monthly Report'.tr,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: FinanceDesignSystem.primaryDark)),
const SizedBox(height: 16), const SizedBox(height: 16),
// Summary Row // Summary Row
Row(children: [ Row(children: [
_summaryTile('Total Earnings'.tr, '${sc.monthlyTotalEarnings.toStringAsFixed(0)} ${'SYP'.tr}', FinanceDesignSystem.successGreen), _summaryTile(
'Total Earnings'.tr,
'${sc.monthlyTotalEarnings.toStringAsFixed(0)} ${'SYP'.tr}',
FinanceDesignSystem.successGreen),
const SizedBox(width: 12), const SizedBox(width: 12),
_summaryTile('Total Trips'.tr, '${sc.monthlyTotalTrips}', FinanceDesignSystem.accentBlue), _summaryTile('Total Trips'.tr, '${sc.monthlyTotalTrips}',
FinanceDesignSystem.accentBlue),
const SizedBox(width: 12), const SizedBox(width: 12),
_summaryTile('Best Day'.tr, '${sc.bestDay}', const Color(0xFFFFD700)), _summaryTile(
'Best Day'.tr, '${sc.bestDay}', const Color(0xFFFFD700)),
]), ]),
const SizedBox(height: 20), const SizedBox(height: 20),
// Monthly Earnings Line Chart // Monthly Earnings Line Chart
SizedBox( SizedBox(
height: 200, height: 200,
child: sc.monthlyEarnings.isEmpty child: sc.monthlyEarnings.isEmpty
? Center(child: Text('No data yet'.tr, style: TextStyle(color: Colors.grey.shade400))) ? Center(
child: Text('No data yet'.tr,
style: TextStyle(color: Colors.grey.shade400)))
: LineChart(LineChartData( : LineChart(LineChartData(
lineTouchData: LineTouchData( lineTouchData: LineTouchData(
enabled: true, enabled: true,
touchTooltipData: LineTouchTooltipData( touchTooltipData: LineTouchTooltipData(
getTooltipItems: (spots) => spots.map((s) => LineTooltipItem( getTooltipItems: (spots) => spots
'${s.y.toStringAsFixed(0)} ${'SYP'.tr}', .map((s) => LineTooltipItem(
const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 12), '${s.y.toStringAsFixed(0)} ${'SYP'.tr}',
)).toList(), const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 12),
))
.toList(),
), ),
), ),
gridData: FlGridData(show: true, drawVerticalLine: false, gridData: FlGridData(
getDrawingHorizontalLine: (v) => FlLine(color: Colors.grey.shade100, strokeWidth: 1), show: true,
drawVerticalLine: false,
getDrawingHorizontalLine: (v) => FlLine(
color: FinanceDesignSystem.borderColor,
strokeWidth: 1),
), ),
titlesData: FlTitlesData( titlesData: FlTitlesData(
bottomTitles: AxisTitles(sideTitles: SideTitles(showTitles: true, interval: 5, bottomTitles: AxisTitles(
getTitlesWidget: (v, m) => Padding(padding: const EdgeInsets.only(top: 8), sideTitles: SideTitles(
child: Text('${v.toInt()}', style: TextStyle(fontSize: 10, color: Colors.grey.shade500)), showTitles: true,
interval: 5,
getTitlesWidget: (v, m) => Padding(
padding: const EdgeInsets.only(top: 8),
child: Text('${v.toInt()}',
style: TextStyle(
fontSize: 10,
color: FinanceDesignSystem.textSecondary)),
), ),
)), )),
leftTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)), leftTitles: const AxisTitles(
topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)), sideTitles: SideTitles(showTitles: false)),
rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)), topTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false)),
rightTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false)),
), ),
borderData: FlBorderData(show: false), borderData: FlBorderData(show: false),
lineBarsData: [ lineBarsData: [
LineChartBarData( LineChartBarData(
spots: sc.monthlyEarnings.map((e) => FlSpot(e.day.toDouble(), e.pricePerDay)).toList(), spots: sc.monthlyEarnings
isCurved: true, curveSmoothness: 0.3, .map((e) =>
color: FinanceDesignSystem.accentBlue, barWidth: 3, FlSpot(e.day.toDouble(), e.pricePerDay))
dotData: FlDotData(show: true, getDotPainter: (s, p, d, i) => .toList(),
FlDotCirclePainter(radius: 3, color: FinanceDesignSystem.accentBlue, strokeWidth: 1, strokeColor: Colors.white), isCurved: true,
curveSmoothness: 0.3,
color: FinanceDesignSystem.accentBlue,
barWidth: 3,
dotData: FlDotData(
show: true,
getDotPainter: (s, p, d, i) => FlDotCirclePainter(
radius: 3,
color: FinanceDesignSystem.accentBlue,
strokeWidth: 1,
strokeColor: Colors.white),
), ),
belowBarData: BarAreaData( belowBarData: BarAreaData(
show: true, show: true,
gradient: LinearGradient(begin: Alignment.topCenter, end: Alignment.bottomCenter, gradient: LinearGradient(
colors: [FinanceDesignSystem.accentBlue.withOpacity(0.2), FinanceDesignSystem.accentBlue.withOpacity(0.0)], begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
FinanceDesignSystem.accentBlue.withOpacity(0.2),
FinanceDesignSystem.accentBlue.withOpacity(0.0)
],
), ),
), ),
), ),
@@ -87,11 +138,20 @@ class MonthlyChartWidget extends StatelessWidget {
return Expanded( return Expanded(
child: Container( child: Container(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
decoration: BoxDecoration(color: color.withOpacity(0.08), borderRadius: BorderRadius.circular(12)), decoration: BoxDecoration(
color: color.withOpacity(0.08),
borderRadius: BorderRadius.circular(12)),
child: Column(children: [ child: Column(children: [
Text(value, style: TextStyle(fontSize: 14, fontWeight: FontWeight.w800, color: color)), Text(value,
style: TextStyle(
fontSize: 14, fontWeight: FontWeight.w800, color: color)),
const SizedBox(height: 2), const SizedBox(height: 2),
Text(label, style: TextStyle(fontSize: 9, color: Colors.grey.shade600), textAlign: TextAlign.center, maxLines: 1, overflow: TextOverflow.ellipsis), Text(label,
style: TextStyle(
fontSize: 9, color: FinanceDesignSystem.textSecondary),
textAlign: TextAlign.center,
maxLines: 1,
overflow: TextOverflow.ellipsis),
]), ]),
), ),
); );

View File

@@ -20,7 +20,7 @@ class StatSummaryCard extends StatelessWidget {
return Container( return Container(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: FinanceDesignSystem.cardColor,
borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius), borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
@@ -68,7 +68,7 @@ class StatSummaryCard extends StatelessWidget {
label, label,
style: TextStyle( style: TextStyle(
fontSize: 11, fontSize: 11,
color: Colors.grey.shade500, color: FinanceDesignSystem.textSecondary,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
maxLines: 1, maxLines: 1,

View File

@@ -13,26 +13,42 @@ class TodayChartWidget extends StatelessWidget {
return Container( return Container(
padding: const EdgeInsets.all(20), padding: const EdgeInsets.all(20),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: FinanceDesignSystem.cardColor,
borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius), borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius),
boxShadow: [ boxShadow: [
BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 10, offset: const Offset(0, 4)), BoxShadow(
color: Colors.black.withOpacity(0.03),
blurRadius: 10,
offset: const Offset(0, 4)),
], ],
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text('Today Overview'.tr, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: FinanceDesignSystem.primaryDark)), Text('Today Overview'.tr,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: FinanceDesignSystem.primaryDark)),
const SizedBox(height: 4), const SizedBox(height: 4),
Text('نظرة عامة على اليوم'.tr, style: TextStyle(fontSize: 11, color: Colors.grey.shade500)), Text('Summary of your daily activity'.tr,
style: TextStyle(
fontSize: 11, color: FinanceDesignSystem.textSecondary)),
const SizedBox(height: 20), const SizedBox(height: 20),
_buildRow(Icons.monetization_on_rounded, 'Earnings'.tr, '${hc.totalMoneyToday} ${'SYP'.tr}', FinanceDesignSystem.successGreen), _buildRow(
Icons.monetization_on_rounded,
'Earnings'.tr,
'${hc.totalMoneyToday} ${'SYP'.tr}',
FinanceDesignSystem.successGreen),
const Divider(height: 24), const Divider(height: 24),
_buildRow(Icons.local_taxi_rounded, 'Rides'.tr, hc.countRideToday, FinanceDesignSystem.accentBlue), _buildRow(Icons.local_taxi_rounded, 'Rides'.tr, hc.countRideToday,
FinanceDesignSystem.accentBlue),
const Divider(height: 24), const Divider(height: 24),
Obx(() => _buildRow(Icons.timer_rounded, 'Online Duration'.tr, hc.totalDurationDisplay.value, const Color(0xFFFF9800))), Obx(() => _buildRow(Icons.timer_rounded, 'Online Duration'.tr,
hc.totalDurationDisplay.value, const Color(0xFFFF9800))),
const Divider(height: 24), const Divider(height: 24),
_buildRow(Icons.cancel_outlined, 'Refused'.tr, hc.countRefuse, FinanceDesignSystem.dangerRed), _buildRow(Icons.cancel_outlined, 'Refused'.tr, hc.countRefuse,
FinanceDesignSystem.dangerRed),
], ],
), ),
); );
@@ -45,12 +61,24 @@ class TodayChartWidget extends StatelessWidget {
children: [ children: [
Container( Container(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
decoration: BoxDecoration(color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(10)), decoration: BoxDecoration(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(10)),
child: Icon(icon, color: color, size: 20), child: Icon(icon, color: color, size: 20),
), ),
const SizedBox(width: 14), const SizedBox(width: 14),
Expanded(child: Text(label, style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.grey.shade700))), Expanded(
Text(value, style: TextStyle(fontSize: 16, fontWeight: FontWeight.w800, color: FinanceDesignSystem.primaryDark, fontFamily: 'digit')), child: Text(label,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: FinanceDesignSystem.primaryDark))),
Text(value,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w800,
color: FinanceDesignSystem.primaryDark,
fontFamily: 'digit')),
], ],
); );
} }

View File

@@ -4,7 +4,6 @@ import 'package:fl_chart/fl_chart.dart';
import '../../../../constant/finance_design_system.dart'; import '../../../../constant/finance_design_system.dart';
import '../../../../controller/home/statistics/statistics_controller.dart'; import '../../../../controller/home/statistics/statistics_controller.dart';
class WeeklyChartWidget extends StatelessWidget { class WeeklyChartWidget extends StatelessWidget {
const WeeklyChartWidget({super.key}); const WeeklyChartWidget({super.key});
@@ -15,32 +14,56 @@ class WeeklyChartWidget extends StatelessWidget {
return Container( return Container(
padding: const EdgeInsets.all(20), padding: const EdgeInsets.all(20),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: FinanceDesignSystem.cardColor,
borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius), borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 10, offset: const Offset(0, 4))], boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.03),
blurRadius: 10,
offset: const Offset(0, 4))
],
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text('Weekly Earnings'.tr, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: FinanceDesignSystem.primaryDark)), Text('Weekly Earnings'.tr,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: FinanceDesignSystem.primaryDark)),
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), padding:
decoration: BoxDecoration(color: FinanceDesignSystem.successGreen.withOpacity(0.1), borderRadius: BorderRadius.circular(12)), const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
child: Text('${sc.weeklyEarnings.toStringAsFixed(0)} ${'SYP'.tr}', style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold, color: FinanceDesignSystem.successGreen)), decoration: BoxDecoration(
color: FinanceDesignSystem.successGreen.withOpacity(0.1),
borderRadius: BorderRadius.circular(12)),
child: Text(
'${sc.weeklyEarnings.toStringAsFixed(0)} ${'SYP'.tr}',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: FinanceDesignSystem.successGreen)),
), ),
]), ]),
const SizedBox(height: 8), const SizedBox(height: 8),
Row(children: [ Row(children: [
_miniStat(Icons.local_taxi_rounded, '${sc.weeklyTrips}', 'Rides'.tr, FinanceDesignSystem.accentBlue), _miniStat(Icons.local_taxi_rounded, '${sc.weeklyTrips}',
'Rides'.tr, FinanceDesignSystem.accentBlue),
const SizedBox(width: 16), const SizedBox(width: 16),
_miniStat(Icons.timer_rounded, '${sc.weeklyHours.toStringAsFixed(1)}h', 'Hours'.tr, const Color(0xFFFF9800)), _miniStat(
Icons.timer_rounded,
'${sc.weeklyHours.toStringAsFixed(1)}h',
'Hours'.tr,
const Color(0xFFFF9800)),
]), ]),
const SizedBox(height: 20), const SizedBox(height: 20),
SizedBox( SizedBox(
height: 180, height: 180,
child: sc.weeklyStats.isEmpty child: sc.weeklyStats.isEmpty
? Center(child: Text('No data yet'.tr, style: TextStyle(color: Colors.grey.shade400))) ? Center(
child: Text('No data yet'.tr,
style: TextStyle(color: Colors.grey.shade400)))
: BarChart( : BarChart(
BarChartData( BarChartData(
alignment: BarChartAlignment.spaceAround, alignment: BarChartAlignment.spaceAround,
@@ -48,24 +71,43 @@ class WeeklyChartWidget extends StatelessWidget {
barTouchData: BarTouchData( barTouchData: BarTouchData(
enabled: true, enabled: true,
touchTooltipData: BarTouchTooltipData( touchTooltipData: BarTouchTooltipData(
getTooltipItem: (group, gi, rod, ri) => BarTooltipItem( getTooltipItem: (group, gi, rod, ri) =>
BarTooltipItem(
'${rod.toY.toStringAsFixed(0)} ${'SYP'.tr}', '${rod.toY.toStringAsFixed(0)} ${'SYP'.tr}',
const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 12), const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 12),
), ),
), ),
), ),
titlesData: FlTitlesData( titlesData: FlTitlesData(
show: true, show: true,
bottomTitles: AxisTitles(sideTitles: SideTitles(showTitles: true, getTitlesWidget: (v, m) { bottomTitles: AxisTitles(
final idx = v.toInt(); sideTitles: SideTitles(
if (idx >= 0 && idx < sc.weeklyStats.length) { showTitles: true,
return Padding(padding: const EdgeInsets.only(top: 8), child: Text(sc.weeklyStats[idx].dayName.tr, style: TextStyle(fontSize: 10, color: Colors.grey.shade500))); getTitlesWidget: (v, m) {
} final idx = v.toInt();
return const SizedBox.shrink(); if (idx >= 0 &&
})), idx < sc.weeklyStats.length) {
leftTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)), return Padding(
topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)), padding:
rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)), const EdgeInsets.only(top: 8),
child: Text(
sc.weeklyStats[idx].dayName.tr,
style: TextStyle(
fontSize: 10,
color: FinanceDesignSystem
.textSecondary)));
}
return const SizedBox.shrink();
})),
leftTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false)),
topTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false)),
rightTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false)),
), ),
borderData: FlBorderData(show: false), borderData: FlBorderData(show: false),
gridData: const FlGridData(show: false), gridData: const FlGridData(show: false),
@@ -76,12 +118,22 @@ class WeeklyChartWidget extends StatelessWidget {
BarChartRodData( BarChartRodData(
toY: stat.earnings, toY: stat.earnings,
width: 20, width: 20,
borderRadius: const BorderRadius.vertical(top: Radius.circular(6)), borderRadius: const BorderRadius.vertical(
top: Radius.circular(6)),
gradient: LinearGradient( gradient: LinearGradient(
begin: Alignment.bottomCenter, end: Alignment.topCenter, begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: isToday colors: isToday
? [FinanceDesignSystem.accentBlue, const Color(0xFF82B1FF)] ? [
: [FinanceDesignSystem.primaryDark.withOpacity(0.6), FinanceDesignSystem.primaryDark.withOpacity(0.3)], FinanceDesignSystem.accentBlue,
const Color(0xFF82B1FF)
]
: [
FinanceDesignSystem.primaryDark
.withOpacity(0.6),
FinanceDesignSystem.primaryDark
.withOpacity(0.3)
],
), ),
), ),
]); ]);
@@ -100,9 +152,15 @@ class WeeklyChartWidget extends StatelessWidget {
return Row(children: [ return Row(children: [
Icon(icon, size: 16, color: color), Icon(icon, size: 16, color: color),
const SizedBox(width: 4), const SizedBox(width: 4),
Text(value, style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold, color: FinanceDesignSystem.primaryDark)), Text(value,
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.bold,
color: FinanceDesignSystem.primaryDark)),
const SizedBox(width: 4), const SizedBox(width: 4),
Text(label, style: TextStyle(fontSize: 11, color: Colors.grey.shade500)), Text(label,
style: TextStyle(
fontSize: 11, color: FinanceDesignSystem.textSecondary)),
]); ]);
} }

View File

@@ -106,7 +106,7 @@ class Language extends StatelessWidget {
alignment: Alignment.center, alignment: Alignment.center,
child: Text( child: Text(
flagIcon, flagIcon,
style: const TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: FinanceDesignSystem.primaryDark, color: FinanceDesignSystem.primaryDark,

View File

@@ -2160,7 +2160,7 @@ packages:
source: hosted source: hosted
version: "0.7.0" version: "0.7.0"
url_launcher: url_launcher:
dependency: transitive dependency: "direct main"
description: description:
name: url_launcher name: url_launcher
sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8

View File

@@ -72,6 +72,7 @@ dependencies:
share_plus: ^12.0.2 share_plus: ^12.0.2
sign_in_with_apple: ^7.0.1 sign_in_with_apple: ^7.0.1
socket_io_client: ^1.0.2 socket_io_client: ^1.0.2
url_launcher: ^6.3.1
vibration: ^3.1.8 vibration: ^3.1.8
video_player: ^2.9.2 video_player: ^2.9.2
wakelock_plus: wakelock_plus: