Update codebase
This commit is contained in:
@@ -70,7 +70,14 @@ class Trip extends Equatable {
|
||||
this.driverPhone,
|
||||
this.vehiclePlate,
|
||||
this.vehicleModel,
|
||||
this.vehicleColor,
|
||||
this.vehicleColorHex,
|
||||
this.driverRating,
|
||||
this.requestedAt,
|
||||
this.distanceKm,
|
||||
this.durationMin,
|
||||
this.paymentMethod,
|
||||
this.serviceClass,
|
||||
});
|
||||
|
||||
final String id;
|
||||
@@ -90,8 +97,34 @@ class Trip extends Equatable {
|
||||
final String? driverPhone;
|
||||
final String? vehiclePlate;
|
||||
final String? vehicleModel;
|
||||
|
||||
/// لون المركبة كاسم (`White`, `أبيض`) — **ما يبحث عنه الراكب في الشارع
|
||||
/// قبل اللوحة**. الخادم يرسله في `vehicle.color`
|
||||
/// (`trips.service.ts:427`).
|
||||
final String? vehicleColor;
|
||||
|
||||
/// اللون كـhex إن وُجد (`vehicles` عندها `color_hex`). يُقدَّم على الاسم
|
||||
/// عند الرسم لأنه دقيق، والاسم يبقى للعرض النصّي.
|
||||
final String? vehicleColorHex;
|
||||
|
||||
final String? driverRating;
|
||||
|
||||
// ── حقول السجلّ ────────────────────────────────────────────────────────
|
||||
// كلها موجودة في `trip.entity.ts` وتصل مع `GET /trips/mine`، وكانت
|
||||
// مُهمَلة في القراءة — فبدت بطاقة «رحلاتي» فارغة إلا من سعر وحالة.
|
||||
|
||||
/// وقت الطلب (`requested_at`, `CreateDateColumn`).
|
||||
final DateTime? requestedAt;
|
||||
|
||||
final double? distanceKm;
|
||||
final double? durationMin;
|
||||
|
||||
/// `cash` افتراضاً في الخادم — يُعرض كي يعرف الراكب كيف دفع.
|
||||
final String? paymentMethod;
|
||||
|
||||
/// نوع الخدمة (`economy` افتراضاً).
|
||||
final String? serviceClass;
|
||||
|
||||
factory Trip.fromJson(Map<String, dynamic> json) {
|
||||
GeoPoint? point(String key) {
|
||||
final v = json[key];
|
||||
@@ -99,6 +132,11 @@ class Trip extends Equatable {
|
||||
}
|
||||
|
||||
final driver = json['driver'] as Map<String, dynamic>?;
|
||||
// المركبة تصل بشكلين: مسطّحة (`vehicle_plate`) في ردّ الرحلة، ومتداخلة
|
||||
// (`vehicle: {plate, color}`) في حدث `assigned` (`trips.service.ts:423`).
|
||||
// القراءة تقبل الاثنين بدل أن تُفرغ البطاقة عند أحدهما.
|
||||
final vehicle = (json['vehicle'] ?? driver?['vehicle'])
|
||||
as Map<String, dynamic>?;
|
||||
return Trip(
|
||||
id: json['id'] as String,
|
||||
status: TripStatus.parse(json['status'] as String?),
|
||||
@@ -112,11 +150,26 @@ class Trip extends Equatable {
|
||||
driverName: driver?['name'] as String? ?? json['driver_name'] as String?,
|
||||
driverPhone:
|
||||
driver?['phone'] as String? ?? json['driver_phone'] as String?,
|
||||
vehiclePlate:
|
||||
driver?['vehicle_plate'] as String? ?? json['vehicle_plate'] as String?,
|
||||
vehicleModel:
|
||||
driver?['vehicle_model'] as String? ?? json['vehicle_model'] as String?,
|
||||
vehiclePlate: vehicle?['plate'] as String? ??
|
||||
driver?['vehicle_plate'] as String? ??
|
||||
json['vehicle_plate'] as String?,
|
||||
vehicleModel: vehicle?['model'] as String? ??
|
||||
driver?['vehicle_model'] as String? ??
|
||||
json['vehicle_model'] as String?,
|
||||
vehicleColor: vehicle?['color'] as String? ??
|
||||
driver?['vehicle_color'] as String? ??
|
||||
json['vehicle_color'] as String?,
|
||||
vehicleColorHex: vehicle?['color_hex'] as String? ??
|
||||
driver?['vehicle_color_hex'] as String? ??
|
||||
json['vehicle_color_hex'] as String?,
|
||||
driverRating: driver?['rating']?.toString(),
|
||||
requestedAt: DateTime.tryParse(json['requested_at']?.toString() ?? ''),
|
||||
// المسافة الفعلية أدقّ من المقدّرة حين تتوفّر بعد انتهاء الرحلة.
|
||||
distanceKm: (json['actual_distance_km'] as num?)?.toDouble() ??
|
||||
(json['distance_km'] as num?)?.toDouble(),
|
||||
durationMin: (json['duration_min'] as num?)?.toDouble(),
|
||||
paymentMethod: json['payment_method'] as String?,
|
||||
serviceClass: json['service_class'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'models/geo_point.dart';
|
||||
import 'models/place.dart';
|
||||
|
||||
/// الوجهات الأخيرة — **محلّية**، كما في سيرو
|
||||
/// (`rp_favorites.dart: RpRecentsRow` + جدول `recentLocations`).
|
||||
///
|
||||
/// أكثر رحلات الراكب تتكرّر: البيت، العمل، بيت الأهل. وبلا هذا يعيد كتابة
|
||||
/// الاسم نفسه كل مرة — وهي أكبر خطوة ضائعة في الشاشة الرئيسية.
|
||||
///
|
||||
/// محلّي لا خادمي عن قصد: `GET /trips/mine` يرجّع رحلات لا **أماكن**
|
||||
/// (بلا اسم الوجهة)، فبناء «الأخيرة» عليه يعطي أسطراً بلا عناوين.
|
||||
class RecentPlacesStore {
|
||||
static const _key = 'recent_places';
|
||||
|
||||
/// خمسة تكفي صفّاً أفقياً واحداً؛ أكثر منها يصير قائمةً تُتصفَّح لا تُلمح.
|
||||
static const _max = 5;
|
||||
|
||||
List<Place> _items = const [];
|
||||
List<Place> get items => _items;
|
||||
|
||||
Future<void> load() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final raw = prefs.getString(_key);
|
||||
if (raw == null || raw.isEmpty) return;
|
||||
try {
|
||||
final list = jsonDecode(raw) as List<dynamic>;
|
||||
_items = list
|
||||
.whereType<Map<String, dynamic>>()
|
||||
.map(_decode)
|
||||
.toList(growable: false);
|
||||
} catch (_) {
|
||||
_items = const [];
|
||||
}
|
||||
}
|
||||
|
||||
/// يضيف المكان في الصدارة، ويزيح تكراره إن سبق — لا يتكدّس نفس المكان.
|
||||
Future<void> add(Place place) async {
|
||||
if (place.label.isEmpty) return;
|
||||
_items = [
|
||||
place,
|
||||
..._items.where((p) => p.id != place.id || p.label != place.label),
|
||||
].take(_max).toList(growable: false);
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(
|
||||
_key,
|
||||
jsonEncode(_items.map(_encode).toList(growable: false)),
|
||||
);
|
||||
}
|
||||
|
||||
static Map<String, dynamic> _encode(Place p) => {
|
||||
'id': p.id,
|
||||
'name': p.name,
|
||||
'address': p.address,
|
||||
'category': p.category,
|
||||
'lat': p.point.lat,
|
||||
'lng': p.point.lng,
|
||||
};
|
||||
|
||||
static Place _decode(Map<String, dynamic> json) => Place(
|
||||
id: json['id']?.toString() ?? '',
|
||||
name: json['name'] as String? ?? '',
|
||||
address: json['address'] as String? ?? '',
|
||||
category: json['category'] as String? ?? '',
|
||||
point: GeoPoint(
|
||||
(json['lat'] as num?)?.toDouble() ?? 0,
|
||||
(json['lng'] as num?)?.toDouble() ?? 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user