Update codebase

This commit is contained in:
Hamza-Ayed
2026-08-09 16:56:13 +03:00
parent 95e2e4f35d
commit b64debaa88
1058 changed files with 164327 additions and 113928 deletions
@@ -1,7 +1,7 @@
import 'package:tripz_driver/constant/box_name.dart';
import 'package:tripz_driver/constant/style.dart';
import 'package:tripz_driver/main.dart';
import 'package:tripz_driver/views/widgets/my_scafold.dart';
import 'package:siro_driver/constant/box_name.dart';
import 'package:siro_driver/constant/style.dart';
import 'package:siro_driver/main.dart';
import 'package:siro_driver/views/widgets/my_scafold.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
@@ -26,7 +26,7 @@ class AboutPage extends StatelessWidget {
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'Tripz LLC\n${(box.read(BoxName.countryCode)?.toString() ?? 'Syria').tr}',
'Siro LLC\n${(box.read(BoxName.countryCode)?.toString() ?? 'Syria').tr}',
style: AppStyle.headTitle2,
textAlign: TextAlign.center,
),
@@ -34,7 +34,7 @@ class AboutPage extends StatelessWidget {
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
'Tripz is a ride-sharing app designed with your safety and affordability in mind. We connect you with reliable drivers in your area, ensuring a convenient and stress-free travel experience.\n\nHere are some of the key features that set us apart:'
'Siro is a ride-sharing app designed with your safety and affordability in mind. We connect you with reliable drivers in your area, ensuring a convenient and stress-free travel experience.\n\nHere are some of the key features that set us apart:'
.tr,
style: AppStyle.title,
textAlign: TextAlign.center,
@@ -1,5 +1,5 @@
import 'package:tripz_driver/views/widgets/my_scafold.dart';
import 'package:tripz_driver/views/widgets/mydialoug.dart';
import 'package:siro_driver/views/widgets/my_scafold.dart';
import 'package:siro_driver/views/widgets/mydialoug.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
@@ -28,7 +28,7 @@ class FrequentlyQuestionsPage extends StatelessWidget {
),
children: [
Text(
'Step-by-step instructions on how to request a ride through the Tripz app.'
'Step-by-step instructions on how to request a ride through the Siro app.'
.tr,
style: AppStyle.title,
),
@@ -43,7 +43,7 @@ class FrequentlyQuestionsPage extends StatelessWidget {
),
children: [
Text(
'Tripz offers a variety of vehicle options to suit your needs, including economy, comfort, and luxury. Choose the option that best fits your budget and passenger count.'
'Siro offers a variety of vehicle options to suit your needs, including economy, comfort, and luxury. Choose the option that best fits your budget and passenger count.'
.tr,
style: AppStyle.title,
),
@@ -58,7 +58,7 @@ class FrequentlyQuestionsPage extends StatelessWidget {
),
children: [
Text(
'Tripz offers multiple payment methods for your convenience. Choose between cash payment or credit/debit card payment during ride confirmation.'
'Siro offers multiple payment methods for your convenience. Choose between cash payment or credit/debit card payment during ride confirmation.'
.tr,
style: AppStyle.title,
),
@@ -73,7 +73,7 @@ class FrequentlyQuestionsPage extends StatelessWidget {
),
children: [
Text(
'Yes, you can cancel your ride under certain conditions (e.g., before driver is assigned). See the Tripz cancellation policy for details.'
'Yes, you can cancel your ride under certain conditions (e.g., before driver is assigned). See the Siro cancellation policy for details.'
.tr,
style: AppStyle.title,
),
@@ -98,7 +98,7 @@ class FrequentlyQuestionsPage extends StatelessWidget {
});
},
child: Text(
'Visit our website or contact Tripz support for information on driver registration and requirements.'
'Visit our website or contact Siro support for information on driver registration and requirements.'
.tr,
style: AppStyle.title,
),
@@ -115,22 +115,22 @@ class FrequentlyQuestionsPage extends StatelessWidget {
),
children: [
Text(
'Tripz provides in-app chat functionality to allow you to communicate with your driver or passenger during your ride.'
'Siro provides in-app chat functionality to allow you to communicate with your driver or passenger during your ride.'
.tr,
style: AppStyle.title,
),
],
),
// Question 8: What safety measures does Tripz offer?
// Question 8: What safety measures does Siro offer?
ExpansionTile(
title: Text(
'What safety measures does Tripz offer?'.tr,
'What safety measures does Siro offer?'.tr,
style: AppStyle.title,
),
children: [
Text(
'Tripz prioritizes your safety. We offer features like driver verification, in-app trip tracking, and emergency contact options.'
'Siro prioritizes your safety. We offer features like driver verification, in-app trip tracking, and emergency contact options.'
.tr,
style: AppStyle.title,
),
@@ -1,14 +1,13 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:tripz_driver/constant/colors.dart';
import 'package:tripz_driver/controller/profile/setting_controller.dart';
import 'package:tripz_driver/views/lang/languages.dart';
import 'package:tripz_driver/views/widgets/my_scafold.dart';
import 'package:tripz_driver/views/widgets/mydialoug.dart';
import 'package:siro_driver/constant/colors.dart';
import 'package:siro_driver/controller/profile/setting_controller.dart';
import 'package:siro_driver/views/lang/languages.dart';
import 'package:siro_driver/views/widgets/mydialoug.dart';
// تأكد من صحة مسارات الاستيراد هذه
import '../../../../controller/functions/vibrate.dart'; // Controller with isVibrate
import '../../../auth/country_widget.dart';
import '../../../widgets/ui/siro_ui.dart';
import 'about_us.dart';
import 'frequantly_question.dart';
import 'using_app_page.dart';
@@ -22,15 +21,13 @@ class SettingsCaptain extends StatelessWidget {
final settingsController = Get.put(SettingController());
final homeController = Get.put(HomePageController());
return MyScafolld(
return SiroPage(
title: 'Settings'.tr,
isleading: true,
body: [
ListView(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 20.0),
padding: SiroUi.pageInsets,
body: ListView(
children: <Widget>[
// --- القسم الأول: عام ---
_buildSectionHeader('General'.tr, context),
SiroSectionTitle('General'.tr),
_buildSettingsCard(
children: [
_buildListTile(
@@ -53,10 +50,8 @@ class SettingsCaptain extends StatelessWidget {
// ),
],
),
const SizedBox(height: 20),
// --- القسم الثاني: تفضيلات التطبيق ---
_buildSectionHeader('App Preferences'.tr, context),
SiroSectionTitle('App Preferences'.tr),
_buildSettingsCard(
children: [
_buildSwitchTile(
@@ -96,10 +91,8 @@ class SettingsCaptain extends StatelessWidget {
),
],
),
const SizedBox(height: 20),
// --- القسم الثالث: المساعدة والدعم ---
_buildSectionHeader('Help & Support'.tr, context),
SiroSectionTitle('Help & Support'.tr),
_buildSettingsCard(
children: [
_buildListTile(
@@ -119,18 +112,17 @@ class SettingsCaptain extends StatelessWidget {
),
],
),
const SizedBox(height: 20),
// --- القسم الرابع: تسجيل الخروج ---
_buildSectionHeader('Account'.tr, context),
SiroSectionTitle('Account'.tr),
_buildSettingsCard(
children: [
ListTile(
leading: const Icon(Icons.logout, color: Colors.red),
leading: const SiroIconBadge(Icons.logout_rounded,
color: AppColor.redColor),
title: Text(
'Logout'.tr,
style: const TextStyle(
color: Colors.red, fontWeight: FontWeight.w500),
color: AppColor.redColor, fontWeight: FontWeight.w600),
),
onTap: () {
MyDialog().getDialog(
@@ -145,34 +137,17 @@ class SettingsCaptain extends StatelessWidget {
},
)
],
)
),
const SizedBox(height: 16),
],
),
],
);
}
// ويدجت لبناء عنوان كل قسم
Widget _buildSectionHeader(String title, BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 8.0, bottom: 12.0),
child: Text(
title,
style: Theme.of(context).textTheme.titleSmall?.copyWith(
color: Colors.grey.shade600,
fontWeight: FontWeight.bold,
),
),
);
}
// ويدجت لبناء بطاقة الإعدادات
// ويدجت لبناء بطاقة الإعدادات — تجمع عناصر القسم داخل سطح واحد.
Widget _buildSettingsCard({required List<Widget> children}) {
return Card(
elevation: 2,
shadowColor: Colors.black.withOpacity(0.1),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
clipBehavior: Clip.antiAlias, // مهم لجعل splash effect داخل حدود البطاقة
return SiroCard(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Column(children: children),
);
}
@@ -184,14 +159,18 @@ class SettingsCaptain extends StatelessWidget {
String? subtitle,
required VoidCallback onTap,
}) {
return ListTile(
leading: Icon(icon, color: Colors.grey.shade700),
title: Text(title, style: const TextStyle(fontWeight: FontWeight.w500)),
subtitle: subtitle != null ? Text(subtitle) : null,
trailing:
const Icon(Icons.arrow_forward_ios, size: 16, color: Colors.grey),
onTap: onTap,
);
return Builder(builder: (context) {
return ListTile(
leading: SiroIconBadge(icon, color: SiroUi.interactive(context)),
title: Text(title, style: const TextStyle(fontWeight: FontWeight.w600)),
subtitle: subtitle != null
? Text(subtitle, style: Theme.of(context).textTheme.bodySmall)
: null,
trailing: Icon(Icons.arrow_forward_ios,
size: 14, color: SiroUi.subtle(context)),
onTap: onTap,
);
});
}
// ويدجت لبناء عنصر يحتوي على مفتاح تفعيل/إلغاء (Switch)
@@ -207,15 +186,19 @@ class SettingsCaptain extends StatelessWidget {
return GetBuilder<T>(
init: controller,
builder: (ctrl) {
return SwitchListTile(
secondary: Icon(icon, color: color ?? Colors.grey.shade700),
title:
Text(title, style: const TextStyle(fontWeight: FontWeight.w500)),
subtitle: Text(subtitle),
value: valueGetter(ctrl),
onChanged: (value) => onChanged(ctrl),
activeColor: AppColor.primaryColor,
);
return Builder(builder: (context) {
return SwitchListTile(
secondary: SiroIconBadge(icon,
color: color ?? SiroUi.interactive(context)),
title:
Text(title, style: const TextStyle(fontWeight: FontWeight.w600)),
subtitle: Text(subtitle,
style: Theme.of(context).textTheme.bodySmall),
value: valueGetter(ctrl),
onChanged: (value) => onChanged(ctrl),
activeThumbColor: SiroUi.interactive(context),
);
});
},
);
}
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:tripz_driver/views/widgets/my_scafold.dart';
import 'package:siro_driver/views/widgets/my_scafold.dart';
// 1. إنشاء Class لتمثيل بيانات كل سؤال وجواب
class FaqItem {
@@ -43,13 +43,13 @@ class UsingAppPage extends StatelessWidget {
question: "What is the feature of our wallet?".tr,
icon: Icons.account_balance_wallet_outlined,
answer: Text(
'''Tripz Wallet Features:
'''Siro Wallet Features:
- Transfer money multiple times.
- Transfer to anyone.
- Make purchases.
- Charge your account.
- Charge a friend's Tripz account.
- Charge a friend's Siro account.
- Store your money with us and receive it in your bank as a monthly salary.'''
.tr,
style:
@@ -57,10 +57,10 @@ class UsingAppPage extends StatelessWidget {
),
),
FaqItem(
question: "What is Types of Trips in Tripz?".tr,
question: "What is Types of Trips in Siro?".tr,
icon: Icons.map_outlined,
answer: Text(
'''Types of Trips in Tripz:
'''Types of Trips in Siro:
- Comfort: For cars newer than 2017 with air conditioning.
- Lady: For girl drivers.
@@ -1,81 +1,70 @@
import 'package:tripz_driver/constant/info.dart';
import 'package:siro_driver/constant/info.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:video_player/video_player.dart';
import 'package:youtube_player_flutter/youtube_player_flutter.dart';
import '../../../../controller/home/captin/help/video_controller.dart';
import 'package:flutter/cupertino.dart';
import '../../../widgets/ui/siro_ui.dart';
class VideoListPage extends StatelessWidget {
VideoListPage({super.key});
final VideoController videoController = Get.put(VideoController());
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('Videos Tutorials'.tr),
),
child: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 10.0), // Outer padding around the list
child: GetBuilder<VideoController>(
builder: (videoController) {
return ListView.builder(
itemCount: videoController.videos.length,
itemBuilder: (context, index) {
final video = videoController.videos[index];
return Container(
margin: const EdgeInsets.symmetric(
vertical: 8.0), // Spacing between each card
decoration: BoxDecoration(
color: CupertinoColors.white,
borderRadius:
BorderRadius.circular(12.0), // Rounded corners
boxShadow: [
BoxShadow(
color: CupertinoColors.systemGrey.withOpacity(0.3),
offset: const Offset(
0, 4), // Offset for shadow to appear below
blurRadius: 10.0, // Blur for softer shadow effect
),
],
border: Border.all(
color: CupertinoColors.systemGrey4,
width: 0.5, // Subtle border for a refined iOS-like look
),
),
child: CupertinoListTile(
title: Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
video['title'],
style: const TextStyle(
color: CupertinoColors.black,
fontWeight: FontWeight.bold,
return SiroPage(
title: 'Videos Tutorials'.tr,
padding: SiroUi.pageInsets,
body: GetBuilder<VideoController>(
builder: (videoController) {
if (videoController.videos.isEmpty) {
return SiroEmptyState(
icon: Icons.video_library_rounded,
title: 'No videos available'.tr,
);
}
return ListView.builder(
itemCount: videoController.videos.length,
itemBuilder: (context, index) {
final video = videoController.videos[index];
return SiroCard(
onTap: () =>
Get.to(() => VideoPlayerPage1(videoUrl: video['url'])),
child: Row(
children: [
SiroIconBadge(Icons.play_arrow_rounded,
color: SiroUi.interactive(context), size: 24),
const SizedBox(width: 14),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
video['title'] ?? '',
style: Theme.of(context)
.textTheme
.bodyMedium
?.copyWith(fontWeight: FontWeight.bold),
),
),
const SizedBox(height: 3),
Text(
video['description'] ?? '',
style: Theme.of(context).textTheme.bodySmall,
),
],
),
subtitle: Text(
video['description'],
style: const TextStyle(
color: CupertinoColors.systemGrey,
),
),
onTap: () {
// Navigate to video player page (iOS-style)
Get.to(() => VideoPlayerPage1(videoUrl: video['url']));
},
),
);
},
Icon(Icons.arrow_forward_ios_rounded,
size: 13, color: SiroUi.subtle(context)),
],
),
);
},
),
),
);
},
),
);
}
@@ -84,7 +73,7 @@ class VideoListPage extends StatelessWidget {
class VideoPlayerPage extends StatelessWidget {
final String videoUrl;
VideoPlayerPage({required this.videoUrl});
VideoPlayerPage({super.key, required this.videoUrl});
final VideoController videoController = Get.put(VideoController());
@@ -93,51 +82,45 @@ class VideoPlayerPage extends StatelessWidget {
// Initialize the video when the page is loaded
videoController.initializeVideo(videoUrl);
return CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(
middle: Text(AppInformation.appName),
),
child: SafeArea(
child: Center(
child: GetBuilder<VideoController>(
builder: (controller) {
if (!controller.videoPlayerController.value.isInitialized) {
return const CircularProgressIndicator(); // Show loading indicator while initializing
}
return SiroPage(
title: AppInformation.appName,
body: Center(
child: GetBuilder<VideoController>(
builder: (controller) {
if (!controller.videoPlayerController.value.isInitialized) {
return const SiroLoading();
}
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Video player widget
AspectRatio(
aspectRatio:
controller.videoPlayerController.value.aspectRatio,
// child: VideoPlayer(controller.videoPlayerController),
child: VideoPlayer(controller.videoPlayerController),
),
const SizedBox(height: 20),
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Video player widget
AspectRatio(
aspectRatio:
controller.videoPlayerController.value.aspectRatio,
child: VideoPlayer(controller.videoPlayerController),
),
const SizedBox(height: 20),
// Play/pause button
CupertinoButton(
onPressed: () {
if (controller.videoPlayerController.value.isPlaying) {
controller.pause();
} else {
controller.play();
}
},
child: Icon(
controller.videoPlayerController.value.isPlaying
? CupertinoIcons.pause
: CupertinoIcons.play_arrow,
color: CupertinoColors.activeBlue,
size: 30,
),
// Play/pause button
IconButton.filled(
iconSize: 32,
onPressed: () {
if (controller.videoPlayerController.value.isPlaying) {
controller.pause();
} else {
controller.play();
}
},
icon: Icon(
controller.videoPlayerController.value.isPlaying
? Icons.pause_rounded
: Icons.play_arrow_rounded,
),
],
);
},
),
),
],
);
},
),
),
);
@@ -147,15 +130,26 @@ class VideoPlayerPage extends StatelessWidget {
class VideoPlayerPage1 extends StatelessWidget {
final String videoUrl;
const VideoPlayerPage1({required this.videoUrl});
const VideoPlayerPage1({super.key, required this.videoUrl});
@override
Widget build(BuildContext context) {
// Extract the video ID from the URL
String videoId = YoutubePlayer.convertUrlToId(videoUrl)!;
final String? videoId = YoutubePlayer.convertUrlToId(videoUrl);
// Create a YoutubePlayerController
final YoutubePlayerController _controller = YoutubePlayerController(
// رابط غير صالح كان يرمي `Null check operator used on a null value`
// ويُسقط الشاشة بيضاء بدل رسالة مفهومة.
if (videoId == null) {
return SiroPage(
title: AppInformation.appName,
body: SiroEmptyState(
icon: Icons.videocam_off_rounded,
title: 'Video unavailable'.tr,
),
);
}
final YoutubePlayerController controller = YoutubePlayerController(
initialVideoId: videoId,
flags: const YoutubePlayerFlags(
autoPlay: true,
@@ -166,24 +160,28 @@ class VideoPlayerPage1 extends StatelessWidget {
);
return Scaffold(
backgroundColor: Colors.black,
body: Stack(
children: [
// Full-screen YouTube player
Positioned.fill(
child: YoutubePlayer(
controller: _controller,
controller: controller,
showVideoProgressIndicator: true,
),
),
// Overlay back button in the top left corner for exit
Positioned(
top: 40.0,
left: 16.0,
child: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.white),
onPressed: () {
Navigator.pop(context);
},
// زر الخروج — كان `left` ثابتاً فيقع تحت الإبهام الخطأ في العربية
SafeArea(
child: PositionedDirectional(
top: 8,
start: 8,
child: CircleAvatar(
backgroundColor: Colors.black45,
child: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => Navigator.pop(context),
),
),
),
),
],
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:tripz_driver/constant/colors.dart';
import 'package:siro_driver/constant/colors.dart';
class BottomBarController extends GetxController {
var currentIndex = 0.obs;
@@ -1,10 +1,10 @@
// import 'package:flutter/material.dart';
// import 'package:get/get.dart';
// import 'package:tripz_driver/constant/colors.dart';
// import 'package:tripz_driver/constant/style.dart';
// import 'package:tripz_driver/controller/functions/camer_controller.dart';
// import 'package:tripz_driver/views/widgets/elevated_btn.dart';
// import 'package:tripz_driver/views/widgets/my_scafold.dart';
// import 'package:siro_driver/constant/colors.dart';
// import 'package:siro_driver/constant/style.dart';
// import 'package:siro_driver/controller/functions/camer_controller.dart';
// import 'package:siro_driver/views/widgets/elevated_btn.dart';
// import 'package:siro_driver/views/widgets/my_scafold.dart';
// class CameraWidgetCardId extends StatelessWidget {
// final CameraClassController cameraClassController =
@@ -1,10 +1,10 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:tripz_driver/constant/style.dart';
import 'package:tripz_driver/views/widgets/elevated_btn.dart';
import 'package:tripz_driver/controller/home/captin/map_driver_controller.dart';
import 'package:tripz_driver/constant/currency.dart';
import 'package:siro_driver/constant/style.dart';
import 'package:siro_driver/views/widgets/elevated_btn.dart';
import 'package:siro_driver/controller/home/captin/map_driver_controller.dart';
import 'package:siro_driver/constant/currency.dart';
import '../../../constant/colors.dart';
import '../../../controller/functions/location_controller.dart';
import '../../Rate/rate_passenger.dart';
@@ -1,11 +1,12 @@
import 'package:tripz_driver/constant/currency.dart';
import 'package:siro_driver/constant/currency.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import '../../../../constant/finance_design_system.dart';
import '../../../../constant/colors.dart';
import '../../../../controller/auth/captin/history_captain.dart';
import 'package:tripz_driver/views/widgets/mydialoug.dart';
import 'package:siro_driver/views/widgets/mydialoug.dart';
import '../../../widgets/ui/siro_ui.dart';
class HistoryCaptain extends StatelessWidget {
const HistoryCaptain({super.key});
@@ -15,14 +16,10 @@ class HistoryCaptain extends StatelessWidget {
Get.put(HistoryCaptainController());
return Scaffold(
backgroundColor: Colors.white,
body: GetBuilder<HistoryCaptainController>(
builder: (controller) {
if (controller.isloading) {
return Center(
child: CircularProgressIndicator(
color: FinanceDesignSystem.primaryDark),
);
return const SiroLoading();
}
final List trips = controller.historyData['message'] ?? [];
@@ -30,20 +27,24 @@ class HistoryCaptain extends StatelessWidget {
return CustomScrollView(
physics: const BouncingScrollPhysics(),
slivers: [
// 1. Custom App Bar
// 1. رأس بتدرّج العلامة — نفس تدرّج رأس القائمة الجانبية
SliverAppBar(
expandedHeight: 180,
expandedHeight: 170,
pinned: true,
stretch: true,
backgroundColor: FinanceDesignSystem.primaryDark,
foregroundColor: Colors.white,
backgroundColor: AppColor.primaryColor,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
titlePadding:
const EdgeInsets.symmetric(horizontal: 48, vertical: 14),
title: Text(
'Ride History'.tr,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 18,
fontSize: 17,
),
),
background: Stack(
@@ -51,11 +52,11 @@ class HistoryCaptain extends StatelessWidget {
children: [
Container(
decoration: BoxDecoration(
gradient: FinanceDesignSystem.balanceGradient,
gradient: SiroUi.brandGradient(context),
),
),
Positioned(
right: -50,
PositionedDirectional(
end: -50,
top: -20,
child: Icon(
Icons.history_rounded,
@@ -66,12 +67,11 @@ class HistoryCaptain extends StatelessWidget {
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(height: 40),
Text(
trips.length.toString(),
style: const TextStyle(
color: Colors.white,
fontSize: 40,
fontSize: 38,
fontWeight: FontWeight.w900,
),
),
@@ -79,10 +79,11 @@ class HistoryCaptain extends StatelessWidget {
'Total Rides'.tr,
style: TextStyle(
color: Colors.white.withValues(alpha: 0.7),
fontSize: 14,
fontSize: 13,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 34),
],
),
],
@@ -93,46 +94,16 @@ class HistoryCaptain extends StatelessWidget {
// 2. Trips List
if (trips.isEmpty)
SliverFillRemaining(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.all(32),
decoration: BoxDecoration(
color: Colors.grey.shade50,
shape: BoxShape.circle,
),
child: Icon(
Icons.history_toggle_off_rounded,
size: 64,
color: Colors.grey.shade300,
),
),
const SizedBox(height: 24),
Text(
'No Rides Yet'.tr,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.grey.shade600,
),
),
const SizedBox(height: 8),
Text(
'Your completed trips will appear here'.tr,
style: TextStyle(
fontSize: 14,
color: Colors.grey.shade400,
),
),
],
),
hasScrollBody: false,
child: SiroEmptyState(
icon: Icons.history_toggle_off_rounded,
title: 'No Rides Yet'.tr,
message: 'Your completed trips will appear here'.tr,
),
)
else
SliverPadding(
padding: const EdgeInsets.fromLTRB(16, 24, 16, 40),
padding: const EdgeInsets.fromLTRB(16, 20, 16, 32),
sliver: SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
@@ -197,141 +168,99 @@ class _TripHistoryCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(bottom: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.04),
blurRadius: 15,
offset: const Offset(0, 8),
),
],
),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(FinanceDesignSystem.cardRadius),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
final theme = Theme.of(context);
final accent = SiroUi.interactive(context);
return SiroCard(
onTap: onTap,
padding: const EdgeInsets.all(16),
child: Column(
children: [
Row(
children: [
SiroIconBadge(Icons.receipt_long_rounded, color: accent),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: FinanceDesignSystem.primaryDark
.withValues(alpha: 0.05),
borderRadius: BorderRadius.circular(12),
),
child: Icon(
Icons.receipt_long_rounded,
color: FinanceDesignSystem.primaryDark,
size: 20,
),
),
const SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${'OrderId'.tr} #${trip['order_id']}',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
color: FinanceDesignSystem.primaryDark,
),
),
Text(
_formatDateToSyria(trip['created_at']),
style: TextStyle(
fontSize: 11,
color: Colors.grey.shade500,
),
),
],
),
],
Text(
'${'OrderId'.tr} #${trip['order_id']}',
overflow: TextOverflow.ellipsis,
style: theme.textTheme.bodyMedium
?.copyWith(fontWeight: FontWeight.bold),
),
Text(
_formatDateToSyria(trip['created_at']),
style: theme.textTheme.bodySmall?.copyWith(fontSize: 11),
),
_buildStatusChip(trip['status']),
],
),
const SizedBox(height: 20),
const Divider(height: 1),
const SizedBox(height: 20),
Row(
),
const SizedBox(width: 8),
_buildStatusChip(trip['status']),
],
),
const SizedBox(height: 14),
const Divider(height: 1),
const SizedBox(height: 14),
Row(
children: [
Column(
children: [
Icon(Icons.circle, size: 11, color: accent),
Container(
width: 2,
height: 20,
color: SiroUi.border(context),
),
const Icon(Icons.location_on_rounded,
size: 14, color: AppColor.redColor),
],
),
const SizedBox(width: 14),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: [
Icon(Icons.circle,
size: 12, color: FinanceDesignSystem.accentBlue),
Container(
width: 2,
height: 20,
color: Colors.grey.shade200,
),
Icon(Icons.location_on_rounded,
size: 14, color: FinanceDesignSystem.dangerRed),
],
Text(
trip['start_name'] ?? 'Pickup Location'.tr,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: theme.textTheme.bodySmall
?.copyWith(fontWeight: FontWeight.w500),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
trip['start_name'] ?? 'Pickup Location'.tr,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
color: Colors.grey.shade700,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 12),
Text(
trip['end_name'] ?? 'Destination Location'.tr,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
color: Colors.grey.shade700,
fontWeight: FontWeight.w500,
),
),
],
const SizedBox(height: 12),
Text(
trip['end_name'] ?? 'Destination Location'.tr,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: theme.textTheme.bodySmall
?.copyWith(fontWeight: FontWeight.w500),
),
],
),
),
if (trip['price'] != null) ...[
const SizedBox(width: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'${trip['price']} ${CurrencyHelper.currency}',
style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w900,
color: AppColor.greenColor,
),
),
if (trip['price'] != null)
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'${trip['price']} ${CurrencyHelper.currency}',
style: TextStyle(
fontWeight: FontWeight.w900,
fontSize: 16,
color: FinanceDesignSystem.primaryDark,
),
),
const Icon(Icons.arrow_forward_ios_rounded,
size: 12, color: Colors.grey),
],
),
Icon(Icons.arrow_forward_ios_rounded,
size: 11, color: SiroUi.subtle(context)),
],
),
],
),
],
),
),
],
),
);
}
@@ -340,73 +269,33 @@ class _TripHistoryCard extends StatelessWidget {
Color color;
IconData icon;
String label = status ?? 'Unknown';
List<Color> gradientColors;
switch (status) {
case 'Apply':
color = FinanceDesignSystem.successGreen;
color = AppColor.greenColor;
icon = Icons.check_circle_rounded;
label = 'Completed'.tr;
gradientColors = [color.withOpacity(0.2), color.withOpacity(0.05)];
break;
case 'Refused':
color = FinanceDesignSystem.dangerRed;
color = AppColor.redColor;
icon = Icons.cancel_rounded;
label = 'Refused'.tr;
gradientColors = [color.withOpacity(0.2), color.withOpacity(0.05)];
break;
case 'Cancel':
color = Colors.orange;
color = AppColor.yellowColor;
icon = Icons.info_rounded;
label = 'Cancelled'.tr;
gradientColors = [color.withOpacity(0.2), color.withOpacity(0.05)];
break;
case 'CancelByPassenger':
color = const Color(0xFF6B4EFF);
color = AppColor.secondaryColorStatic;
icon = Icons.person_off_rounded;
label = 'Cancelled by Passenger'.tr;
gradientColors = [color.withOpacity(0.2), color.withOpacity(0.05)];
break;
default:
color = Colors.grey;
icon = Icons.help_rounded;
gradientColors = [color.withOpacity(0.2), color.withOpacity(0.05)];
}
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: gradientColors,
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(20),
border: Border.all(color: color.withValues(alpha: 0.3), width: 1),
boxShadow: [
BoxShadow(
color: color.withValues(alpha: 0.1),
blurRadius: 4,
offset: const Offset(0, 2),
),
],
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 14, color: color),
const SizedBox(width: 6),
Text(
label,
style: TextStyle(
color: color,
fontSize: 11,
fontWeight: FontWeight.w800,
letterSpacing: 0.3,
),
),
],
),
);
return SiroTag(label, color: color, icon: icon);
}
}
@@ -1,11 +1,13 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intaleq_maps/intaleq_maps.dart';
import 'package:tripz_driver/constant/api_key.dart';
import 'package:siro_driver/constant/api_key.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:tripz_driver/controller/auth/captin/history_captain.dart';
import 'package:tripz_driver/controller/functions/launch.dart';
import 'package:siro_driver/controller/auth/captin/history_captain.dart';
import 'package:siro_driver/controller/functions/launch.dart';
import '../../../widgets/ui/siro_ui.dart';
class HistoryDetailsPage extends StatefulWidget {
const HistoryDetailsPage({super.key});
@@ -32,13 +34,8 @@ class _HistoryDetailsPageState extends State<HistoryDetailsPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[50],
appBar: AppBar(
title: Text('Trip Details'.tr),
backgroundColor: Colors.white,
elevation: 1,
),
return SiroPage(
title: 'Trip Details'.tr,
body: GetBuilder<HistoryCaptainController>(
builder: (controller) {
if (controller.isloading) {
@@ -256,12 +253,9 @@ class _DetailCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Card(
elevation: 2,
shadowColor: Colors.black.withValues(alpha: 0.05),
margin: const EdgeInsets.only(bottom: 16.0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Padding(
return Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: SiroCard(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -1,38 +1,37 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:tripz_driver/constant/box_name.dart';
import 'package:tripz_driver/constant/links.dart';
import 'package:tripz_driver/controller/functions/upload_image.dart';
import 'package:tripz_driver/controller/home/captin/home_captain_controller.dart';
import 'package:tripz_driver/device_compatibility_page.dart';
import 'package:tripz_driver/main.dart';
import 'package:siro_driver/constant/box_name.dart';
import 'package:siro_driver/constant/links.dart';
import 'package:siro_driver/controller/functions/upload_image.dart';
import 'package:siro_driver/controller/home/captin/home_captain_controller.dart';
import 'package:siro_driver/device_compatibility_page.dart';
import 'package:siro_driver/main.dart';
// استيراد الصفحات الأخرى... تأكد من صحة المسارات
import 'package:tripz_driver/views/Rate/rate_app_page.dart';
import 'package:tripz_driver/views/auth/captin/contact_us_page.dart';
import 'package:tripz_driver/views/auth/captin/invite_driver_screen.dart';
import 'package:tripz_driver/views/home/statistics/statistics_dashboard.dart';
import 'package:tripz_driver/views/gamification/challenges_page.dart';
import 'package:tripz_driver/views/gamification/leaderboard_page.dart';
import 'package:tripz_driver/views/gamification/referral_center_page.dart';
import 'package:tripz_driver/views/home/journal/schedule_page.dart';
import 'package:tripz_driver/views/notification/available_rides_page.dart';
import 'package:tripz_driver/views/auth/captin/logout_captain.dart';
import 'package:tripz_driver/views/home/Captin/history/history_captain.dart';
import 'package:tripz_driver/views/home/Captin/home_captain/help_captain.dart';
import 'package:tripz_driver/views/home/Captin/About Us/settings_captain.dart';
import 'package:tripz_driver/views/home/my_wallet/walet_captain.dart';
import 'package:tripz_driver/views/home/profile/profile_captain.dart';
import 'package:tripz_driver/views/notification/notification_captain.dart';
import 'package:siro_driver/views/Rate/rate_app_page.dart';
import 'package:siro_driver/views/auth/captin/contact_us_page.dart';
import 'package:siro_driver/views/auth/captin/invite_driver_screen.dart';
import 'package:siro_driver/views/home/statistics/earnings_page.dart';
import 'package:siro_driver/views/gamification/challenges_page.dart';
import 'package:siro_driver/views/gamification/leaderboard_page.dart';
import 'package:siro_driver/views/home/journal/schedule_page.dart';
import 'package:siro_driver/views/notification/available_rides_page.dart';
import 'package:siro_driver/views/auth/captin/logout_captain.dart';
import 'package:siro_driver/views/home/Captin/history/history_captain.dart';
import 'package:siro_driver/views/home/Captin/home_captain/help_captain.dart';
import 'package:siro_driver/views/home/Captin/About Us/settings_captain.dart';
import 'package:siro_driver/views/home/my_wallet/walet_captain.dart';
import 'package:siro_driver/views/home/profile/profile_captain.dart';
import 'package:siro_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';
import '../../../widgets/ui/siro_ui.dart';
import '../../../transit/transit_driver_home_page.dart';
import '../About Us/video_page.dart';
import '../../../food_delivery/food_delivery_home_page.dart';
import '../../journal/driver_scheduled_rides_page.dart';
import '../../journal/driver_insurance_page.dart';
// 1. إنشاء Class لتعريف بيانات كل عنصر في القائمة
class DrawerItem {
@@ -48,173 +47,224 @@ class DrawerItem {
required this.onTap});
}
/// مجموعة عناصر تحت عنوان واحد. القائمة كانت ٢٢ عنصراً مسطّحاً بـ ٢٢ لوناً
/// مختلفاً، فيصعب العثور على أي بند. التجميع يقصّر زمن البحث بلا تغيير أي وجهة.
class DrawerSection {
final String title;
final List<DrawerItem> items;
DrawerSection({required this.title, required this.items});
}
// --- الويدجت الرئيسية للقائمة الجانبية ---
class AppDrawer extends StatelessWidget {
AppDrawer({super.key});
final ImageController imageController = Get.put(ImageController());
// 2. تعريف بيانات القائمة بشكل مركزي ومنظم
final List<DrawerItem> drawerItems = [
// DrawerItem(
// title: 'Mawasalati'.tr,
// icon: Icons.directions_bus_filled_rounded,
// color: Colors.teal,
// onTap: () => Get.to(() => const TransitDriverHomePage())),
DrawerItem(
title: 'Balance'.tr,
icon: Icons.account_balance_wallet,
color: Colors.green,
onTap: () => Get.to(() => WalletCaptainRefactored())),
DrawerItem(
title: 'Statistics'.tr,
icon: Icons.bar_chart_rounded,
color: Colors.deepPurple,
onTap: () => Get.to(() => StatisticsDashboard())),
DrawerItem(
title: 'Challenges'.tr,
icon: Icons.bolt_rounded,
color: Colors.amber,
onTap: () => Get.to(() => ChallengesPage())),
DrawerItem(
title: 'My Schedule'.tr,
icon: Icons.calendar_today_rounded,
color: Colors.teal,
onTap: () => Get.to(() => SchedulePage())),
DrawerItem(
title: 'Leaderboard'.tr,
icon: Icons.leaderboard_rounded,
color: Colors.red,
onTap: () => Get.to(() => LeaderboardPage())),
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: 'Invite Driver'.tr,
icon: Icons.person_add_rounded,
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())),
// 2. تعريف بيانات القائمة مجمَّعة حسب الغرض.
// الوجهات لم تتغيّر — التغيير في الترتيب واللون فقط.
// اللون صار دلالياً: أخضر = مال، كهرماني = مكافآت، أحمر = خروج،
// وما عداه لون العلامة. الطيف العشوائي السابق كان يشتّت لا يوجّه.
final List<DrawerSection> sections = [
DrawerSection(title: 'Services'.tr, items: [
DrawerItem(
title: 'Available for rides'.tr,
icon: Icons.drive_eta_rounded,
color: AppColor.primaryColor,
onTap: () => Get.to(() => const AvailableRidesPage())),
DrawerItem(
title: 'Mawasalati'.tr,
icon: Icons.directions_bus_filled_rounded,
color: AppColor.primaryColor,
onTap: () => Get.to(() => const TransitDriverHomePage())),
DrawerItem(
title: 'Delivery'.tr,
icon: Icons.delivery_dining_rounded,
color: AppColor.primaryColor,
onTap: () => Get.to(() => const FoodDeliveryHomePage())),
]),
DrawerSection(title: 'Wallet & Earnings'.tr, items: [
DrawerItem(
title: 'Balance'.tr,
icon: Icons.account_balance_wallet_rounded,
color: AppColor.greenColor,
onTap: () => Get.to(() => const WalletCaptainRefactored())),
DrawerItem(
title: 'My Earnings'.tr,
icon: Icons.payments_rounded,
color: AppColor.greenColor,
onTap: () => Get.to(() => EarningsPage())),
DrawerItem(
title: 'Insurance'.tr,
icon: Icons.health_and_safety_rounded,
color: AppColor.greenColor,
onTap: () => Get.to(() => const DriverInsurancePage())),
]),
DrawerSection(title: 'My Trips'.tr, items: [
DrawerItem(
title: 'My Schedule'.tr,
icon: Icons.calendar_today_rounded,
color: AppColor.primaryColor,
onTap: () => Get.to(() => SchedulePage())),
DrawerItem(
title: 'Upcoming Scheduled Rides'.tr,
icon: Icons.edit_calendar_rounded,
color: AppColor.primaryColor,
onTap: () => Get.to(() => const DriverScheduledRidesPage())),
DrawerItem(
title: 'History of Trip'.tr,
icon: Icons.history_rounded,
color: AppColor.primaryColor,
onTap: () => Get.to(() => const HistoryCaptain())),
]),
DrawerSection(title: 'Rewards'.tr, items: [
DrawerItem(
title: 'Challenges'.tr,
icon: Icons.bolt_rounded,
color: AppColor.yellowColor,
onTap: () => Get.to(() => ChallengesPage())),
DrawerItem(
title: 'Leaderboard'.tr,
icon: Icons.leaderboard_rounded,
color: AppColor.yellowColor,
onTap: () => Get.to(() => LeaderboardPage())),
DrawerItem(
title: 'Invite Driver'.tr,
icon: Icons.person_add_alt_1_rounded,
color: AppColor.yellowColor,
onTap: () => Get.to(() => InviteScreen())),
]),
DrawerSection(title: 'My Account'.tr, items: [
DrawerItem(
title: 'Profile'.tr,
icon: Icons.person_rounded,
color: AppColor.primaryColor,
onTap: () => Get.to(() => ProfileCaptain())),
DrawerItem(
title: 'Notifications'.tr,
icon: Icons.notifications_rounded,
color: AppColor.primaryColor,
onTap: () => Get.to(() => const NotificationCaptain())),
DrawerItem(
title: 'Settings'.tr,
icon: Icons.settings_rounded,
color: AppColor.primaryColor,
onTap: () => Get.to(() => const SettingsCaptain())),
]),
DrawerSection(title: 'Support'.tr, items: [
DrawerItem(
title: 'Helping Center'.tr,
icon: Icons.help_center_rounded,
color: AppColor.primaryColor,
onTap: () => Get.to(() => HelpCaptain())),
DrawerItem(
title: 'Contact Us'.tr,
icon: Icons.email_rounded,
color: AppColor.primaryColor,
onTap: () => Get.to(() => ContactUsPage())),
DrawerItem(
title: 'Videos Tutorials'.tr,
icon: Icons.play_circle_fill_rounded,
color: AppColor.primaryColor,
onTap: () => Get.to(() => VideoListPage())),
DrawerItem(
title: 'Rate Our App'.tr,
icon: Icons.star_rounded,
color: AppColor.primaryColor,
onTap: () => Get.to(() => RatingScreen())),
DrawerItem(
title: 'Is device compatible'.tr,
icon: Icons.memory_rounded,
color: AppColor.primaryColor,
onTap: () => Get.to(() => DeviceCompatibilityPage())),
DrawerItem(
title: 'Privacy Policy'.tr,
icon: Icons.privacy_tip_rounded,
color: AppColor.primaryColor,
onTap: () =>
launchUrl(Uri.parse('${AppLink.server}/privacy_policy.php'))),
]),
];
@override
Widget build(BuildContext context) {
// نبني قائمة مسطّحة من العناوين والعناصر لتبقى الحركة المتدرّجة تعمل.
final rows = <Widget>[];
for (final section in sections) {
rows.add(_DrawerSectionTitle(section.title));
rows.addAll(section.items.map((e) => _DrawerItemTile(item: e)));
}
return Drawer(
child: Container(
color: Theme.of(context).scaffoldBackgroundColor,
child: Column(
children: [
// --- الجزء العلوي من القائمة (بيانات المستخدم) ---
UserHeader(), // استخدمنا الويدجت المحسنة بالأسفل
backgroundColor: 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),
),
),
);
},
),
// --- قائمة العناصر المتحركة ---
Expanded(
child: AnimationLimiter(
child: ListView.builder(
padding: const EdgeInsets.fromLTRB(10, 8, 10, 8),
itemCount: rows.length,
itemBuilder: (BuildContext context, int index) {
return AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 300),
child: SlideAnimation(
verticalOffset: 40.0,
child: FadeInAnimation(child: rows[index]),
),
);
},
),
),
],
),
),
// --- تسجيل الخروج مثبَّت أسفل القائمة ---
// كان آخر عنصر في قائمة من ٢٢ بنداً، فيتطلّب تمريراً كاملاً للوصول إليه.
SafeArea(
top: false,
child: Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border(
top: BorderSide(color: Theme.of(context).dividerColor)),
),
padding: const EdgeInsets.fromLTRB(10, 6, 10, 6),
child: _DrawerItemTile(
item: DrawerItem(
title: 'Sign Out'.tr,
icon: Icons.logout_rounded,
color: AppColor.redColor,
onTap: () => Get.to(() => const LogoutCaptain())),
),
),
),
],
),
);
}
}
// --- عنوان مجموعة داخل القائمة ---
class _DrawerSectionTitle extends StatelessWidget {
final String title;
const _DrawerSectionTitle(this.title);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsetsDirectional.fromSTEB(14, 16, 14, 6),
child: Text(
title.toUpperCase(),
style: Theme.of(context).textTheme.bodySmall?.copyWith(
fontSize: 11,
fontWeight: FontWeight.bold,
letterSpacing: 0.8,
),
),
);
}
@@ -227,22 +277,26 @@ class _DrawerItemTile extends StatelessWidget {
@override
Widget build(BuildContext context) {
// النيفي الداكن لا يُقرأ على خلفية ليلية، فنستبدله بلون العلامة الفاتح.
final isDark = Theme.of(context).brightness == Brightness.dark;
final color = item.color == AppColor.primaryColor && isDark
? AppColor.secondaryColorStatic
: item.color;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
padding: const EdgeInsets.symmetric(vertical: 2.0),
child: ListTile(
leading: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: item.color.withValues(alpha: 0.1),
shape: BoxShape.circle,
),
child: Icon(item.icon, color: item.color, size: 24),
),
dense: true,
visualDensity: const VisualDensity(vertical: -1),
horizontalTitleGap: 12,
contentPadding: const EdgeInsets.symmetric(horizontal: 12),
leading: SiroIconBadge(item.icon, color: color, size: 20),
title: Text(
item.title,
overflow: TextOverflow.ellipsis,
style: Theme.of(context)
.textTheme
.titleMedium
.bodyMedium
?.copyWith(fontWeight: FontWeight.w500),
),
onTap: () {
@@ -252,7 +306,7 @@ class _DrawerItemTile extends StatelessWidget {
});
},
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
splashColor: item.color.withValues(alpha: 0.2),
splashColor: color.withValues(alpha: 0.15),
),
);
}
@@ -320,10 +374,9 @@ class UserHeader extends StatelessWidget {
fontSize: 18,
shadows: [Shadow(blurRadius: 2, color: Colors.black26)]),
),
accountEmail:
box.read(BoxName.emailDriver).toString().contains('tripzapp')
? Text('Your email not updated yet'.tr)
: Text(box.read(BoxName.emailDriver)),
accountEmail: box.read(BoxName.emailDriver).toString().contains('siroapp')
? Text('Your email not updated yet'.tr)
: Text(box.read(BoxName.emailDriver)),
currentAccountPicture: GetBuilder<ImageController>(
builder: (controller) => Stack(
clipBehavior: Clip.none,
@@ -333,34 +386,37 @@ class UserHeader extends StatelessWidget {
shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 2),
boxShadow: [
BoxShadow(color: Colors.black.withValues(alpha: 0.3), blurRadius: 5)
BoxShadow(
color: Colors.black.withValues(alpha: 0.3), blurRadius: 5)
],
),
child: controller.isloading
? const CircularProgressIndicator(color: Colors.white)
: CircleAvatar(
backgroundImage: (box
.read(BoxName.driverPhotoUrl)
?.toString()
.isNotEmpty ==
true)
? NetworkImage(box.read(BoxName.driverPhotoUrl))
: null,
: Builder(builder: (context) {
final photoUrl =
box.read(BoxName.driverPhotoUrl)?.toString() ?? '';
final avatarImage =
photoUrl.isNotEmpty ? NetworkImage(photoUrl) : null;
// [تعديل هام]: في حال فشل تحميل الصورة (غير موجودة)
onBackgroundImageError: (exception, stackTrace) {
// طباعة الخطأ في الكونسول للتوضيح
debugPrint(
"Profile image not found or error loading: $exception");
// استدعاء نافذة التنبيه
_showUploadPhotoDialog(context, controller);
},
return CircleAvatar(
backgroundImage: avatarImage,
// أيقونة بديلة تظهر في الخلفية إذا لم تكن الصورة موجودة
backgroundColor: Colors.grey.shade300,
child: const Icon(Icons.person,
size: 40, color: Colors.white),
),
// Flutter يمنع onBackgroundImageError بلا صورة
// (assertion)، فنمرّره فقط عند وجود صورة فعلية.
onBackgroundImageError: avatarImage == null
? null
: (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,
@@ -383,31 +439,31 @@ class UserHeader extends StatelessWidget {
),
),
otherAccountsPictures: [
SizedBox(
width: 60,
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 4),
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.15),
borderRadius: BorderRadius.circular(999),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.star_rounded, color: AppColor.gold, size: 15),
const SizedBox(width: 3),
Text(
homeCaptainController.rating.toString(),
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 14),
fontSize: 13),
),
const SizedBox(width: 2),
const Icon(Icons.star, color: Colors.amber, size: 16),
],
),
),
],
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Theme.of(context).primaryColor, Colors.blue.shade700],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
// تدرّج العلامة نفسه المستعمل في رؤوس الصفحات الداخلية
// (كان `Colors.blue.shade700` وهو أزرق لا علاقة له بهوية سيرو).
decoration: BoxDecoration(gradient: SiroUi.brandGradient(context)),
);
}
}
@@ -1,52 +1,43 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:tripz_driver/controller/home/captin/help/help_controller.dart';
import 'package:tripz_driver/views/home/Captin/home_captain/help_details_replay_page.dart';
import 'package:siro_driver/controller/home/captin/help/help_controller.dart';
import 'package:siro_driver/views/home/Captin/home_captain/help_details_replay_page.dart';
import 'package:flutter/cupertino.dart';
import '../../../../constant/colors.dart';
import '../../../../controller/functions/encrypt_decrypt.dart';
import '../../../widgets/my_scafold.dart';
import '../../../widgets/ui/siro_ui.dart';
class HelpCaptain extends StatelessWidget {
HelpCaptain({super.key});
const HelpCaptain({super.key});
@override
Widget build(BuildContext context) {
Get.put(HelpController());
final theme = Theme.of(context);
return MyScafolld(
return SiroPage(
title: 'Helping Page'.tr,
isleading: true,
body: [
SingleChildScrollView(
padding: const EdgeInsets.all(20.0),
padding: SiroUi.pageInsets,
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
padding: const EdgeInsets.all(18.0),
decoration: BoxDecoration(
color: theme.colorScheme.surfaceVariant.withOpacity(0.5),
borderRadius: BorderRadius.circular(15.0),
border: Border.all(color: theme.dividerColor),
),
child: Text(
'If you need any help or have questions, this is the right place to do that. You are welcome!'
.tr,
style: theme.textTheme.bodyLarge,
textAlign: TextAlign.center,
SiroCard(
child: Row(
children: [
SiroIconBadge(Icons.support_agent_rounded,
color: SiroUi.interactive(context)),
const SizedBox(width: 12),
Expanded(
child: Text(
'If you need any help or have questions, this is the right place to do that. You are welcome!'
.tr,
style: theme.textTheme.bodyMedium,
),
),
],
),
),
const SizedBox(height: 24),
Text(
'Submit Your Question'.tr,
style: theme.textTheme.titleMedium
?.copyWith(fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
SiroSectionTitle('Submit Your Question'.tr),
GetBuilder<HelpController>(
builder: (helpController) => Form(
key: helpController.formKey,
@@ -58,8 +49,6 @@ class HelpCaptain extends StatelessWidget {
hintText: 'Enter your Question here'.tr,
prefixIcon:
const Icon(Icons.question_answer_outlined),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12)),
),
maxLines: 3,
validator: (value) {
@@ -71,10 +60,10 @@ class HelpCaptain extends StatelessWidget {
),
const SizedBox(height: 16),
helpController.isLoading
? const Center(child: CircularProgressIndicator())
? const SiroLoading()
: SizedBox(
width: double.infinity,
child: ElevatedButton(
child: ElevatedButton.icon(
onPressed: () {
if (helpController.formKey.currentState!
.validate()) {
@@ -83,53 +72,36 @@ class HelpCaptain extends StatelessWidget {
.clear();
}
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColor.primaryColor,
foregroundColor: Colors.white,
padding:
const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12)),
),
child: Text('Submit Question'.tr),
icon: const Icon(Icons.send_rounded, size: 18),
label: Text('Submit Question'.tr),
),
),
],
),
),
),
const SizedBox(height: 32),
Text(
'Your Questions'.tr,
style: theme.textTheme.titleMedium
?.copyWith(fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
SiroSectionTitle('Your Questions'.tr),
GetBuilder<HelpController>(
builder: (helpController) {
final questions = helpController.helpQuestionDate['message'];
if (questions == null || questions.isEmpty) {
return Center(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Text('No questions asked yet.'.tr),
return Padding(
padding: const EdgeInsets.symmetric(vertical: 24),
child: SiroEmptyState(
icon: Icons.forum_outlined,
title: 'No questions asked yet.'.tr,
),
);
}
return ListView.separated(
return ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: questions.length,
separatorBuilder: (context, index) =>
const SizedBox(height: 12),
itemBuilder: (context, index) {
var list = questions[index];
return Card(
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: BorderSide(color: theme.dividerColor),
),
return SiroCard(
padding: EdgeInsets.zero,
child: ListTile(
title: Text(
EncryptionHelper.instance
@@ -142,8 +114,8 @@ class HelpCaptain extends StatelessWidget {
list['datecreated'],
style: theme.textTheme.bodySmall,
),
trailing:
const Icon(Icons.arrow_forward_ios, size: 16),
trailing: Icon(Icons.arrow_forward_ios,
size: 14, color: SiroUi.subtle(context)),
onTap: () {
helpController.getIndex(
int.parse(EncryptionHelper.instance
@@ -159,173 +131,10 @@ class HelpCaptain extends StatelessWidget {
);
},
),
const SizedBox(height: 16),
],
),
),
],
);
}
}
// class HelpCaptain extends StatelessWidget {
// HelpCaptain({super.key});
// @override
// Widget build(BuildContext context) {
// Get.put(HelpController());
// return CupertinoPageScaffold(
// navigationBar: CupertinoNavigationBar(
// middle: Text('Helping Page'.tr),
// leading: CupertinoButton(
// padding: EdgeInsets.zero,
// child: Icon(CupertinoIcons.back),
// onPressed: () => Navigator.pop(context),
// ),
// ),
// child: SafeArea(
// child: Padding(
// padding: const EdgeInsets.all(16.0),
// child: Column(
// children: [
// Padding(
// padding: const EdgeInsets.symmetric(vertical: 12.0),
// child: Container(
// padding: const EdgeInsets.all(16.0),
// decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(12.0),
// border: Border.all(
// color: CupertinoColors.systemGrey2,
// ),
// ),
// child: Text(
// 'If you need any help or have questions, this is the right place to do that. You are welcome!'
// .tr,
// style: CupertinoTheme.of(context).textTheme.textStyle,
// textAlign: TextAlign.center,
// ),
// ),
// ),
// Card(
// elevation: 3,
// color: CupertinoColors.systemGrey6,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(12.0),
// ),
// child: Padding(
// padding: const EdgeInsets.all(16.0),
// child: GetBuilder<HelpController>(
// builder: (helpController) => Form(
// key: helpController.formKey,
// child: Column(
// children: [
// CupertinoTextField(
// controller: helpController.helpQuestionController,
// placeholder: 'Enter your Question here'.tr,
// decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(12),
// border: Border.all(
// color: CupertinoColors.systemGrey,
// ),
// ),
// padding: const EdgeInsets.all(16),
// clearButtonMode: OverlayVisibilityMode.editing,
// ),
// const SizedBox(height: 20),
// helpController.isLoading
// ? const CupertinoActivityIndicator()
// : CupertinoButton.filled(
// onPressed: () {
// if (helpController.formKey.currentState!
// .validate()) {
// helpController.addHelpQuestion();
// // Clear the feedback form
// helpController.formKey.currentState!
// .reset();
// }
// },
// child: Text('Submit Question'.tr),
// ),
// ],
// ),
// ),
// ),
// ),
// ),
// const SizedBox(height: 20),
// Expanded(
// child: GetBuilder<HelpController>(
// builder: (helpController) => Padding(
// padding: const EdgeInsets.all(10),
// child: Container(
// decoration: BoxDecoration(
// border: Border.all(
// color: CupertinoColors.systemGrey2,
// ),
// borderRadius: BorderRadius.circular(12.0),
// ),
// child: ListView.builder(
// itemCount: helpController.helpQuestionDate['message'] !=
// null
// ? helpController.helpQuestionDate['message'].length
// : 0,
// itemBuilder: (BuildContext context, int index) {
// var list =
// helpController.helpQuestionDate['message'][index];
// return Padding(
// padding: const EdgeInsets.all(3),
// child: Container(
// padding: const EdgeInsets.symmetric(
// vertical: 12, horizontal: 16),
// decoration: BoxDecoration(
// border: Border.all(
// color: CupertinoColors.activeGreen,
// width: 2,
// ),
// borderRadius: BorderRadius.circular(12),
// ),
// child: GestureDetector(
// onTap: () {
// helpController.getIndex(
// list['id'], list['helpQuestion']);
// helpController
// .getHelpRepley(list['id'].toString());
// Get.to(() => const HelpDetailsReplayPage());
// },
// child: Row(
// mainAxisAlignment:
// MainAxisAlignment.spaceBetween,
// children: [
// Expanded(
// child: Text(
// list['helpQuestion'],
// style: CupertinoTheme.of(context)
// .textTheme
// .textStyle,
// overflow: TextOverflow.ellipsis,
// ),
// ),
// Text(
// list['datecreated'],
// style: CupertinoTheme.of(context)
// .textTheme
// .tabLabelTextStyle,
// ),
// ],
// ),
// ),
// ),
// );
// },
// ),
// ),
// ),
// ),
// ),
// ],
// ),
// ),
// ),
// );
// }
// }
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:tripz_driver/constant/style.dart';
import 'package:tripz_driver/views/widgets/mycircular.dart';
import 'package:siro_driver/constant/style.dart';
import 'package:siro_driver/views/widgets/mycircular.dart';
import '../../../../controller/functions/encrypt_decrypt.dart';
import '../../../../controller/home/captin/help/help_controller.dart';
@@ -88,6 +88,13 @@ class HelpDetailsReplayPage extends StatelessWidget {
replayData == null ||
EncryptionHelper.instance.decryptData(replayData['replay']).toString() == 'not yet';
if (isNoReply && helpController.aiReplies.containsKey(helpController.indexQuestion)) {
return Text(
helpController.aiReplies[helpController.indexQuestion]!,
style: Theme.of(context).textTheme.bodyLarge,
);
}
return Text(
isNoReply
? 'No Response yet.'.tr
@@ -6,8 +6,8 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:flutter_font_icons/flutter_font_icons.dart';
import 'package:tripz_driver/views/home/Captin/home_captain/drawer_captain.dart';
import 'package:tripz_driver/views/widgets/mycircular.dart';
import 'package:siro_driver/views/home/Captin/home_captain/drawer_captain.dart';
import 'package:siro_driver/views/widgets/mycircular.dart';
import '../../../../constant/box_name.dart';
import '../../../../constant/colors.dart';
@@ -222,23 +222,34 @@ class _HomeAppBar extends StatelessWidget implements PreferredSizeWidget {
// ── Logo + App Name ──────────────────────
title: Padding(
padding: const EdgeInsets.only(left: 4),
child: Row(
children: [
_LogoBadge(),
const SizedBox(width: 10),
Expanded(
child: Text(
AppInformation.appName.split(' ')[0].tr,
style: const TextStyle(
color: _Token.accent,
fontSize: 20,
fontWeight: FontWeight.w800,
letterSpacing: 0.8,
),
overflow: TextOverflow.ellipsis,
),
),
],
// ‏شارات الـ actions تلتهم عرض الـ AppBar فلا يبقى للعنوان أحياناً
// ‏سوى ~26px، بينما الشعار وحده 36px — ومن هنا كان الفيض.
// ‏نُسقط الاسم عند ضيق المساحة ونُبقي الشعار: هو الهوية الأهم.
child: LayoutBuilder(
builder: (context, constraints) {
final showName = constraints.maxWidth >= 96;
return Row(
mainAxisSize: MainAxisSize.min,
children: [
_LogoBadge(),
if (showName) ...[
const SizedBox(width: 6),
Flexible(
child: Text(
AppInformation.appName.split(' ')[0].tr,
style: const TextStyle(
color: _Token.accent,
fontSize: 18,
fontWeight: FontWeight.w800,
letterSpacing: 0.5,
),
overflow: TextOverflow.ellipsis,
),
),
],
],
);
},
),
),
actions: [
@@ -734,7 +745,7 @@ class _FloatingControls extends StatelessWidget {
onTap: () =>
Bubble().startBubbleHead(sendAppToBackground: true),
tooltip: 'Overlay'.tr,
child: Image.asset('assets/images/logo1.png',
child: Image.asset('assets/images/logo.png',
width: 26, height: 26),
),
const SizedBox(height: 10),
@@ -24,8 +24,7 @@ class OsmMapView extends StatelessWidget {
final double currentHeading = locationController.heading;
final cityPolygon = CountryLogic.getCurrentCityPolygon();
final bool inServiceArea =
CountryLogic.isPointInPolygon(currentLocation, cityPolygon);
final bool inServiceArea = CountryLogic.isPointInPolygon(currentLocation, cityPolygon);
return Stack(
children: [
@@ -66,16 +65,12 @@ class OsmMapView extends StatelessWidget {
left: 20,
right: 20,
child: Container(
padding:
const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
decoration: BoxDecoration(
color: Colors.redAccent.withOpacity(0.9),
borderRadius: BorderRadius.circular(12),
boxShadow: const [
BoxShadow(
color: Colors.black26,
blurRadius: 4,
offset: Offset(0, 2))
BoxShadow(color: Colors.black26, blurRadius: 4, offset: Offset(0, 2))
],
),
child: const Row(
@@ -1,8 +1,8 @@
import 'package:tripz_driver/controller/functions/tts.dart';
import 'package:siro_driver/controller/functions/tts.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:tripz_driver/controller/home/payment/captain_wallet_controller.dart';
import 'package:siro_driver/controller/home/payment/captain_wallet_controller.dart';
import '../../../../../constant/style.dart';
import '../../../../widgets/elevated_btn.dart';
@@ -1,9 +1,9 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intaleq_maps/intaleq_maps.dart';
import 'package:tripz_driver/constant/colors.dart';
import 'package:tripz_driver/controller/home/captin/destination_controller.dart';
import 'package:tripz_driver/controller/functions/tts.dart';
import 'package:siro_driver/constant/colors.dart';
import 'package:siro_driver/controller/home/captin/destination_controller.dart';
import 'package:siro_driver/controller/functions/tts.dart';
class DestinationBottomSheet extends StatelessWidget {
const DestinationBottomSheet({super.key});
@@ -67,9 +67,7 @@ class DestinationBottomSheet extends StatelessWidget {
init: Get.find<TextToSpeechController>(),
builder: (tts) => IconButton(
icon: Icon(
tts.isSpeaking
? Icons.volume_up_rounded
: Icons.volume_mute_rounded,
tts.isSpeaking ? Icons.volume_up_rounded : Icons.volume_mute_rounded,
color: AppColor.primaryColor,
size: 26,
),
@@ -111,12 +109,10 @@ class DestinationBottomSheet extends StatelessWidget {
side: BorderSide(color: Colors.green.withOpacity(0.3)),
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 14, vertical: 12),
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
child: Row(
children: [
const Icon(Icons.check_circle_rounded,
color: Colors.green, size: 22),
const Icon(Icons.check_circle_rounded, color: Colors.green, size: 22),
const SizedBox(width: 10),
Expanded(
child: Column(
@@ -167,8 +163,7 @@ class DestinationBottomSheet extends StatelessWidget {
fillColor: Theme.of(context).brightness == Brightness.dark
? const Color(0xFF202B4B)
: Colors.grey.withOpacity(0.1),
contentPadding: const EdgeInsets.symmetric(
vertical: 14, horizontal: 16),
contentPadding: const EdgeInsets.symmetric(vertical: 14, horizontal: 16),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(14),
borderSide: BorderSide.none,
@@ -195,28 +190,21 @@ class DestinationBottomSheet extends StatelessWidget {
itemBuilder: (context, index) {
final place = c.placesSuggestions[index];
return ListTile(
leading: const Icon(Icons.place_rounded,
color: Colors.grey),
leading: const Icon(Icons.place_rounded, color: Colors.grey),
title: Text(
place['name'] ?? "",
style: const TextStyle(fontSize: 13),
),
subtitle: Text(
place['description'] ?? "",
style: const TextStyle(
fontSize: 11, color: Colors.grey),
style: const TextStyle(fontSize: 11, color: Colors.grey),
),
onTap: () {
FocusScope.of(context).unfocus();
Get.back(); // Close sheet
final lat = double.tryParse(
place['latitude']?.toString() ?? '0') ??
0.0;
final lng = double.tryParse(
place['longitude']?.toString() ?? '0') ??
0.0;
c.saveDestination(LatLng(lat, lng),
place['name'] ?? 'Destination');
final lat = double.tryParse(place['latitude']?.toString() ?? '0') ?? 0.0;
final lng = double.tryParse(place['longitude']?.toString() ?? '0') ?? 0.0;
c.saveDestination(LatLng(lat, lng), place['name'] ?? 'Destination');
},
);
},
@@ -1,14 +1,14 @@
import 'package:tripz_driver/constant/box_name.dart';
import 'package:tripz_driver/controller/firebase/local_notification.dart';
import 'package:tripz_driver/main.dart';
import 'package:tripz_driver/views/home/Captin/driver_map_page.dart';
import 'package:tripz_driver/views/home/Captin/orderCaptin/vip_order_page.dart';
import 'package:tripz_driver/views/auth/syria/registration_view.dart';
import 'package:siro_driver/constant/box_name.dart';
import 'package:siro_driver/controller/firebase/local_notification.dart';
import 'package:siro_driver/main.dart';
import 'package:siro_driver/views/home/Captin/driver_map_page.dart';
import 'package:siro_driver/views/home/Captin/orderCaptin/vip_order_page.dart';
import 'package:siro_driver/views/auth/syria/registration_view.dart';
import 'package:flutter/material.dart';
import 'package:flutter_font_icons/flutter_font_icons.dart';
import 'package:get/get.dart';
import 'package:tripz_driver/controller/home/captin/home_captain_controller.dart';
import 'package:tripz_driver/views/widgets/mydialoug.dart';
import 'package:siro_driver/controller/home/captin/home_captain_controller.dart';
import 'package:siro_driver/views/widgets/mydialoug.dart';
import '../../../../../constant/links.dart';
import '../../../../../controller/firebase/notification_service.dart';
@@ -16,7 +16,7 @@ import '../../../../../controller/functions/crud.dart';
import '../../../../../controller/home/captin/order_request_controller.dart';
import '../../../../../print.dart';
import '../../../../Rate/ride_calculate_driver.dart';
import 'package:tripz_driver/views/home/statistics/statistics_dashboard.dart';
import 'package:siro_driver/views/home/statistics/earnings_page.dart';
// ─────────────────────────────────────────────
// Design Tokens (Responsive)
@@ -103,7 +103,7 @@ GetBuilder<HomeCaptainController> leftMainMenuCaptainIcons() {
color: _T.blue,
tooltip: 'Statistics'.tr,
onTap: () {
Get.to(() => StatisticsDashboard());
Get.to(() => EarningsPage());
},
onLongPress: () =>
box.write(BoxName.statusDriverLocation, 'off'),
@@ -1,8 +1,8 @@
import 'package:tripz_driver/constant/colors.dart';
import 'package:tripz_driver/constant/style.dart';
import 'package:tripz_driver/controller/home/captin/help/maintain_center_controller.dart';
import 'package:tripz_driver/views/widgets/elevated_btn.dart';
import 'package:tripz_driver/views/widgets/my_scafold.dart';
import 'package:siro_driver/constant/colors.dart';
import 'package:siro_driver/constant/style.dart';
import 'package:siro_driver/controller/home/captin/help/maintain_center_controller.dart';
import 'package:siro_driver/views/widgets/elevated_btn.dart';
import 'package:siro_driver/views/widgets/my_scafold.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
@@ -1,4 +1,4 @@
import 'package:tripz_driver/constant/currency.dart';
import 'package:siro_driver/constant/currency.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intaleq_maps/intaleq_maps.dart';
import 'package:tripz_driver/constant/api_key.dart';
import 'package:siro_driver/constant/api_key.dart';
import '../../../../controller/functions/location_controller.dart';
import '../../../../controller/home/captin/map_driver_controller.dart';
@@ -26,7 +26,7 @@ class GoogleDriverMap extends StatelessWidget {
builder: (controller) => Listener(
onPointerDown: (_) => controller.onUserMapInteraction(),
child: IntaleqMap(
apiKey: AK.mapSaasKey,
apiKey: AK.mapAPIKEY,
onMapCreated: (mapController) {
controller.onMapCreated(mapController);
},
@@ -1,6 +1,6 @@
import 'package:tripz_driver/constant/colors.dart';
import 'package:tripz_driver/constant/style.dart';
import 'package:tripz_driver/controller/home/captin/map_driver_controller.dart';
import 'package:siro_driver/constant/colors.dart';
import 'package:siro_driver/constant/style.dart';
import 'package:siro_driver/controller/home/captin/map_driver_controller.dart';
import 'package:flutter/material.dart';
import 'package:flutter_font_icons/flutter_font_icons.dart';
import 'package:get/get.dart';
@@ -1,10 +1,10 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:tripz_driver/constant/colors.dart';
import 'package:tripz_driver/controller/home/captin/map_driver_controller.dart';
import 'package:siro_driver/constant/colors.dart';
import 'package:siro_driver/controller/home/captin/map_driver_controller.dart';
import '../../../../constant/box_name.dart';
import '../../../../constant/style.dart';
import 'package:tripz_driver/views/widgets/mydialoug.dart';
import 'package:siro_driver/views/widgets/mydialoug.dart';
import '../../../../controller/voice_call_controller.dart';
import '../../../../controller/functions/launch.dart';
import '../../../../controller/functions/location_controller.dart';
@@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:tripz_driver/views/widgets/error_snakbar.dart';
import 'package:tripz_driver/views/widgets/my_textField.dart';
import 'package:tripz_driver/views/widgets/elevated_btn.dart'; // Checked import
import 'package:siro_driver/views/widgets/error_snakbar.dart';
import 'package:siro_driver/views/widgets/my_textField.dart';
import 'package:siro_driver/views/widgets/elevated_btn.dart'; // Checked import
import 'package:flutter_font_icons/flutter_font_icons.dart';
import '../../../../constant/box_name.dart';
@@ -153,8 +153,7 @@ class MarkerGenerator {
..strokeWidth = 3.0;
canvas.drawCircle(const Offset(size / 2, size / 2), size / 2.5, paint);
canvas.drawCircle(
const Offset(size / 2, size / 2), size / 2.5, borderPaint);
canvas.drawCircle(const Offset(size / 2, size / 2), size / 2.5, borderPaint);
TextPainter iconPainter = TextPainter(textDirection: TextDirection.ltr);
iconPainter.text = TextSpan(
@@ -5,8 +5,8 @@ import 'package:flutter_overlay_window/flutter_overlay_window.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:just_audio/just_audio.dart';
import 'package:tripz_driver/constant/api_key.dart';
import 'package:tripz_driver/models/overlay_service.dart';
import 'package:siro_driver/constant/api_key.dart';
import 'package:siro_driver/models/overlay_service.dart';
import '../../../../constant/box_name.dart';
import '../../../../constant/links.dart';
import '../../../../controller/firebase/local_notification.dart';
@@ -41,9 +41,16 @@ class OrderOverlay extends StatefulWidget {
class _OrderOverlayState extends State<OrderOverlay>
with WidgetsBindingObserver {
// === State Variables ===
/// مدة مرحلة "الطلب العام" بعد انتهاء السبق الحصري.
static const int kPublicWindowSeconds = 15;
OrderData? orderData;
Timer? timer;
int remainingSeconds = 10;
int remainingSeconds = kPublicWindowSeconds;
/// هل ما زلنا داخل ثواني السبق الحصري؟ تنقلب إلى false تلقائياً حين
/// يتبقّى من العدّاد ما يساوي مدة المرحلة العامة.
bool isExclusive = false;
final AudioPlayer audioPlayer = AudioPlayer();
bool buttonsEnabled = true;
final String mapApiKey = AK.mapAPIKEY;
@@ -113,20 +120,29 @@ class _OrderOverlayState extends State<OrderOverlay>
void _processEventData(dynamic event) {
_log("Received event: $event");
if (event is List<dynamic>) {
try {
myList = event;
final newOrder = OrderData.fromList(event);
_log("Parsed OrderData: ${newOrder.toMap()}");
setState(() {
orderData = newOrder;
});
_resetAndStartTimer();
} catch (e, s) {
_log("Error parsing OrderData: $e\nStackTrace: $s");
// ‏مساران يغذّيان هذه النافذة بشكلين مختلفين:
// • FCM → قائمة مفهرسة
// • السوكِت → خريطة JSON
// ‏كان الشرط يقبل القائمة وحدها، فحمولة السوكِت تُرفض بصمت ولا تظهر
// ‏نافذة إطلاقاً. OrderData.fromAny يوحّد الشكلين.
try {
final newOrder = OrderData.fromAny(event);
if (newOrder == null) {
_log("Unexpected data format: $event");
return;
}
} else {
_log("Unexpected data format: $event");
if (event is List) myList = event;
_log("Parsed OrderData: ${newOrder.toMap()}");
setState(() {
orderData = newOrder;
isExclusive = newOrder.offerType == 'exclusive';
});
_resetAndStartTimer();
} catch (e, s) {
_log("Error parsing OrderData: $e\nStackTrace: $s");
}
}
@@ -151,13 +167,16 @@ class _OrderOverlayState extends State<OrderOverlay>
_startTimer();
}
/// المدة الكلية للنافذة = ثواني السبق الحصري + مدة الطلب العام.
///
/// في وضع الإسناد بالدفعات: ٥ ثوانٍ الطلب خاص بهذا السائق، ثم ١٥ ثانية
/// طلب عام يتنافس فيها مع غيره — أي نافذة ٢٠ ثانية إجمالاً.
/// في البثّ الحر (بلا offerType): ١٥ ثانية عامة فقط، بلا شارة.
int _calculateTimerDuration() {
if (orderData?.durationToPassengerMinutes != null &&
orderData!.durationToPassengerMinutes > 0) {
int duration = orderData!.durationToPassengerMinutes * 60;
return duration > 10 ? 10 : duration;
}
return 10;
final int head = orderData?.offerType == 'exclusive'
? (orderData!.offerExpiresIn > 0 ? orderData!.offerExpiresIn : 5)
: 0;
return head + kPublicWindowSeconds;
}
void _startTimer() {
@@ -171,6 +190,11 @@ class _OrderOverlayState extends State<OrderOverlay>
setState(() {
if (remainingSeconds > 0) {
remainingSeconds--;
// ‏انتهى السبق: الطلب صار عاماً. النافذة لا تُغلق — السائق يظل
// ‏قادراً على القبول لكنه صار يتنافس.
if (isExclusive && remainingSeconds <= kPublicWindowSeconds) {
isExclusive = false;
}
} else {
timer.cancel();
_stopAudio();
@@ -450,12 +474,37 @@ class _OrderOverlayState extends State<OrderOverlay>
children: [
Row(
children: [
Icon(Icons.drive_eta_rounded, color: AppColors.white, size: 24),
Icon(
orderData?.isScheduled == true
? Icons.schedule
: isExclusive
? Icons.star_rounded
: Icons.drive_eta_rounded,
color: orderData?.isScheduled == true
? const Color(0xFFB39DDB)
: isExclusive
? const Color(0xFFFFD54F)
: AppColors.white,
size: 24,
),
const SizedBox(width: 8),
// ‏العنوان يحمل حالة العرض: خاص خلال السبق، عام بعده، و"طلب
// ‏جديد" في البثّ الحر حيث لا معنى للتمييز.
Text(
"طلب جديد".tr,
style: const TextStyle(
color: AppColors.white,
orderData?.isScheduled == true
// ‏الأولوية للمجدولة: معلومة دائمة عن الرحلة تسبق حالة
// ‏العرض المؤقتة، والسائق يحتاجها ليقرر إن كان يستطيع
// ‏الالتزام بالموعد.
? "🗓️ رحلة مجدولة".tr
: orderData?.offerType == null
? "طلب جديد".tr
: (isExclusive ? "⭐ طلب خاص لك".tr : "🌐 طلب عام".tr),
style: TextStyle(
color: orderData?.isScheduled == true
? const Color(0xFFB39DDB)
: isExclusive
? const Color(0xFFFFD54F)
: AppColors.white,
fontSize: 18,
fontWeight: FontWeight.w600),
),
@@ -1,11 +1,14 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intaleq_maps/intaleq_maps.dart';
import 'package:tripz_driver/constant/api_key.dart';
import 'package:tripz_driver/constant/colors.dart';
import 'package:tripz_driver/controller/home/captin/order_request_controller.dart';
import 'package:tripz_driver/constant/currency.dart';
import 'package:tripz_driver/views/widgets/driver_earnings_badge.dart';
import 'package:siro_driver/constant/api_key.dart';
import 'package:siro_driver/constant/colors.dart';
import 'package:siro_driver/controller/home/captin/order_request_controller.dart';
import 'package:siro_driver/views/widgets/offer_type_badge.dart';
import 'package:siro_driver/views/widgets/scheduled_ride_badge.dart';
import 'package:siro_driver/views/widgets/sms_ride_badge.dart';
import 'package:siro_driver/constant/currency.dart';
import 'package:siro_driver/views/widgets/driver_earnings_badge.dart';
class OrderRequestPage extends StatelessWidget {
const OrderRequestPage({super.key});
@@ -76,7 +79,7 @@ class OrderRequestPage extends StatelessWidget {
zoom: 13.0,
),
markers: controller.markers,
mapType: Get.isDarkMode
mapType: Theme.of(context).brightness == Brightness.dark
? IntaleqMapType.normal
: IntaleqMapType.light,
polylines: controller.polylines,
@@ -109,6 +112,24 @@ class OrderRequestPage extends StatelessWidget {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
// شارة الطلب الخاص/العام — تختفي في وضع البثّ الحر
if (controller.offerInfo != null) ...[
OfferTypeBadge(rideInfo: controller.offerInfo!),
const SizedBox(width: 10),
],
// شارة الرحلة المجدولة — موعد مضبوط لا طلب فوري
if (ScheduledRideBadge.isScheduled(
controller.scheduleInfo)) ...[
ScheduledRideBadge(
rideInfo: controller.scheduleInfo!),
const SizedBox(width: 10),
],
// راكب بلا إنترنت — الاتصال هو القناة الوحيدة
if (SmsRideBadge.isSmsRide(
controller.scheduleInfo)) ...[
SmsRideBadge(rideInfo: controller.scheduleInfo!),
const SizedBox(width: 10),
],
const Icon(Icons.near_me,
color: Colors.amber, size: 16),
const SizedBox(width: 8),
@@ -198,8 +219,7 @@ class OrderRequestPage extends StatelessWidget {
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
"${controller.tripPrice} ${CurrencyHelper.currency}",
Text("${controller.tripPrice} ${CurrencyHelper.currency}",
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
@@ -2,14 +2,14 @@
// import 'package:flutter/material.dart';
// import 'package:get/get.dart';
// import 'package:tripz_maps/tripz_maps.dart';
// import 'package:intaleq_maps/intaleq_maps.dart';
// import 'package:tripz_driver/controller/home/captin/home_captain_controller.dart';
// import 'package:tripz_driver/constant/box_name.dart';
// import 'package:tripz_driver/controller/firebase/firbase_messge.dart';
// import 'package:tripz_driver/main.dart';
// import 'package:tripz_driver/print.dart';
// import 'package:tripz_driver/views/home/Captin/driver_map_page.dart';
// import 'package:siro_driver/controller/home/captin/home_captain_controller.dart';
// import 'package:siro_driver/constant/box_name.dart';
// import 'package:siro_driver/controller/firebase/firbase_messge.dart';
// import 'package:siro_driver/main.dart';
// import 'package:siro_driver/print.dart';
// import 'package:siro_driver/views/home/Captin/driver_map_page.dart';
// import '../../../../constant/colors.dart';
// import '../../../../constant/links.dart';
@@ -2,7 +2,7 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intaleq_maps/intaleq_maps.dart';
import 'package:tripz_driver/constant/api_key.dart';
import 'package:siro_driver/constant/api_key.dart';
import 'dart:math' as math;
import '../../../../constant/colors.dart';
@@ -62,7 +62,7 @@ class _OrderRequestPageTestState extends State<OrderRequestPageTest> {
SizedBox(
height: Get.height * .33,
child: Obx(() => IntaleqMap(
apiKey: AK.mapSaasKey,
apiKey: AK.mapAPIKEY,
initialCameraPosition: CameraPosition(
zoom: 12,
target:
@@ -1,9 +1,9 @@
import 'dart:convert';
import 'package:tripz_driver/constant/box_name.dart';
import 'package:tripz_driver/constant/links.dart';
import 'package:tripz_driver/controller/functions/crud.dart';
import 'package:tripz_driver/views/widgets/my_scafold.dart';
import 'package:siro_driver/constant/box_name.dart';
import 'package:siro_driver/constant/links.dart';
import 'package:siro_driver/controller/functions/crud.dart';
import 'package:siro_driver/views/widgets/my_scafold.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
@@ -2,7 +2,7 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:tripz_driver/views/widgets/mycircular.dart';
import 'package:siro_driver/views/widgets/mycircular.dart';
import '../../../controller/functions/ocr_controller.dart';