Files
tripz-llc/apps/driver/lib/views/home/profile/cars_inserting_page.dart
T
HamzaandClaude Opus 4.8 6234e66471 feat: Gemini AI (doc OCR + face match) + role-assignment endpoints
- GeminiService (integrations/gemini, @Global): extractDocument (OCR fields) + faceMatch; graceful if no GEMINI_API_KEY
- documents: face-match now real via Gemini; POST /admin/documents/:id/ocr extracts fields for CS auto-fill
- roles: PATCH /admin/users/:id/role (admin) + POST /platform/users/role (bootstrap via x-platform-secret)
- config: gemini + platform.secret; .env.example entries

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 20:01:26 +03:00

309 lines
11 KiB
Dart
Executable File

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../constant/colors.dart';
import '../../../constant/style.dart';
import '../../auth/captin/ai_eg_controller.dart';
import '../../auth/captin/driver_car_controller.dart';
import 'package:sefer_driver/views/widgets/elevated_btn.dart';
import 'package:sefer_driver/views/widgets/my_scafold.dart';
class CarsInsertingPage extends StatelessWidget {
CarsInsertingPage({super.key});
// حقن الكنترولرز
final driverCarController = Get.put(DriverCarController());
final aiController = Get.put(AI());
@override
Widget build(BuildContext context) {
return MyScafolld(
title: 'Insert New Car'.tr,
isleading: true,
body: [
Container(
color: AppColor.accentColor.withOpacity(.2),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: [
// 1. الوجه الأمامي (الذكاء الاصطناعي)
egyptCarLicenceFront(),
// 2. الوجه الخلفي (الذكاء الاصطناعي)
egyptCarLicenceBack(),
const SizedBox(height: 10),
// تعليمات
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Please make sure to read the license carefully.'.tr,
style: const TextStyle(fontWeight: FontWeight.bold)),
const SizedBox(height: 5),
Text(
'If your car license has the new design, upload the front side with two images.'
.tr,
style: const TextStyle(fontSize: 12)),
],
),
),
const SizedBox(height: 20),
// 3. زر الحفظ النهائي
GetBuilder<AI>(builder: (controller) {
// التحقق من أن الصور تم رفعها
bool isFrontReady =
controller.responseIdCardDriverEgyptFront.isNotEmpty;
bool isBackReady =
controller.responseIdCardDriverEgyptBack.isNotEmpty;
return MyElevatedButton(
title: 'Save New Car'.tr,
// تعطيل الزر إذا لم تكتمل البيانات
onPressed: _handleSaveCar,
kolor: (isFrontReady && isBackReady)
? AppColor.primaryColor
: Colors.grey,
);
})
],
),
),
)
],
);
}
// منطق الحفظ (يربط الـ AI بالـ DriverCarController)
void _handleSaveCar() {
final aiFront = Get.find<AI>().responseIdCardDriverEgyptFront;
final aiBack = Get.find<AI>().responseIdCardDriverEgyptBack;
// استدعاء دالة الإضافة في كنترولر السيارات
Get.find<DriverCarController>().addNewCarToAccount(
vin: aiBack['chassis'].toString(),
plate: aiFront['car_plate'].toString(), // اللوحة من الأمام
make: aiBack['make'].toString(),
model: aiBack['model'].toString(),
year: aiBack['year'].toString(),
expiryDate: aiFront['LicenseExpirationDate'].toString(),
color: aiBack['color'].toString(),
colorHex: aiBack['color_hex'].toString(),
owner: aiFront['owner'].toString(),
address: aiFront['address'].toString(),
inspectionDate: aiBack['inspection_date'].toString(), // تاريخ الفحص
displacement: aiBack['displacement'].toString(), // السعة اللترية
fuel: aiBack['fuel'].toString(),
);
}
}
// --- Widget الوجه الأمامي ---
GetBuilder<AI> egyptCarLicenceFront() {
return GetBuilder<AI>(
builder: (ai) {
if (ai.responseIdCardDriverEgyptFront.isNotEmpty) {
final licenseExpiryDate = DateTime.tryParse(
ai.responseIdCardDriverEgyptFront['LicenseExpirationDate'] ??
'') ??
DateTime.now();
final isLicenseExpired = licenseExpiryDate.isBefore(DateTime.now());
return Card(
elevation: 4.0,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.0)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Vehicle Details Front'.tr,
style: AppStyle.headTitle2),
IconButton(
// إعادة الرفع
onPressed: () => ai.allMethodForAI('car_front'),
icon: const Icon(Icons.refresh,
color: AppColor.primaryColor),
),
],
),
const Divider(color: AppColor.accentColor),
_infoRow('Plate Number'.tr,
ai.responseIdCardDriverEgyptFront['car_plate']),
_infoRow('Owner Name'.tr,
ai.responseIdCardDriverEgyptFront['owner']),
_infoRow(
'Address'.tr, ai.responseIdCardDriverEgyptFront['address']),
Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('License Expiry Date'.tr),
Text(
licenseExpiryDate.toString().split(' ')[0],
style: TextStyle(
fontWeight: FontWeight.bold,
color: isLicenseExpired ? Colors.red : Colors.green,
),
),
],
),
),
],
),
),
);
}
// حالة الانتظار (زر الرفع)
return Card(
child: InkWell(
onTap: () => ai.allMethodForAI('car_front'), // ✅ هنا التفعيل
child: Column(
children: [
Image.asset(
'assets/images/3.png',
height: Get.height * .20,
fit: BoxFit.contain,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text('Capture Car License (Front)'.tr,
style: AppStyle.title),
),
],
),
),
);
},
);
}
// --- Widget الوجه الخلفي ---
GetBuilder<AI> egyptCarLicenceBack() {
return GetBuilder<AI>(
builder: (ai) {
if (ai.responseIdCardDriverEgyptBack.isNotEmpty) {
// منطق تواريخ الفحص والضريبة
final inspectionDateStr =
ai.responseIdCardDriverEgyptBack['inspection_date'] ?? '';
return Card(
elevation: 4.0,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.0)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Vehicle Details Back'.tr, style: AppStyle.headTitle2),
IconButton(
// إعادة الرفع
onPressed: () => ai.allMethodForAI('car_back'),
icon: const Icon(Icons.refresh,
color: AppColor.primaryColor),
),
],
),
const Divider(color: AppColor.accentColor),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: _infoRow('Make'.tr,
ai.responseIdCardDriverEgyptBack['make'])),
Expanded(
child: _infoRow('Model'.tr,
ai.responseIdCardDriverEgyptBack['model'])),
],
),
_infoRow('Year'.tr, ai.responseIdCardDriverEgyptBack['year']),
_infoRow(
'Chassis'.tr, ai.responseIdCardDriverEgyptBack['chassis']),
Row(
children: [
Expanded(
child: _infoRow('Color'.tr,
ai.responseIdCardDriverEgyptBack['color'])),
// عرض دائرة اللون
if (ai.responseIdCardDriverEgyptBack['color_hex'] != null)
Container(
width: 20,
height: 20,
margin: const EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
color: Color(int.parse(ai
.responseIdCardDriverEgyptBack['color_hex']
.toString()
.replaceFirst('#', '0xff'))),
shape: BoxShape.circle,
border: Border.all(color: Colors.grey)),
)
],
),
_infoRow('Displacement'.tr,
"${ai.responseIdCardDriverEgyptBack['displacement']} cc"),
_infoRow('Fuel'.tr, ai.responseIdCardDriverEgyptBack['fuel']),
_infoRow('Inspection Date'.tr, inspectionDateStr),
],
),
),
);
}
// حالة الانتظار
return Card(
child: InkWell(
onTap: () => ai.allMethodForAI('car_back'), // ✅ هنا التفعيل
child: Column(
children: [
Image.asset(
'assets/images/4.png',
height: Get.height * .20,
fit: BoxFit.contain,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text('Capture Car License (Back)'.tr,
style: AppStyle.title),
),
],
),
),
);
},
);
}
// Helper Widget
Widget _infoRow(String label, String? value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("$label:", style: const TextStyle(color: Colors.grey)),
Expanded(
child: Text(value ?? "---",
textAlign: TextAlign.end,
style: const TextStyle(fontWeight: FontWeight.bold)),
),
],
),
);
}