Files
tripz-llc/docs/39-siro-screens.md
T
Hamza-AyedandClaude Opus 5 69da4abc01 feat(apps): سقالة rider_new و driver_new على Cubit — المرحلة 1
بناء من الصفر على باك إند NestJS، بقرار المالك 2026-08-04 الذي يعكس قرارَي
نقل GetX (2026-07-21) واعتماد باك إند PHP (2026-07-27). لا يُورَّث سطر دارت
من apps/*-archive-cubit، وسيرو مرجع بصري وسلوكي لا مصدر نسخ.

الوثائق:
- docs/37: الخطة الكاملة بستّ مراحل وبواباتها
- docs/38: عقد الـAPI من 37 controller، معظمه متحقَّق حيّاً من السيرفر المنشور
- docs/39: جرد 202 شاشة في تطبيقَي سيرو، مصنّفة داخل/خارج النطاق

الطبقة الأصلية منقولة من *-archive-cubit وحدها لأنها هوية النشر:
- rider_new  → com.mobileapp.store.ride · shorebird 496cb3ac
- driver_new → com.sefer_driver (أندرويد) · com.sefer.driver (iOS) · 68cc9345
- أُصلح تعارض: هدف RunnerTests في driver_new كان يحمل bundle الراكب

الأصول مصدرها *-archive-cubit لا سيرو: أصول الأرشيف مجموعة أشمل (كل صور
سيرو + صور تريبز) وخطوطها هي خطوط docs/26. استُكمل السائق بعشرة ملفات
ناقصة من سيرو (شعارات مزوّدي الدفع + صوتان).

lib/ مكتوب من الصفر (11 ملف لكل تطبيق):
- AppConfig بأعلام const — أساس نموذج lite/pro/max
- TokenStore على التخزين الآمن، يقرأ exp محليّاً بلا حزمة خارجية
- AuthInterceptor بتجديد استباقي وطلقة واحدة — عمر التوكن 15 دقيقة فقط
- ApiClient و ApiException يفهم مصفوفة message في NestJS

flutter analyze نظيف في التطبيقين. البناء الفعلي لم يُجرَّب بعد: بوابة
المرحلة 1 تتطلّب البناء على السيرفر، والوصول إليه غير متاح حالياً.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 21:21:26 +03:00

197 lines
12 KiB
Markdown

# 39 — جرد شاشات سيرو: المرجع البصري والسلوكي
الغرض: هذا **ما نبني عليه الشكل والترتيب** في `rider_new` و`driver_new`
(م0.3 من `docs/37`). المصدر: `~/development/App/Siro/siro_rider` و`siro_driver`.
> **قاعدة الاستخدام**: هذا الملف يجيب على «ما هي الشاشة، وما ترتيب خطواتها،
> وأي حالة حافة عولجت ميدانياً». **لا يُنسخ ملف دارت واحد من سيرو.**
> شكل الواجهة يُعاد بناؤه على `docs/26` بجودة أعلى، والعقد من `docs/38`.
---
## 1. المخزون — الحجم الحقيقي
| | شاشات/ويدجت | ملاحظة |
|---|---|---|
| `siro_rider/lib/views` | 89 ملف | يشمل الطعام والنقل العام |
| `siro_driver/lib/views` | 113 ملف | يشمل التوصيل والتلعيب والإحصاءات |
**ليس كله في النطاق.** خارج نطاق `docs/37` تماماً: `food/`, `food_delivery/`,
`transit/`, `gamification/`, `assurance_health_page`, `siro_prime_page`,
`android_bot`. هذي تُقرأ لاحقاً عند وحدات `docs/33` المدفوعة، لا الآن.
**داخل النطاق** (م1–م6): المصادقة · الخريطة وطلب الرحلة · مسار الرحلة ·
المحفظة · الدراور والملف · الإشعارات · التقييم.
---
## 2. المصادقة — مرجع م3
### التسلسل في سيرو (متطابق في التطبيقين)
```
موافقة الشروط → إذن الموقع → رقم الهاتف → OTP → [تسجيل] → الرئيسية
```
بوابتان **قبل** أي حقل إدخال، وكل واحدة شاشة كاملة لا حوار:
1. **صفحة الموافقة** (`_buildAgreementPage`): نصّ الاتفاقية بـHTML من الخادم،
مربّع اختيار، وزر متابعة **معطّل حتى يُؤشَّر**. تُحفظ
(`BoxName.agreeTerms == 'agreed'`) ولا تتكرر.
2. **صفحة إذن الموقع**: تطلب الإذن، ومعها زر `openAppSettings()` للحالة التي
يرفض فيها المستخدم نهائياً. تطبيق السائق يراقب دورة حياة التطبيق
(`WidgetsBindingObserver` + `didChangeAppLifecycleState`) ليعيد الفحص عند
**العودة من إعدادات النظام** — بلا هذا تبقى الشاشة عالقة. حالة حافة حقيقية
لازم تُنقل.
### شاشة الهاتف
- `IntlPhoneField` مع مفتاح دولة افتراضي من `BoxName.countryCode`.
- تحقّقات مطبّقة: فارغ · **يبدأ بصفر → رفض** («أدخل بلا الصفر») · أقصر من 10.
- الرقم يُرسل بلا `+`.
### شاشة الـOTP
- **3 خانات** في سيرو، حقل واحد بتباعد حروف كبير + ثلاث نقاط تقدّم متحرّكة.
- ⚠️ **تريبز يستخدم 4 خانات** (`docs/38`). الشكل يُقلَّد، الطول لا.
- ⚠️ **لا يوجد عدّاد إعادة إرسال ولا زر «إعادة الإرسال» في سيرو.** هذه
**فجوة، لا مرجع**: تريبز يحدّ `send-otp` بـ3 طلبات/5 دقائق، فبلا عدّاد
تنازلي يُحظر المستخدم بثلاث ضغطات. **لازم نضيفها.**
### شاشة التسجيل
الاسم الأول · الأخير · البريد. ⚠️ عقد تريبز يقبل `{ name, language }` فقط
(`PATCH /users/me`) — حقل اسم واحد. لا تُنقل الحقول كما هي.
### فروق تطبيق السائق
مسار إضافي بعد الدخول: `registration_view` (تسجيل السائق) →
`pending_driver_page` (شاشة «قيد المراجعة») → `camera_lisence_page` /
`text_scanner` / `passportimage` (تصوير الوثائق) → `cars_inserting_page`.
يقابلها في تريبز: `/drivers/apply` → `/drivers/profile` →
`/drivers/documents` → `/vehicles`، **ثم إعادة دخول إجبارية** لأن الدور
يتغيّر بعد الاعتماد (مصيدة `docs/38` §5).
### ما لا يُنقل من طبقة مصادقة سيرو
`login_controller.dart` فيه JWT مزدوج (توكن عام + `walletJwt` منفصل)، وقفل
تزامن ساكن، وعدّاد إخفاقات، وفكّ base64 يدوي للـpayload. **هذا تعقيد مفروض
من باك إند PHP**، وتريبز عنده `access_token`/`refresh_token` واحد. لا يُنقل.
المُنقَل هو الفكرة الصالحة: **تجديد واحد متزامن لا يتضاعف عند تعدد الطلبات**.
---
## 3. الخريطة وطلب الرحلة — مرجع م4
أنضج جزء في سيرو، وأدقّ ما نأخذه منه. الوحدة: `views/home/route_planner/`
(10 ملفات، 1,928 سطراً) + `views/home/map_widget.dart/`.
### البنية: خريطة ثابتة + ورقة سفلية بثلاث حالات
1. **مطوية** (`_Collapsed`) — بطاقة «إلى أين؟» فقط.
2. **موسّعة** (`_Expanded`) — المخطّط الكامل.
3. **اختيار من الخريطة** (`RpMapPickOverlay`) — الورقة تنزوي، ودبّوس ثابت في
المنتصف (`rp_center_pin`) والخريطة تتحرك تحته. النمط الصحيح: **المستخدم
يحرّك الخريطة لا الدبّوس.**
### ترتيب المخطّط الموسّع (من أعلى لأسفل)
ترويسة → **مبدّل نوع الطلب** (لنفسي ⇄ لشخص آخر) → **الخط الزمني للمسار**
(المصدر · محطات وسيطة · الوجهة) → **وصول سريع** (المنزل/العمل) → **متقدّم**.
- المصدر افتراضياً = الموقع الحالي، وقابل للتغيير من الخريطة.
- عند «لشخص آخر» يتبدّل حقل المصدر فوراً (`rp_sheet.dart:509`).
- **المحطات الوسيطة** صفوف قابلة للإضافة/الحذف — يقابلها `stops[]` في
`POST /trips` (`docs/38` §4). موجودة في الطرفين.
- المفضّلات (`rp_favorites`) والبحث (`rp_search_dialog` + `rp_search_results`).
### نافذة البحث عن سائق (`searching_captain_window`)
- أنيميشن رادار (دورة ثانيتين) + نصّ الحالة من الكنترولر + مؤشّر دوّار.
- **لا مقبض سحب** — لا تُغلق بالسحب، **فقط بزر «إلغاء البحث»**. قرار تصميمي
صحيح يُنقل: المستخدم لا يزيح شاشة البحث بالخطأ.
- الويدجت «غبي» بلا منطق؛ المؤقّت في الكنترولر هو من يقرر متى يعرض حوار
زيادة الأجرة. **يقابل مباشرةً** مصيدة `docs/38` §4: `expired`/`no_drivers`
قد لا يصلان من الخادم → **المهلة المحليّة إلزامية**. سيرو عالجها؛ نكرّرها.
### بطاقة الرحلة الجارية (`apply_order_widget`, 871 سطراً)
ترويسة مضغوطة · بطاقة معلومات · **شارة السائق** · **لوحة مركبة مرسومة** ·
أيقونة سيارة متحرّكة · صف أزرار · حقل رسالة مخصّصة · مؤشّرا
«وصل السائق وينتظر ن دقيقة» و«الوقت المتبقّي للوصول».
هذي المكوّنات هي ما يجعل الشاشة تبدو احترافية — تُعاد بناؤها في
`packages/tripz_ui`، لا تُنسخ.
### شاشات مساندة
`payment_method_page` · `cash_confirm_bottom_page` · `cancel_raide_page`
(أسباب الإلغاء) · `ride_begin_passenger` · `car_details_widget_to_go` ·
`trip_monitor` + `trip_link_monitor` (مشاركة رابط تتبّع) ·
`voice_call_bottom_sheet` (WebRTC — يقابل `call:*` في `docs/38` §9).
### شاشة السائق (`order_request_page`, 468 سطراً)
خريطة → **كبسولة «الوصول للراكب»** → بطاقة سفلية:
`الراكب + السعر` → `شريط معلومات (المسافة/المدة)` → `العناوين` → `الأزرار`.
- **حالة تحميل صريحة** إن وصل العرض بلا بيانات كاملة — لا شاشة فارغة.
- `order_over_lay.dart` (847 سطراً) = العرض المنبثق فوق أي شاشة. يقابل
`trip:offer` و`trip:offer_taken` في `docs/38` §9.
- ⚠️ شارة `driverEarningsExtra` تعتمد حقولاً من `add_ride.php` (باك إند PHP)
**غير موجودة في عقد NestJS** — تُسقط أو يُضاف لها حقل في الخادم. مثال حيّ
على أن سيرو ليس مطابقاً للعقد.
---
## 4. المحفظة — مرجع م5
| الراكب | السائق |
|---|---|
| `passenger_wallet` · `payment_history_passenger_page` · `cliq_payment_sheet` · `payment_screen_cliq/mtn/sham` | `walet_captain` · `pay_out_screen` · `weekly_payment_page` · `transfer_budget_page` · `points_captain` · `ecash` · `bank_account_egypt` |
محفظة السائق مقسّمة لويدجت جاهزة (`balance_card` ·
`financial_summary_card` · `quick_actions` · `transaction_preview_item`) —
تفكيك جيد يُحتذى.
⚠️ **مصيدتان**:
1. سيرو يخلط محفظة الراكب والسائق في تصميم واحد. تريبز يفصلهما (التزام مقابل
إيراد) — لا تُوحَّد الشاشة.
2. `pay_out_screen` في سيرو **خطوة واحدة**؛ تريبز **خطوتان** مع OTP
(`docs/38` §6). الشاشة تُعاد تصميمها لا تُقلَّد.
---
## 5. الدراور والملف والإشعارات — مرجع م6
**الراكب**: `drawer_menu_page` · `passenger_profile_page` · `order_history` ·
`setting_page` · `languages` · `about_page` · `contact_us` ·
`frequentlyQuestionsPage` · `share_app_page` · `complaint_page` ·
`promos_passenger_page` · `taarif_page` · `notification_page` ·
`rate_captain` + `rating_driver_bottom`.
**السائق**: `drawer_captain` · `bottom_bar` (تنقّل سفلي — الراكب بلا) ·
`profile_captain` · `captains_cars` · `history_captain` +
`history_details_page` · `settings_captain` · `behavior_page` ·
`feed_back_page` · `help_captain` + `help_details_replay_page` ·
`available_rides_page` · `statistics_dashboard` (+6 ويدجت رسوم) ·
`rate_passenger` · `ride_calculate_driver` · `sos_connect` (استغاثة).
**شاشة التقييم مهمة معمارياً**: تُفرض عند فتح التطبيق عبر
`GET /trips/rating/pending` (`docs/38` §7) — تُبنى في م5 لا م6.
---
## 6. الويدجت المشتركة — مدخل `packages/tripz_ui`
الملفات نفسها **مكرّرة حرفياً** في التطبيقين:
`circle_container` · `elevated_btn` · `error_snakbar` · `icon_widget_menu` ·
`my_circular_indicator_timer` · `my_scafold` · `my_textField` · `mycircular` ·
`mydialoug` · `voice_call_bottom_sheet`.
**هذا بالضبط ما تحلّه `packages/tripz_ui`** (م2.11): ازدواج مؤكَّد في سيرو،
لا يتكرر عندنا.
---
## 7. ملاحظات أداء — مادة قائمة الممنوعات (م2.12)
من قراءة سيرو، هذي أنماط تُتجنّب في `*_new`:
- `Get.put()` داخل `build()` (`login_page.dart:27`) — حقن عند كل إعادة بناء.
- ملفات ويدجت تتجاوز 800 سطر (`apply_order_widget` 871 ·
`order_over_lay` 847 · `home_captin` 840) — تفكّك.
- `GetBuilder` يلفّ الشاشة كاملة → إعادة بناء الشجرة كلها عند أي تحديث.
البديل: `BlocSelector`/`buildWhen` على أصغر جزء.
- منطق داخل الويدجت. النمط الصحيح موجود في سيرو نفسه
(`searching_captain_window` «غبي» والمؤقّت في الكنترولر) — يُعمَّم.
> قائمة الممنوعات النهائية تُستكمل في م2 بعد تشخيص `*-archive-cubit` نفسه —
> فسبب الأداء المرفوض هناك، لا هنا.