376 lines
14 KiB
Dart
Executable File
376 lines
14 KiB
Dart
Executable File
import 'dart:io';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
|
|
import 'package:sefer_driver/constant/box_name.dart';
|
|
import 'package:sefer_driver/constant/links.dart';
|
|
import 'package:sefer_driver/controller/functions/upload_image.dart';
|
|
import 'package:sefer_driver/controller/home/captin/home_captain_controller.dart';
|
|
import 'package:sefer_driver/device_compatibility_page.dart';
|
|
import 'package:sefer_driver/main.dart';
|
|
|
|
// استيراد الصفحات الأخرى... تأكد من صحة المسارات
|
|
import 'package:sefer_driver/views/Rate/rate_app_page.dart';
|
|
import 'package:sefer_driver/views/auth/captin/contact_us_page.dart';
|
|
import 'package:sefer_driver/views/auth/captin/invite_driver_screen.dart';
|
|
import 'package:sefer_driver/views/notification/available_rides_page.dart';
|
|
import 'package:sefer_driver/views/auth/captin/logout_captain.dart';
|
|
import 'package:sefer_driver/views/home/Captin/history/history_captain.dart';
|
|
import 'package:sefer_driver/views/home/Captin/home_captain/help_captain.dart';
|
|
import 'package:sefer_driver/views/home/Captin/About Us/settings_captain.dart';
|
|
import 'package:sefer_driver/views/home/my_wallet/walet_captain.dart';
|
|
import 'package:sefer_driver/views/home/profile/profile_captain.dart';
|
|
import 'package:sefer_driver/views/notification/notification_captain.dart';
|
|
import 'package:url_launcher/url_launcher.dart';
|
|
import '../../../../constant/colors.dart';
|
|
import '../About Us/video_page.dart';
|
|
import '../assurance_health_page.dart';
|
|
import '../maintain_center_page.dart';
|
|
|
|
// 1. إنشاء Class لتعريف بيانات كل عنصر في القائمة
|
|
class DrawerItem {
|
|
final String title;
|
|
final IconData icon;
|
|
final Color color;
|
|
final VoidCallback onTap;
|
|
|
|
DrawerItem(
|
|
{required this.title,
|
|
required this.icon,
|
|
required this.color,
|
|
required this.onTap});
|
|
}
|
|
|
|
// --- الويدجت الرئيسية للقائمة الجانبية ---
|
|
class AppDrawer extends StatelessWidget {
|
|
AppDrawer({super.key});
|
|
|
|
final ImageController imageController = Get.put(ImageController());
|
|
|
|
// 2. تعريف بيانات القائمة بشكل مركزي ومنظم
|
|
final List<DrawerItem> drawerItems = [
|
|
DrawerItem(
|
|
title: 'Balance'.tr,
|
|
icon: Icons.account_balance_wallet,
|
|
color: Colors.green,
|
|
onTap: () => Get.to(() => WalletCaptainRefactored())),
|
|
DrawerItem(
|
|
title: 'Profile'.tr,
|
|
icon: Icons.person,
|
|
color: Colors.blue,
|
|
onTap: () => Get.to(() => ProfileCaptain())),
|
|
DrawerItem(
|
|
title: 'History of Trip'.tr,
|
|
icon: Icons.history,
|
|
color: Colors.orange,
|
|
onTap: () => Get.to(() => const HistoryCaptain())),
|
|
DrawerItem(
|
|
title: 'Available for rides'.tr,
|
|
icon: Icons.drive_eta,
|
|
color: Colors.teal,
|
|
onTap: () => Get.to(() => const AvailableRidesPage())),
|
|
DrawerItem(
|
|
title: 'Notifications'.tr,
|
|
icon: Icons.notifications,
|
|
color: Colors.purple,
|
|
onTap: () => Get.to(() => const NotificationCaptain())),
|
|
DrawerItem(
|
|
title: 'Helping Center'.tr,
|
|
icon: Icons.help_center,
|
|
color: Colors.cyan,
|
|
onTap: () => Get.to(() => HelpCaptain())),
|
|
DrawerItem(
|
|
title: 'Share App'.tr,
|
|
icon: Icons.share,
|
|
color: Colors.indigo,
|
|
onTap: () => Get.to(() => InviteScreen())),
|
|
// DrawerItem(
|
|
// title: 'Maintenance Center'.tr,
|
|
// icon: Icons.build,
|
|
// color: Colors.brown,
|
|
// onTap: () => Get.to(() => MaintainCenterPage())),
|
|
// DrawerItem(
|
|
// title: 'Health Insurance'.tr,
|
|
// icon: Icons.favorite,
|
|
// color: Colors.pink,
|
|
// onTap: () => Get.to(() => AssuranceHealthPage())),
|
|
DrawerItem(
|
|
title: 'Contact Us'.tr,
|
|
icon: Icons.email,
|
|
color: Colors.blueGrey,
|
|
onTap: () => Get.to(() => ContactUsPage())),
|
|
DrawerItem(
|
|
title: 'Videos Tutorials'.tr,
|
|
icon: Icons.video_library,
|
|
color: Colors.redAccent,
|
|
onTap: () => Get.to(() => VideoListPage())),
|
|
DrawerItem(
|
|
title: 'Rate Our App'.tr,
|
|
icon: Icons.star,
|
|
color: Colors.amber,
|
|
onTap: () => Get.to(() => RatingScreen())),
|
|
DrawerItem(
|
|
title: 'Is device compatible'.tr,
|
|
icon: Icons.memory,
|
|
color: Colors.greenAccent,
|
|
onTap: () => Get.to(() => DeviceCompatibilityPage())),
|
|
DrawerItem(
|
|
title: 'Privacy Policy'.tr,
|
|
icon: Icons.memory,
|
|
color: Colors.greenAccent,
|
|
onTap: () =>
|
|
launchUrl(Uri.parse('${AppLink.server}/privacy_policy.php'))),
|
|
DrawerItem(
|
|
title: 'Settings'.tr,
|
|
icon: Icons.settings,
|
|
color: Colors.grey.shade600,
|
|
onTap: () => Get.to(() => const SettingsCaptain())),
|
|
];
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Drawer(
|
|
child: Container(
|
|
color: Theme.of(context).scaffoldBackgroundColor,
|
|
child: Column(
|
|
children: [
|
|
// --- الجزء العلوي من القائمة (بيانات المستخدم) ---
|
|
UserHeader(), // استخدمنا الويدجت المحسنة بالأسفل
|
|
|
|
// --- قائمة العناصر المتحركة ---
|
|
Expanded(
|
|
child: AnimationLimiter(
|
|
child: ListView.builder(
|
|
padding: const EdgeInsets.all(8.0),
|
|
itemCount: drawerItems.length + 1, // +1 لزر تسجيل الخروج
|
|
itemBuilder: (BuildContext context, int index) {
|
|
// --- زر تسجيل الخروج في النهاية ---
|
|
if (index == drawerItems.length) {
|
|
return AnimationConfiguration.staggeredList(
|
|
position: index,
|
|
duration: const Duration(milliseconds: 375),
|
|
child: SlideAnimation(
|
|
verticalOffset: 50.0,
|
|
child: FadeInAnimation(
|
|
child: _DrawerItemTile(
|
|
item: DrawerItem(
|
|
title: 'Sign Out'.tr,
|
|
icon: Icons.logout,
|
|
color: Colors.red,
|
|
onTap: () =>
|
|
Get.to(() => const LogoutCaptain())),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
// --- بقية العناصر ---
|
|
final item = drawerItems[index];
|
|
return AnimationConfiguration.staggeredList(
|
|
position: index,
|
|
duration: const Duration(milliseconds: 375),
|
|
child: SlideAnimation(
|
|
verticalOffset: 50.0,
|
|
child: FadeInAnimation(
|
|
child: _DrawerItemTile(item: item),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
// --- ويدجت خاصة بكل عنصر في القائمة ---
|
|
class _DrawerItemTile extends StatelessWidget {
|
|
final DrawerItem item;
|
|
const _DrawerItemTile({required this.item});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
|
child: ListTile(
|
|
leading: Container(
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
color: item.color.withOpacity(0.1),
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Icon(item.icon, color: item.color, size: 24),
|
|
),
|
|
title: Text(
|
|
item.title,
|
|
style: Theme.of(context)
|
|
.textTheme
|
|
.titleMedium
|
|
?.copyWith(fontWeight: FontWeight.w500),
|
|
),
|
|
onTap: () {
|
|
Get.back(); // لإغلاق القائمة عند الضغط
|
|
Future.delayed(const Duration(milliseconds: 250), () {
|
|
item.onTap(); // الانتقال للصفحة بعد تأخير بسيط لإظهار الأنيميشن
|
|
});
|
|
},
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
|
splashColor: item.color.withOpacity(0.2),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
// --- ويدجت محسنة للجزء العلوي من القائمة ---
|
|
// ... (الاستيرادات السابقة تبقى كما هي)
|
|
|
|
// --- تم تعديل UserHeader لإضافة التحقق من الصورة ---
|
|
class UserHeader extends StatelessWidget {
|
|
UserHeader({super.key});
|
|
final ImageController imageController = Get.find<ImageController>();
|
|
final HomeCaptainController homeCaptainController =
|
|
Get.find<HomeCaptainController>();
|
|
|
|
// دالة لإظهار التنبيه
|
|
void _showUploadPhotoDialog(
|
|
BuildContext context, ImageController controller) {
|
|
// نستخدم addPostFrameCallback لضمان عدم ظهور الخطأ أثناء بناء الواجهة
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
// نتأكد ألا يكون هناك dialog مفتوح بالفعل لتجنب التكرار
|
|
if (Get.isDialogOpen == true) return;
|
|
|
|
Get.defaultDialog(
|
|
title: "Profile Photo Required".tr,
|
|
titleStyle:
|
|
const TextStyle(color: Colors.red, fontWeight: FontWeight.bold),
|
|
middleText:
|
|
"Please upload a clear photo of your face to be identified by passengers."
|
|
.tr,
|
|
barrierDismissible: false, // منع الإغلاق بالضغط خارج النافذة
|
|
radius: 15,
|
|
contentPadding: const EdgeInsets.all(20),
|
|
confirm: ElevatedButton.icon(
|
|
onPressed: () {
|
|
Get.back(); // إغلاق النافذة الحالية
|
|
// فتح الكاميرا فوراً
|
|
controller.choosImagePicture(
|
|
AppLink.uploadImagePortrate, 'portrait');
|
|
},
|
|
icon: const Icon(Icons.camera_alt, color: Colors.white),
|
|
label: Text("Take Photo Now".tr,
|
|
style: const TextStyle(color: Colors.white)),
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: AppColor
|
|
.primaryColor, // تأكد من وجود هذا اللون أو استبدله بـ Colors.blue
|
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
|
),
|
|
),
|
|
cancel: TextButton(
|
|
onPressed: () => Get.back(),
|
|
child: Text("Later".tr, style: const TextStyle(color: Colors.grey)),
|
|
),
|
|
);
|
|
});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return UserAccountsDrawerHeader(
|
|
accountName: Text(
|
|
box.read(BoxName.nameDriver).toString(),
|
|
style: const TextStyle(
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: 18,
|
|
shadows: [Shadow(blurRadius: 2, color: Colors.black26)]),
|
|
),
|
|
accountEmail:
|
|
box.read(BoxName.emailDriver).toString().contains('intaleqapp')
|
|
? Text('Your email not updated yet'.tr)
|
|
: Text(box.read(BoxName.emailDriver)),
|
|
currentAccountPicture: GetBuilder<ImageController>(
|
|
builder: (controller) => Stack(
|
|
clipBehavior: Clip.none,
|
|
children: [
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
border: Border.all(color: Colors.white, width: 2),
|
|
boxShadow: [
|
|
BoxShadow(color: Colors.black.withOpacity(0.3), blurRadius: 5)
|
|
],
|
|
),
|
|
child: controller.isloading
|
|
? const CircularProgressIndicator(color: Colors.white)
|
|
: CircleAvatar(
|
|
// محاولة تحميل الصورة
|
|
backgroundImage: NetworkImage(
|
|
'${AppLink.server}/portrate_captain_image/${box.read(BoxName.driverID)}.jpg'),
|
|
|
|
// [تعديل هام]: في حال فشل تحميل الصورة (غير موجودة)
|
|
onBackgroundImageError: (exception, stackTrace) {
|
|
// طباعة الخطأ في الكونسول للتوضيح
|
|
debugPrint(
|
|
"Profile image not found or error loading: $exception");
|
|
// استدعاء نافذة التنبيه
|
|
_showUploadPhotoDialog(context, controller);
|
|
},
|
|
|
|
// أيقونة بديلة تظهر في الخلفية إذا لم تكن الصورة موجودة
|
|
backgroundColor: Colors.grey.shade300,
|
|
child: const Icon(Icons.person,
|
|
size: 40, color: Colors.white),
|
|
),
|
|
),
|
|
Positioned(
|
|
bottom: -5,
|
|
right: -5,
|
|
child: InkWell(
|
|
onTap: () => controller.choosImagePicture(
|
|
AppLink.uploadImagePortrate, 'portrait'),
|
|
child: Container(
|
|
padding: const EdgeInsets.all(4),
|
|
decoration: const BoxDecoration(
|
|
color: Colors.white,
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Icon(Icons.camera_alt,
|
|
color: Theme.of(context).primaryColor, size: 18),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
otherAccountsPictures: [
|
|
Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Text(
|
|
homeCaptainController.rating.toString(),
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: 16),
|
|
),
|
|
const SizedBox(width: 4),
|
|
const Icon(Icons.star, color: Colors.amber, size: 20),
|
|
],
|
|
),
|
|
],
|
|
decoration: BoxDecoration(
|
|
gradient: LinearGradient(
|
|
colors: [Theme.of(context).primaryColor, Colors.blue.shade700],
|
|
begin: Alignment.topLeft,
|
|
end: Alignment.bottomRight,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|