Update: 2026-07-04 04:05:08
This commit is contained in:
@@ -145,6 +145,9 @@ class AppLink {
|
||||
static String get getSurgeHeatmap =>
|
||||
"$server/ride/heatmap/get_surge_heatmap.php";
|
||||
|
||||
static String get getPredictiveDemand =>
|
||||
"$server/api/demand/getPredictiveDemandZones.php";
|
||||
|
||||
///mapOSM = 'https://routesy.intaleq.xyz'
|
||||
static String get mapOSM {
|
||||
switch (currentCountry) {
|
||||
|
||||
@@ -61,8 +61,13 @@ class HomeCaptainController extends GetxController {
|
||||
double widthMapTypeAndTraffic = 50;
|
||||
// === متغيرات الهيت ماب الجديدة ===
|
||||
bool isHeatmapVisible = false;
|
||||
Set<Polygon> heatmapPolygons =
|
||||
{}; // سنستخدم Polygon لرسم المربعات على جوجل مابس
|
||||
Set<Polygon> heatmapPolygons = {};
|
||||
|
||||
// === متغيرات التنبؤ الذكي بالطلب ===
|
||||
bool isPredictiveVisible = false;
|
||||
Set<Polygon> predictivePolygons = {};
|
||||
List<Map<String, dynamic>> predictiveZones = [];
|
||||
Timer? _predictiveTimer;
|
||||
|
||||
// Inject the LocationController class
|
||||
// final locationController = Get.put(LocationController());
|
||||
@@ -198,6 +203,97 @@ class HomeCaptainController extends GetxController {
|
||||
});
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════
|
||||
// 🔮 التنبؤ الذكي بالطلب
|
||||
// ════════════════════════════════════════════════════════
|
||||
|
||||
/// تبديل عرض/إخفاء طبقة التنبؤ الذكي
|
||||
void togglePredictiveDemand() {
|
||||
isPredictiveVisible = !isPredictiveVisible;
|
||||
if (isPredictiveVisible) {
|
||||
_startPredictiveCycle();
|
||||
} else {
|
||||
_predictiveTimer?.cancel();
|
||||
predictivePolygons.clear();
|
||||
predictiveZones.clear();
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void _startPredictiveCycle() {
|
||||
_predictiveTimer?.cancel();
|
||||
fetchAndDrawPredictiveDemand();
|
||||
// تحديث كل 30 دقيقة (يتوافق مع دورة الـ cron)
|
||||
_predictiveTimer = Timer.periodic(const Duration(minutes: 30), (_) {
|
||||
if (isPredictiveVisible) fetchAndDrawPredictiveDemand();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> fetchAndDrawPredictiveDemand() async {
|
||||
print("🔮 [Predictive] Fetching demand zones...");
|
||||
try {
|
||||
final myLat = locationController.myLocation.latitude;
|
||||
final myLng = locationController.myLocation.longitude;
|
||||
|
||||
final response = await http.get(
|
||||
Uri.parse(
|
||||
"${AppLink.getPredictiveDemand}?lat=$myLat&lng=$myLng&radius=10"
|
||||
"&t=${DateTime.now().millisecondsSinceEpoch}",
|
||||
),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final body = json.decode(response.body);
|
||||
if (body['success'] == true) {
|
||||
final zones = List<Map<String, dynamic>>.from(body['zones'] ?? []);
|
||||
predictiveZones = zones;
|
||||
_drawPredictivePolygons(zones);
|
||||
print("✅ [Predictive] ${zones.length} zones loaded.");
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print("❌ [Predictive] Error: $e");
|
||||
}
|
||||
}
|
||||
|
||||
void _drawPredictivePolygons(List<Map<String, dynamic>> zones) {
|
||||
const double offset = 0.008; // أكبر قليلاً من الهيتماب (0.005) ليكون مميزاً
|
||||
final Set<Polygon> temp = {};
|
||||
|
||||
for (final zone in zones) {
|
||||
final double lat = (zone['lat'] as num).toDouble();
|
||||
final double lng = (zone['lng'] as num).toDouble();
|
||||
final int score = (zone['demand_score'] as num).toInt();
|
||||
|
||||
// ألوان التنبؤ: أزرق/سماوي (مختلف تماماً عن الهيتماب)
|
||||
final Color fill = score >= 8
|
||||
? const Color(0xFF0EA5E9).withOpacity(0.35) // أزرق قوي
|
||||
: score >= 4
|
||||
? const Color(0xFF38BDF8).withOpacity(0.30) // أزرق فاتح
|
||||
: const Color(0xFF7DD3FC).withOpacity(0.25); // سماوي خفيف
|
||||
|
||||
final Color stroke = score >= 8
|
||||
? const Color(0xFF0369A1).withOpacity(0.9)
|
||||
: const Color(0xFF0EA5E9).withOpacity(0.8);
|
||||
|
||||
temp.add(Polygon(
|
||||
polygonId: PolygonId("pred_${lat}_$lng"),
|
||||
points: [
|
||||
LatLng(lat - offset, lng - offset),
|
||||
LatLng(lat + offset, lng - offset),
|
||||
LatLng(lat + offset, lng + offset),
|
||||
LatLng(lat - offset, lng + offset),
|
||||
],
|
||||
fillColor: fill,
|
||||
strokeColor: stroke,
|
||||
strokeWidth: 2,
|
||||
));
|
||||
}
|
||||
|
||||
predictivePolygons = temp;
|
||||
update();
|
||||
}
|
||||
|
||||
void goToWalletFromConnect() {
|
||||
Get.back();
|
||||
Get.back();
|
||||
|
||||
@@ -803,6 +803,7 @@ final Map<String, String> ar_eg = {
|
||||
"Heading your way now. Please be ready.": "قاعد يجيك دلوقتي. من فضلك استعد.",
|
||||
"Health Insurance": "التأمين الصحي",
|
||||
"Heatmap": "خريطة الحرارة",
|
||||
"Predictive Demand": "🔮 توقعات الطلب",
|
||||
"Height:": "الطول:",
|
||||
"Hello": "أهلاً",
|
||||
"Hello this is Captain": "أهلاً، ده الكابتن",
|
||||
|
||||
@@ -803,6 +803,7 @@ final Map<String, String> ar_jo = {
|
||||
"Heading your way now. Please be ready.": "في طريقه إليك الآن. يرجى الاستعداد.",
|
||||
"Health Insurance": "التأمين الصحي",
|
||||
"Heatmap": "خريطة الحرارة",
|
||||
"Predictive Demand": "🔮 توقعات الطلب",
|
||||
"Height:": "الطول:",
|
||||
"Hello": "مرحباً",
|
||||
"Hello this is Captain": "مرحباً، هذا الكابتن",
|
||||
|
||||
@@ -803,6 +803,7 @@ final Map<String, String> ar_sy = {
|
||||
"Heading your way now. Please be ready.": "عم ييجي لعندك هلق. تفضّل جهّز حالك.",
|
||||
"Health Insurance": "التأمين الصحي",
|
||||
"Heatmap": "خريطة حرارية",
|
||||
"Predictive Demand": "🔮 توقعات الطلب",
|
||||
"Height:": "الطول:",
|
||||
"Hello": "أهلاً",
|
||||
"Hello this is Captain": "أهلاً، أنا الكابتن",
|
||||
|
||||
@@ -803,6 +803,7 @@ final Map<String, String> en = {
|
||||
"Heading your way now. Please be ready.": "Heading your way now. Please be ready.",
|
||||
"Health Insurance": "Health Insurance",
|
||||
"Heatmap": "Heatmap",
|
||||
"Predictive Demand": "Predictive Demand",
|
||||
"Height:": "Height:",
|
||||
"Hello": "Hello",
|
||||
"Hello this is Captain": "Hello this is Captain",
|
||||
|
||||
@@ -326,6 +326,42 @@ class _AppBarControls extends StatelessWidget {
|
||||
onTap: c.toggleHeatmap,
|
||||
),
|
||||
),
|
||||
// Predictive Demand
|
||||
GetBuilder<HomeCaptainController>(
|
||||
builder: (c) => Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
_IconBtn(
|
||||
icon: Icons.auto_awesome_rounded,
|
||||
color: c.isPredictiveVisible
|
||||
? const Color(0xFF0EA5E9)
|
||||
: Colors.grey.shade600,
|
||||
tooltip: 'Predictive Demand'.tr,
|
||||
onTap: c.togglePredictiveDemand,
|
||||
),
|
||||
if (c.isPredictiveVisible && c.predictiveZones.isNotEmpty)
|
||||
Positioned(
|
||||
top: -4,
|
||||
right: -4,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(3),
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFF0EA5E9),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Text(
|
||||
'${c.predictiveZones.length}',
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 8,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Center on me
|
||||
_IconBtn(
|
||||
icon: Icons.my_location_rounded,
|
||||
@@ -398,7 +434,10 @@ class _MapView extends StatelessWidget {
|
||||
mapType: s.isMapDarkMode
|
||||
? IntaleqMapType.normal
|
||||
: IntaleqMapType.light,
|
||||
polygons: ctrl.heatmapPolygons,
|
||||
polygons: {
|
||||
...ctrl.heatmapPolygons,
|
||||
...ctrl.predictivePolygons,
|
||||
},
|
||||
markers: {
|
||||
Marker(
|
||||
markerId: MarkerId('MyLocation'.tr),
|
||||
|
||||
@@ -2,7 +2,7 @@ name: siro_driver
|
||||
description: "A new Flutter project."
|
||||
publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
||||
|
||||
version: 1.0.0+2
|
||||
version: 1.0.0+3
|
||||
|
||||
environment:
|
||||
sdk: ">=3.0.5 <4.0.0"
|
||||
|
||||
Reference in New Issue
Block a user