Food: single-source tracking, mode exclusivity, in-app navigation
This commit is contained in:
@@ -12,6 +12,7 @@ import '../../controller/voice_call_controller.dart';
|
||||
import '../../controller/food/food_models.dart';
|
||||
import '../widgets/my_scafold.dart';
|
||||
import 'food_home_page.dart';
|
||||
import 'food_tracking_map_page.dart';
|
||||
|
||||
class FoodOrderTrackingPage extends StatefulWidget {
|
||||
final int orderId;
|
||||
@@ -130,6 +131,25 @@ class _FoodOrderTrackingPageState extends State<FoodOrderTrackingPage> {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// خريطة التتبّع تظهر فقط بعد إسناد سائق — قبلها لا يوجد ما يُتتبَّع
|
||||
if (order.status == 'courier_assigned' || order.status == 'picked_up')
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton.icon(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColor.accentColor,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
|
||||
),
|
||||
onPressed: () => Get.to(() => FoodTrackingMapPage(orderId: order.id)),
|
||||
icon: const Icon(Icons.map_rounded, color: Colors.white),
|
||||
label: Text(
|
||||
_isAr ? 'تتبّع السائق على الخريطة' : 'Track courier on map',
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
// الاتصال بالسائق متاح فقط أثناء التوصيل، وعبر قناة مقنّعة:
|
||||
// لا رقم هاتف يُعرض لأي طرف — جلسة صوتية مؤقتة تُقفل بانتهاء الطلب.
|
||||
if (order.status == 'courier_assigned' || order.status == 'picked_up')
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
// food_tracking_map_page.dart — خريطة تتبّع سائق التوصيل (جهة الراكب)
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
|
||||
import '../../constant/box_name.dart';
|
||||
import '../../constant/colors.dart';
|
||||
import '../../constant/style.dart';
|
||||
import '../../controller/food/food_tracking_controller.dart';
|
||||
import '../../env/env.dart';
|
||||
import '../../main.dart';
|
||||
import '../widgets/my_scafold.dart';
|
||||
|
||||
class FoodTrackingMapPage extends StatelessWidget {
|
||||
final int orderId;
|
||||
const FoodTrackingMapPage({super.key, required this.orderId});
|
||||
|
||||
bool get _isAr => box.read(BoxName.lang) == 'ar';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final c = Get.put(FoodTrackingController(orderId), tag: 'food_track_$orderId');
|
||||
|
||||
return GetBuilder<FoodTrackingController>(
|
||||
tag: 'food_track_$orderId',
|
||||
builder: (_) => MyScafolld(
|
||||
title: _isAr ? 'تتبّع السائق' : 'Track courier',
|
||||
isleading: true,
|
||||
body: [
|
||||
IntaleqMap(
|
||||
apiKey: Env.mapSaasKey,
|
||||
onMapCreated: c.onMapCreated,
|
||||
onStyleLoaded: c.onStyleLoaded,
|
||||
markers: c.markers,
|
||||
initialCameraPosition: CameraPosition(
|
||||
target: c.courierPosition ??
|
||||
c.merchantPosition ??
|
||||
c.destinationPosition ??
|
||||
const LatLng(31.9539, 35.9106), // عمّان — حتى يصل أول موقع
|
||||
zoom: 14,
|
||||
),
|
||||
),
|
||||
if (c.isLoading)
|
||||
const Positioned.fill(child: Center(child: CircularProgressIndicator())),
|
||||
Positioned(left: 12, right: 12, bottom: 20, child: _statusCard(c)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _statusCard(FoodTrackingController c) {
|
||||
final String message;
|
||||
final Color color;
|
||||
|
||||
if (!c.isTrackingActive) {
|
||||
message = _isAr
|
||||
? 'انتهى تتبّع هذا الطلب'
|
||||
: 'Tracking for this order has ended';
|
||||
color = AppColor.grayColor;
|
||||
} else if (c.courierPosition == null) {
|
||||
message = _isAr
|
||||
? 'بانتظار إشارة موقع السائق…'
|
||||
: 'Waiting for the courier location…';
|
||||
color = AppColor.grayColor;
|
||||
} else if (c.isStale) {
|
||||
// صراحةً بدل إيهام الراكب بحركة حيّة والعلامة مجمّدة على شاشته
|
||||
message = _isAr
|
||||
? 'إشارة السائق ضعيفة — آخر موقع معروف'
|
||||
: 'Weak courier signal — last known position';
|
||||
color = const Color(0xFFF29900);
|
||||
} else if (c.orderStatus == 'picked_up') {
|
||||
message = _isAr ? 'السائق في طريقه إليك' : 'Courier is on the way to you';
|
||||
color = AppColor.accentColor;
|
||||
} else {
|
||||
message = _isAr
|
||||
? 'السائق في طريقه إلى ${c.merchantName}'
|
||||
: 'Courier heading to ${c.merchantName}';
|
||||
color = AppColor.accentColor;
|
||||
}
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(14),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.cardColor,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
boxShadow: [
|
||||
BoxShadow(color: Colors.black.withOpacity(0.12), blurRadius: 10, offset: const Offset(0, 3)),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.delivery_dining_rounded, color: color),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(message, style: AppStyle.title.copyWith(fontWeight: FontWeight.bold)),
|
||||
if (c.destinationAddress != null)
|
||||
Text(
|
||||
'${_isAr ? 'التسليم إلى' : 'Delivering to'}: ${c.destinationAddress}',
|
||||
style: AppStyle.subtitle,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user