Files
intaleq_driver/lib/controller/gamification/challenges_controller.dart

287 lines
8.8 KiB
Dart

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:sefer_driver/constant/box_name.dart';
import 'package:sefer_driver/constant/links.dart';
import 'package:sefer_driver/controller/functions/crud.dart';
import '../../../main.dart';
// ════════════════════════════════════════════
// نموذج التحدي
// ════════════════════════════════════════════
class Challenge {
final String id;
final String titleEn;
final String titleAr;
final String descriptionEn;
final String descriptionAr;
final IconData icon;
final Color color;
final int target;
final int reward; // نقاط
final String type; // 'daily' or 'weekly'
final String metric; // 'trips', 'earnings', 'hours', 'acceptance_rate'
int currentProgress;
bool isClaimed;
Challenge({
required this.id,
required this.titleEn,
required this.titleAr,
required this.descriptionEn,
required this.descriptionAr,
required this.icon,
required this.color,
required this.target,
required this.reward,
required this.type,
required this.metric,
this.currentProgress = 0,
this.isClaimed = false,
});
double get progress => (currentProgress / target).clamp(0.0, 1.0);
bool get isCompleted => currentProgress >= target;
}
// ════════════════════════════════════════════
// Controller
// ════════════════════════════════════════════
class ChallengesController extends GetxController {
bool isLoading = false;
List<Challenge> dailyChallenges = [];
List<Challenge> weeklyChallenges = [];
@override
void onInit() {
super.onInit();
_generateChallenges();
_loadProgress();
fetchChallengeProgress();
}
void _generateChallenges() {
final now = DateTime.now();
final isWeekend = now.weekday == 5 || now.weekday == 6; // الجمعة والسبت
dailyChallenges = [
Challenge(
id: 'daily_trips_5',
titleEn: 'Road Runner',
titleAr: 'سائق سريع',
descriptionEn: 'Complete 5 trips today',
descriptionAr: 'أكمل 5 رحلات اليوم',
icon: Icons.local_taxi_rounded,
color: const Color(0xFF2196F3),
target: 5,
reward: 50,
type: 'daily',
metric: 'trips',
),
Challenge(
id: 'daily_trips_10',
titleEn: 'Marathon Driver',
titleAr: 'سائق الماراثون',
descriptionEn: 'Complete 10 trips today',
descriptionAr: 'أكمل 10 رحلات اليوم',
icon: Icons.directions_car_rounded,
color: const Color(0xFFFF9800),
target: 10,
reward: 150,
type: 'daily',
metric: 'trips',
),
Challenge(
id: 'daily_earnings',
titleEn: 'Money Maker',
titleAr: 'صانع المال',
descriptionEn: 'Earn 3000 SYP today',
descriptionAr: 'اربح 3000 ل.س اليوم',
icon: Icons.monetization_on_rounded,
color: const Color(0xFF4CAF50),
target: 3000,
reward: 100,
type: 'daily',
metric: 'earnings',
),
if (isWeekend)
Challenge(
id: 'daily_weekend_bonus',
titleEn: 'Weekend Warrior',
titleAr: 'محارب عطلة نهاية الأسبوع',
descriptionEn: 'Complete 8 trips on the weekend',
descriptionAr: 'أكمل 8 رحلات في عطلة نهاية الأسبوع',
icon: Icons.celebration_rounded,
color: const Color(0xFFE91E63),
target: 8,
reward: 200,
type: 'daily',
metric: 'trips',
),
];
weeklyChallenges = [
Challenge(
id: 'weekly_trips_30',
titleEn: 'Weekly Champion',
titleAr: 'بطل الأسبوع',
descriptionEn: 'Complete 30 trips this week',
descriptionAr: 'أكمل 30 رحلة هذا الأسبوع',
icon: Icons.emoji_events_rounded,
color: const Color(0xFFFFD700),
target: 30,
reward: 300,
type: 'weekly',
metric: 'trips',
),
Challenge(
id: 'weekly_earnings',
titleEn: 'Big Earner',
titleAr: 'الربح الكبير',
descriptionEn: 'Earn 20,000 SYP this week',
descriptionAr: 'اربح 20,000 ل.س هذا الأسبوع',
icon: Icons.account_balance_wallet_rounded,
color: const Color(0xFF9C27B0),
target: 20000,
reward: 500,
type: 'weekly',
metric: 'earnings',
),
Challenge(
id: 'weekly_hours',
titleEn: 'Time Master',
titleAr: 'سيد الوقت',
descriptionEn: 'Drive for 20 hours this week',
descriptionAr: 'اقضِ 20 ساعة في القيادة هذا الأسبوع',
icon: Icons.timer_rounded,
color: const Color(0xFF00BCD4),
target: 20,
reward: 400,
type: 'weekly',
metric: 'hours',
),
];
}
void _loadProgress() {
final today = DateTime.now().toIso8601String().split('T')[0];
final savedDate = box.read('challenges_date');
if (savedDate != today) {
// يوم جديد — إعادة تعيين التحديات اليومية
box.write('challenges_date', today);
for (var c in dailyChallenges) {
box.write('challenge_${c.id}_claimed', false);
}
}
// تحميل حالة المطالبة
for (var c in dailyChallenges) {
c.isClaimed = box.read('challenge_${c.id}_claimed') ?? false;
}
for (var c in weeklyChallenges) {
c.isClaimed = box.read('challenge_${c.id}_claimed') ?? false;
}
}
Future<void> fetchChallengeProgress() async {
isLoading = true;
update();
try {
// جلب رحلات اليوم
var todayRes = await CRUD().getWallet(
link: AppLink.getDriverPaymentToday,
payload: {'driverID': box.read(BoxName.driverID).toString()},
);
int todayTrips = 0;
double todayEarnings = 0;
if (todayRes != null && todayRes != 'failure') {
var data = jsonDecode(todayRes);
todayEarnings = double.tryParse(data['message']?[0]?['todayAmount']?.toString() ?? '0') ?? 0;
todayTrips = int.tryParse(data['message']?[0]?['todayCount']?.toString() ?? '0') ?? 0;
}
// تحديث التحديات اليومية
for (var c in dailyChallenges) {
switch (c.metric) {
case 'trips':
c.currentProgress = todayTrips;
break;
case 'earnings':
c.currentProgress = todayEarnings.toInt();
break;
}
}
// Fetch weekly aggregate for weekly challenges
var weeklyRes = await CRUD().get(
link: AppLink.getWeeklyAggregate,
payload: {'driver_id': box.read(BoxName.driverID).toString()},
);
int weeklyTrips = 0;
double weeklyEarnings = 0;
double weeklyHours = 0;
if (weeklyRes != null && weeklyRes != 'failure') {
var data = jsonDecode(weeklyRes);
if (data['message'] is List) {
for (var day in data['message']) {
weeklyTrips += int.tryParse(day['trips']?.toString() ?? '0') ?? 0;
weeklyEarnings += double.tryParse(day['earnings']?.toString() ?? '0') ?? 0;
weeklyHours += double.tryParse(day['hours']?.toString() ?? '0') ?? 0;
}
}
}
for (var c in weeklyChallenges) {
switch (c.metric) {
case 'trips':
c.currentProgress = weeklyTrips;
break;
case 'earnings':
c.currentProgress = weeklyEarnings.toInt();
break;
case 'hours':
c.currentProgress = weeklyHours.toInt();
break;
}
}
} catch (e) {
debugPrint('❌ [Challenges] Error: $e');
}
isLoading = false;
update();
}
Future<void> claimReward(Challenge challenge) async {
if (!challenge.isCompleted || challenge.isClaimed) return;
try {
var res = await CRUD().post(
link: AppLink.claimChallengeReward,
payload: {
'driver_id': box.read(BoxName.driverID).toString(),
'challenge_id': challenge.id,
'points': challenge.reward.toString(),
},
);
if (res != null && res != 'failure') {
challenge.isClaimed = true;
box.write('challenge_${challenge.id}_claimed', true);
debugPrint('🎉 Claimed ${challenge.reward} points for ${challenge.id}');
update();
}
} catch (e) {
debugPrint('❌ [Challenges] Claim error: $e');
}
}
}