add new featurs like new stat page
This commit is contained in:
@@ -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,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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": "ستظهر رحلاتك المكتملة هنا",
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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": "",
|
||||||
|
|||||||
@@ -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)),
|
||||||
|
|||||||
@@ -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
|
||||||
|
? '🥈'
|
||||||
|
: '🥉';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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,
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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)),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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),
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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')),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user