first commit

This commit is contained in:
Hamza-Ayed
2026-06-09 08:40:31 +03:00
commit d8901e1a87
3161 changed files with 536187 additions and 0 deletions

View File

@@ -0,0 +1,233 @@
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
class AboutPage extends StatelessWidget {
const AboutPage({super.key});
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('About Us'.tr),
),
child: SafeArea(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Company Logo
Center(
child: Image.asset(
'assets/images/logo.gif', // Replace with your logo image asset path
height: 80.0,
),
),
const SizedBox(height: 20),
// Company Name and Introduction
Text(
'Intaleq LLC',
style: CupertinoTheme.of(context).textTheme.navTitleTextStyle,
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
Text(
"Syria's pioneering ride-sharing service, proudly developed by Arabian and local owners. We prioritize being near you both our valued passengers and our dedicated captains."
.tr,
style: CupertinoTheme.of(context).textTheme.textStyle,
textAlign: TextAlign.center,
),
const SizedBox(height: 30),
// Key Features Section
Text(
'Why Choose Intaleq?'.tr,
style: CupertinoTheme.of(context).textTheme.navTitleTextStyle,
textAlign: TextAlign.center,
),
const SizedBox(height: 15),
// Nearest Availability
Row(
children: [
const Icon(CupertinoIcons.location_solid,
color: CupertinoColors.activeBlue),
const SizedBox(width: 10),
Expanded(
child: Text(
'Closest to You'.tr,
style: CupertinoTheme.of(context).textTheme.textStyle,
),
),
],
),
const SizedBox(height: 10),
Text(
'We connect you with the nearest drivers for faster pickups and quicker journeys.'
.tr,
style: CupertinoTheme.of(context)
.textTheme
.textStyle
.copyWith(color: CupertinoColors.secondaryLabel),
),
const SizedBox(height: 20),
// High-Level Security
Row(
children: [
const Icon(CupertinoIcons.shield_fill,
color: CupertinoColors.activeGreen),
const SizedBox(width: 10),
Expanded(
child: Text(
'Uncompromising Security'.tr,
style: CupertinoTheme.of(context).textTheme.textStyle,
),
),
],
),
const SizedBox(height: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Icon(CupertinoIcons.person_2_fill,
size: 18, color: CupertinoColors.activeGreen),
const SizedBox(width: 5),
Text(
'Lady Captains Available'.tr,
style: CupertinoTheme.of(context)
.textTheme
.textStyle
.copyWith(fontSize: 15),
),
],
),
const SizedBox(height: 5),
Row(
children: [
const Icon(CupertinoIcons.recordingtape,
size: 18, color: CupertinoColors.activeGreen),
const SizedBox(width: 5),
Text(
'Recorded Trips (Voice & AI Analysis)'.tr,
style: CupertinoTheme.of(context)
.textTheme
.textStyle
.copyWith(fontSize: 15),
),
],
),
],
),
const SizedBox(height: 20),
// Fast Support
Row(
children: [
const Icon(CupertinoIcons.bolt_horizontal_fill,
color: CupertinoColors.systemOrange),
const SizedBox(width: 10),
Expanded(
child: Text(
'Fastest Complaint Response'.tr,
style: CupertinoTheme.of(context).textTheme.textStyle,
),
),
],
),
const SizedBox(height: 10),
Text(
'Our dedicated customer service team ensures swift resolution of any issues.'
.tr,
style: CupertinoTheme.of(context)
.textTheme
.textStyle
.copyWith(color: CupertinoColors.secondaryLabel),
),
const SizedBox(height: 20),
// Affordable Pricing
Row(
children: [
const Icon(CupertinoIcons.money_dollar_circle_fill,
color: CupertinoColors.activeBlue),
const SizedBox(width: 10),
Expanded(
child: Text(
'Affordable for Everyone'.tr,
style: CupertinoTheme.of(context).textTheme.textStyle,
),
),
],
),
const SizedBox(height: 10),
Text(
'Enjoy competitive prices across all trip options, making travel accessible.'
.tr,
style: CupertinoTheme.of(context)
.textTheme
.textStyle
.copyWith(color: CupertinoColors.secondaryLabel),
),
const SizedBox(height: 20),
// Trip Options
Row(
children: [
const Icon(CupertinoIcons.car_detailed,
color: CupertinoColors.systemPurple),
const SizedBox(width: 10),
Expanded(
child: Text(
'Variety of Trip Choices'.tr,
style: CupertinoTheme.of(context).textTheme.textStyle,
),
),
],
),
const SizedBox(height: 10),
Text(
'Choose the trip option that perfectly suits your needs and preferences.'
.tr,
style: CupertinoTheme.of(context)
.textTheme
.textStyle
.copyWith(color: CupertinoColors.secondaryLabel),
),
const SizedBox(height: 20),
// Passenger Choice
Row(
children: [
Icon(CupertinoIcons.hand_draw_fill,
color: CupertinoColors.systemGreen),
const SizedBox(width: 10),
Expanded(
child: Text(
'Your Choice, Our Priority'.tr,
style: CupertinoTheme.of(context).textTheme.textStyle,
),
),
],
),
const SizedBox(height: 10),
Text(
'Because we are near, you have the flexibility to choose the ride that works best for you.'
.tr,
style: CupertinoTheme.of(context)
.textTheme
.textStyle
.copyWith(color: CupertinoColors.secondaryLabel),
),
],
),
),
),
),
);
}
}

View File

@@ -0,0 +1,360 @@
import 'package:siro_rider/constant/colors.dart';
import 'package:siro_rider/constant/style.dart';
import 'package:siro_rider/views/widgets/my_scafold.dart';
import 'package:flutter/material.dart';
import 'package:flutter_font_icons/flutter_font_icons.dart';
import 'package:get/get.dart';
import '../../../controller/functions/tts.dart';
import '../../../controller/home/contact_us_controller.dart';
import '../../widgets/elevated_btn.dart';
class ContactUsPage extends StatelessWidget {
ContactUsPage({super.key});
@override
Widget build(BuildContext context) {
final controller = Get.put(ContactUsController());
final isDark = Theme.of(context).brightness == Brightness.dark;
return MyScafolld(
title: "Contact Us".tr,
isleading: true,
body: [
// Background subtle gradient/shape
Positioned.fill(
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: isDark
? [const Color(0xFF0D0D14), const Color(0xFF161622)]
: [const Color(0xFFF8F9FF), const Color(0xFFEFF1FB)],
),
),
),
),
SafeArea(
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// ── Hero Section ──────────────────────────────────────────
_buildHeroSection(isDark),
const SizedBox(height: 24),
// ── Availability Status ────────────────────────────────────
_buildAvailabilityStatus(controller, isDark),
const SizedBox(height: 24),
// ── Support Actions ────────────────────────────────────────
Text(
"Reach out to us via".tr,
style: AppStyle.title.copyWith(
fontWeight: FontWeight.bold,
fontSize: 16,
color: isDark ? Colors.white70 : Colors.black54,
),
),
const SizedBox(height: 12),
_buildContactCards(controller, isDark),
const SizedBox(height: 32),
// ── About Section ──────────────────────────────────────────
_buildAboutSection(isDark),
const SizedBox(height: 40),
],
),
),
),
],
);
}
Widget _buildHeroSection(bool isDark) {
return Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: isDark ? Colors.white.withOpacity(0.05) : Colors.white,
borderRadius: BorderRadius.circular(24),
border: Border.all(
color: isDark ? Colors.white12 : Colors.black.withOpacity(0.05),
),
boxShadow: [
BoxShadow(
color: isDark ? Colors.black26 : Colors.black.withOpacity(0.03),
blurRadius: 20,
offset: const Offset(0, 10),
)
],
),
child: Column(
children: [
Container(
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: isDark ? Colors.white10 : Colors.white,
border: Border.all(color: AppColor.primaryColor.withOpacity(0.2)),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(50),
child: Image.asset('assets/images/logo.gif', height: 80),
),
),
const SizedBox(height: 16),
Text(
"Intaleq Support".tr,
style: AppStyle.headTitle2.copyWith(
fontSize: 22,
fontWeight: FontWeight.bold,
color: isDark ? Colors.white : AppColor.primaryColor,
),
),
const SizedBox(height: 4),
Text(
"We're here to help you 24/7".tr,
style: TextStyle(
color: isDark ? Colors.white54 : Colors.black45,
fontSize: 14,
),
),
],
),
);
}
Widget _buildAvailabilityStatus(ContactUsController controller, bool isDark) {
final isOpen = controller.isWorkTime;
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: BoxDecoration(
color: (isOpen ? AppColor.greenColor : Colors.orange).withOpacity(0.1),
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: (isOpen ? AppColor.greenColor : Colors.orange).withOpacity(0.2),
),
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: isOpen ? AppColor.greenColor : Colors.orange,
),
child: Icon(
isOpen ? Icons.check_circle_outline : Icons.access_time,
color: Colors.white,
size: 18,
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
isOpen ? "Support is currently Online".tr : "Support is Away".tr,
style: TextStyle(
fontWeight: FontWeight.bold,
color: isOpen ? AppColor.greenColor : Colors.orange,
),
),
Text(
"${"Working Hours:".tr} ${controller.workHoursString}",
style: TextStyle(
fontSize: 12,
color: isDark ? Colors.white60 : Colors.black54,
),
),
],
),
),
],
),
);
}
Widget _buildContactCards(ContactUsController controller, bool isDark) {
return Column(
children: [
_ContactCard(
title: "Voice Call".tr,
subtitle: "Direct talk with our team".tr,
icon: Icons.phone_in_talk_outlined,
color: AppColor.primaryColor,
isDark: isDark,
enabled: controller.isWorkTime,
onTap: controller.makeCall,
trailing: controller.isWorkTime ? null : Icon(Icons.lock_clock_outlined, size: 20, color: isDark ? Colors.white24 : Colors.black26),
),
const SizedBox(height: 12),
_ContactCard(
title: "WhatsApp".tr,
subtitle: "Chat with us anytime".tr,
icon: FontAwesome.whatsapp,
color: AppColor.greenColor,
isDark: isDark,
onTap: controller.sendWhatsApp,
),
const SizedBox(height: 12),
_ContactCard(
title: "Email Support".tr,
subtitle: "For official inquiries".tr,
icon: Icons.alternate_email_outlined,
color: AppColor.redColor,
isDark: isDark,
onTap: controller.sendEmail,
),
],
);
}
Widget _buildAboutSection(bool isDark) {
return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: isDark ? Colors.white.withOpacity(0.02) : Colors.black.withOpacity(0.02),
borderRadius: BorderRadius.circular(24),
border: Border.all(color: isDark ? Colors.white10 : Colors.black12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"About Intaleq".tr,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
color: isDark ? Colors.white : Colors.black87,
),
),
IconButton(
onPressed: () {
Get.find<TextToSpeechController>().speakText(
'Intaleq is the safest and most reliable ride-sharing app designed especially for passengers in Syria. We provide a comfortable, respectful, and affordable riding experience with features that prioritize your safety and convenience.'
.tr,
);
},
icon: Icon(Icons.volume_up_outlined, color: AppColor.primaryColor),
),
],
),
const SizedBox(height: 12),
Text(
'Intaleq is the safest and most reliable ride-sharing app designed especially for passengers in Syria. We provide a comfortable, respectful, and affordable riding experience with features that prioritize your safety and convenience. Our trusted captains are verified, insured, and supported by regular car maintenance carried out by top engineers. We also offer on-road support services to make sure every trip is smooth and worry-free. With Intaleq, you enjoy quality, safety, and peace of mind—every time you ride.'
.tr,
style: TextStyle(
color: isDark ? Colors.white70 : Colors.black54,
fontSize: 14,
height: 1.6,
),
),
],
),
);
}
}
class _ContactCard extends StatelessWidget {
final String title;
final String subtitle;
final IconData icon;
final Color color;
final bool isDark;
final bool enabled;
final VoidCallback onTap;
final Widget? trailing;
const _ContactCard({
required this.title,
required this.subtitle,
required this.icon,
required this.color,
required this.isDark,
this.enabled = true,
required this.onTap,
this.trailing,
});
@override
Widget build(BuildContext context) {
return Material(
color: Colors.transparent,
child: InkWell(
onTap: enabled ? onTap : null,
borderRadius: BorderRadius.circular(20),
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: enabled
? (isDark ? Colors.white.withOpacity(0.05) : Colors.white)
: (isDark ? Colors.white.withOpacity(0.02) : Colors.grey.withOpacity(0.05)),
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: enabled
? (isDark ? Colors.white12 : Colors.black.withOpacity(0.05))
: Colors.transparent,
),
boxShadow: enabled ? [
BoxShadow(
color: isDark ? Colors.black12 : Colors.black.withOpacity(0.02),
blurRadius: 10,
offset: const Offset(0, 4),
)
] : null,
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: (enabled ? color : Colors.grey).withOpacity(0.12),
borderRadius: BorderRadius.circular(14),
),
child: Icon(icon, color: enabled ? color : Colors.grey, size: 24),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
color: enabled
? (isDark ? Colors.white : Colors.black87)
: Colors.grey,
),
),
Text(
subtitle,
style: TextStyle(
fontSize: 13,
color: isDark ? Colors.white38 : Colors.black38,
),
),
],
),
),
trailing ?? Icon(
Icons.arrow_forward_ios,
size: 14,
color: isDark ? Colors.white24 : Colors.black12,
),
],
),
),
),
);
}
}

View File

@@ -0,0 +1,228 @@
import 'package:siro_rider/views/home/HomePage/contact_us.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class FrequentlyQuestionsPage extends StatelessWidget {
const FrequentlyQuestionsPage({super.key});
void _showAnswerDialog(BuildContext context, String question, String answer) {
showCupertinoDialog(
context: context,
builder: (BuildContext context) => CupertinoAlertDialog(
title: Text(question,
style: const TextStyle(
fontWeight: FontWeight.bold, color: Colors.indigo)),
content: Text(answer),
actions: <CupertinoDialogAction>[
CupertinoDialogAction(
isDefaultAction: true,
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Close'),
),
],
),
);
}
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
backgroundColor: Colors.indigo,
middle: Text(
'Frequently Asked Questions'.tr,
style: const TextStyle(color: Colors.white),
),
),
child: SafeArea(
child: ListView(
children: <Widget>[
CupertinoListSection.insetGrouped(
header: Text(
'Getting Started'.tr,
style: const TextStyle(fontWeight: FontWeight.bold),
),
children: <CupertinoListTile>[
CupertinoListTile(
leading: const Icon(
CupertinoIcons.car_detailed,
color: Colors.indigo,
),
title: Text('How do I request a ride?'.tr),
trailing: const CupertinoListTileChevron(),
onTap: () => _showAnswerDialog(
context,
'How do I request a ride?'.tr,
'Simply open the Intaleq app, enter your destination, and tap "Request Ride". The app will connect you with a nearby driver.'
.tr,
),
),
],
),
CupertinoListSection.insetGrouped(
header: Text(
'Vehicle Options'.tr,
style: const TextStyle(fontWeight: FontWeight.bold),
),
children: <CupertinoListTile>[
CupertinoListTile(
leading: const Icon(
CupertinoIcons.car_fill,
color: Colors.blue,
),
title: Text('What types of vehicles are available?'.tr),
trailing: const CupertinoListTileChevron(),
onTap: () => _showAnswerDialog(
context,
'What types of vehicles are available?'.tr,
'Intaleq offers a variety of options including Economy, Comfort, and Luxury to suit your needs and budget.'
.tr,
),
),
],
),
CupertinoListSection.insetGrouped(
header: Text(
'Payments'.tr,
style: const TextStyle(fontWeight: FontWeight.bold),
),
children: <CupertinoListTile>[
CupertinoListTile(
leading: const Icon(
CupertinoIcons.creditcard,
color: Colors.green,
),
title: Text('How can I pay for my ride?'.tr),
trailing: const CupertinoListTileChevron(),
onTap: () => _showAnswerDialog(
context,
'How can I pay for my ride?'.tr,
'You can pay for your ride using cash or credit/debit card. You can select your preferred payment method before confirming your ride.'
.tr,
),
),
],
),
CupertinoListSection.insetGrouped(
header: Text(
'Ride Management'.tr,
style: const TextStyle(fontWeight: FontWeight.bold),
),
children: <CupertinoListTile>[
CupertinoListTile(
leading: const Icon(
CupertinoIcons.xmark_circle_fill,
color: Colors.red,
),
title: Text('Can I cancel my ride?'.tr),
trailing: const CupertinoListTileChevron(),
onTap: () => _showAnswerDialog(
context,
'Can I cancel my ride?'.tr,
'Yes, you can cancel your ride, but please note that cancellation fees may apply depending on how far in advance you cancel.'
.tr,
),
),
],
),
CupertinoListSection.insetGrouped(
header: Text(
'For Drivers'.tr,
style: const TextStyle(fontWeight: FontWeight.bold),
),
children: <CupertinoListTile>[
CupertinoListTile(
leading: const Icon(
CupertinoIcons.person_crop_circle_fill,
color: Colors.orange,
),
title: Text('Driver Registration & Requirements'.tr),
trailing: const CupertinoListTileChevron(),
onTap: () => showCupertinoDialog(
context: context,
builder: (BuildContext context) => CupertinoAlertDialog(
title: Text('Driver Registration'.tr,
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.indigo)),
content: Text(
'To register as a driver or learn about the requirements, please visit our website or contact Intaleq support directly.'
.tr),
actions: <CupertinoDialogAction>[
CupertinoDialogAction(
isDefaultAction: true,
onPressed: () {
Get.to(() => ContactUsPage());
// Optionally, you can open a URL here
},
child: Text('Visit Website/Contact Support'.tr),
),
CupertinoDialogAction(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Close'.tr),
),
],
),
),
),
],
),
CupertinoListSection.insetGrouped(
header: Text(
'Communication'.tr,
style: const TextStyle(fontWeight: FontWeight.bold),
),
children: <CupertinoListTile>[
CupertinoListTile(
leading: const Icon(
CupertinoIcons.chat_bubble_2_fill,
color: Colors.purple,
),
title: Text(
'How do I communicate with the other party (passenger/driver)?'
.tr),
trailing: const CupertinoListTileChevron(),
onTap: () => _showAnswerDialog(
context,
'How do I communicate with the other party (passenger/driver)?'
.tr,
'You can communicate with your driver or passenger through the in-app chat feature once a ride is confirmed.'
.tr,
),
),
],
),
CupertinoListSection.insetGrouped(
header: Text(
'Safety & Security'.tr,
style: const TextStyle(fontWeight: FontWeight.bold),
),
children: <CupertinoListTile>[
CupertinoListTile(
leading: const Icon(
CupertinoIcons.shield_fill,
color: Colors.teal,
),
title: Text('What safety measures does Intaleq offer?'.tr),
trailing: const CupertinoListTileChevron(),
onTap: () => _showAnswerDialog(
context,
'What safety measures does Intaleq offer?'.tr,
'Intaleq offers various safety features including driver verification, in-app trip tracking, emergency contact options, and the ability to share your trip status with trusted contacts.'
.tr,
),
),
],
),
const SizedBox(height: 20), // Add some bottom padding
],
),
),
);
}
}

View File

@@ -0,0 +1,577 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../constant/colors.dart';
import '../../../constant/style.dart';
import '../../../controller/home/profile/invit_controller.dart';
import '../../../print.dart';
class ShareAppPage extends StatelessWidget {
final InviteController controller = Get.put(InviteController());
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColor.secondaryColor,
appBar: AppBar(
backgroundColor: AppColor.secondaryColor,
elevation: 0,
title: Text(
'Invite'.tr,
style: AppStyle.headTitle2.copyWith(fontSize: 20),
),
leading: IconButton(
icon: Icon(Icons.arrow_back_ios, color: AppColor.cyanBlue),
onPressed: () => Get.back(),
),
),
body: SafeArea(
child: GetBuilder<InviteController>(
builder: (controller) {
return Column(
children: [
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: _buildPassengerTab(context),
),
),
],
);
},
),
),
);
}
Widget _buildPassengerTab(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppColor.grayColor.withOpacity(0.08),
borderRadius: BorderRadius.circular(12),
),
child: Column(
children: [
Text(
"Share this code with your friends and earn rewards when they use it!"
.tr,
textAlign: TextAlign.center,
style: TextStyle(
color: AppColor.grayColor,
fontSize: 13,
),
),
],
),
),
const SizedBox(height: 20),
_buildPhoneInput(),
const SizedBox(height: 20),
_buildActionButtonsPassengers(),
const SizedBox(height: 20),
const SizedBox(height: 20),
_buildInvitationsListPassengers(context),
],
);
}
// Widget _buildPhoneInput() {
// return Container(
// decoration: BoxDecoration(
// color: CupertinoColors.systemGrey6,
// borderRadius: BorderRadius.circular(8),
// ),
// child: Row(
// children: [
// Expanded(
// child: CupertinoTextField.borderless(
// controller: controller.invitePhoneController,
// placeholder: 'Enter phone'.tr,
// padding: const EdgeInsets.all(12),
// keyboardType: TextInputType.phone,
// ),
// ),
// CupertinoButton(
// child: const Icon(CupertinoIcons.person_badge_plus,
// color: AppColor.blueColor),
// onPressed: () async {
// await controller.pickContacts();
// if (controller.contacts.isNotEmpty) {
// if (box.read(BoxName.isSavedPhones) == null) {
// controller.savePhoneToServer();
// box.write(BoxName.isSavedPhones, true);
// }
// _showContactsDialog(Get.context!);
// }
// },
// ),
// ],
// ),
// );
// }
Widget _buildPhoneInput() {
return Container(
decoration: BoxDecoration(
color: AppColor.grayColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColor.grayColor.withOpacity(0.1)),
),
child: Row(
children: [
Expanded(
child: CupertinoTextField.borderless(
controller: controller.invitePhoneController,
placeholder: 'Enter phone'.tr,
placeholderStyle: TextStyle(
color: AppColor.grayColor.withOpacity(0.5), fontSize: 16),
style: TextStyle(color: AppColor.writeColor, fontSize: 16),
padding: const EdgeInsets.all(14),
keyboardType: TextInputType.phone,
),
),
CupertinoButton(
child: Icon(CupertinoIcons.person_badge_plus,
color: AppColor.cyanBlue),
onPressed: () async {
await controller.pickContacts();
Log.print('contacts: ${controller.contacts}');
if (controller.contacts.isNotEmpty) {
_showContactsDialog(Get
.context!); // Show contacts dialog after loading contacts
} else {
Get.snackbar(
'No contacts available'.tr,
'Please add contacts to your phone.'.tr,
);
}
},
),
],
),
);
}
Widget _buildActionButtonsPassengers() {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 16.0),
child: Row(
children: [
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 6,
offset: const Offset(0, 3),
),
],
),
child: CupertinoButton(
color: AppColor.primaryColor,
borderRadius: BorderRadius.circular(10),
padding: const EdgeInsets.symmetric(vertical: 14),
onPressed: controller.sendInviteToPassenger,
child: Text(
'Send Invite'.tr,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: AppColor.secondaryColor,
),
),
),
),
),
const SizedBox(width: 16),
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 6,
offset: const Offset(0, 3),
),
],
),
child: CupertinoButton(
color: AppColor.cyanBlue,
borderRadius: BorderRadius.circular(10),
padding: const EdgeInsets.symmetric(vertical: 14),
child: Text(
'Show Invitations'.tr,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: AppColor.secondaryColor,
),
),
onPressed: () async {
controller.fetchDriverStatsPassengers();
},
),
),
),
],
),
);
}
Widget _buildInvitationsListPassengers(BuildContext context) {
return SizedBox(
height: Get.height * .4,
child: controller.driverInvitationDataToPassengers.isEmpty
? Center(
child: Text(
"No invitation found yet!".tr,
style: TextStyle(
color: AppColor.grayColor,
fontSize: 17,
),
),
)
: ListView.builder(
itemCount: controller.driverInvitationDataToPassengers.length,
itemBuilder: (context, index) {
return _buildInvitationItemPassengers(context, index);
},
),
);
}
Widget _buildInvitationItemPassengers(BuildContext context, int index) {
// Extracting the data from the sample JSON-like structure
var invitation = controller.driverInvitationDataToPassengers[index];
int countOfInvitDriver =
int.tryParse(invitation['countOfInvitDriver']?.toString() ?? '0') ?? 0;
double progressValue = (countOfInvitDriver / 10.0).clamp(0.0, 1.0);
return GestureDetector(
onTap: () {
controller.onSelectPassengerInvitation(index);
},
child: Container(
margin: const EdgeInsets.symmetric(vertical: 8.0),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppColor.grayColor.withOpacity(0.08),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColor.grayColor.withOpacity(0.05)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
invitation['passengerName']
.toString(), // Handle null or missing data
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.w600,
color: AppColor.writeColor,
),
),
const SizedBox(height: 8),
ClipRRect(
borderRadius: BorderRadius.circular(4),
child: LinearProgressIndicator(
value: progressValue,
backgroundColor: AppColor.grayColor.withOpacity(0.1),
valueColor:
AlwaysStoppedAnimation<Color>(AppColor.primaryColor),
minHeight: 6,
),
),
const SizedBox(height: 4),
Text(
'$countOfInvitDriver / 2 ${'Trip'.tr}', // Show trips completed
style: TextStyle(
fontSize: 13,
color: AppColor.grayColor,
),
),
],
),
),
);
}
Widget _buildPassengerStats(BuildContext context) {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppColor.grayColor.withOpacity(0.08),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColor.grayColor.withOpacity(0.05)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Your Rewards".tr,
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.w600,
color: AppColor.writeColor,
),
),
const SizedBox(height: 16),
_buildStatItem(
context,
"Total Invites".tr,
controller.driverInvitationDataToPassengers[0]['countOfInvitDriver']
.toString(),
),
_buildStatItem(
context,
"Active Users".tr,
controller.driverInvitationDataToPassengers[0]['passengerName']
.toString(),
),
],
),
);
}
Widget _buildStatItem(BuildContext context, String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
label,
style: TextStyle(
color: AppColor.writeColor,
fontSize: 15,
),
),
Text(
value,
style: const TextStyle(
fontWeight: FontWeight.w600,
color: AppColor.blueColor,
fontSize: 15,
),
),
],
),
);
}
void _showContactsDialog(BuildContext context) {
Get.defaultDialog(
backgroundColor: AppColor.secondaryColor,
title: 'Choose from contact'.tr,
titleStyle: TextStyle(color: AppColor.writeColor),
content: SizedBox(
height: 400,
width: 400,
child: Column(
children: [
// Header with cancel and title
// Container(
// padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
// decoration: const BoxDecoration(
// borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
// color: CupertinoColors.systemGrey6,
// ),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// CupertinoButton(
// padding: EdgeInsets.zero,
// child: Text(
// 'Cancel'.tr,
// style: const TextStyle(color: CupertinoColors.systemBlue),
// ),
// onPressed: () => Navigator.pop(context),
// ),
// Container(
// child: Text('Choose from contact'.tr,
// style: AppStyle.title)),
// const SizedBox(width: 60), // Balance for Cancel button
// ],
// ),
// ),
// Contact list
Expanded(
child: ListView.builder(
itemCount: controller.contactMaps.length,
itemBuilder: (context, index) {
final contact = controller.contactMaps[index];
return CupertinoButton(
padding: EdgeInsets.zero,
onPressed: () {
controller.selectPhone(contact['phones'].toString());
},
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 16, vertical: 12),
decoration: BoxDecoration(
color: AppColor.secondaryColor,
border: Border(
bottom: BorderSide(
color: AppColor.grayColor.withOpacity(0.1),
),
),
),
child: Row(
children: [
// Display contact name and phone number
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
contact['name'],
style: TextStyle(
color: AppColor.writeColor,
fontSize: 17,
fontWeight: FontWeight.w500,
),
),
Text(
(contact['phones'][0].toString()),
style: TextStyle(
color: AppColor.grayColor,
fontSize: 15,
),
),
],
),
),
// Chevron icon for selection
Icon(
CupertinoIcons.chevron_forward,
color: AppColor.grayColor.withOpacity(0.5),
),
],
),
),
);
},
),
),
],
),
),
);
// showCupertinoModalPopup(
// context: context,
// builder: (BuildContext context) => Container(
// height: 400,
// decoration: BoxDecoration(
// color: CupertinoColors.systemBackground,
// borderRadius: const BorderRadius.vertical(top: Radius.circular(20)),
// boxShadow: [
// BoxShadow(
// color: CupertinoColors.black.withOpacity(0.2),
// offset: const Offset(0, -4),
// blurRadius: 10,
// ),
// ],
// ),
// child: Column(
// children: [
// // Header with cancel and title
// Container(
// padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
// decoration: const BoxDecoration(
// borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
// color: CupertinoColors.systemGrey6,
// ),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// CupertinoButton(
// padding: EdgeInsets.zero,
// child: Text(
// 'Cancel'.tr,
// style: const TextStyle(color: CupertinoColors.systemBlue),
// ),
// onPressed: () => Navigator.pop(context),
// ),
// Container(
// child: Text('Choose from contact'.tr,
// style: AppStyle.title)),
// const SizedBox(width: 60), // Balance for Cancel button
// ],
// ),
// ),
// // Contact list
// Expanded(
// child: ListView.builder(
// itemCount: controller.contactMaps.length,
// itemBuilder: (context, index) {
// final contact = controller.contactMaps[index];
// return CupertinoButton(
// padding: EdgeInsets.zero,
// onPressed: () {
// controller.selectPhone(contact['phones'].toString());
// },
// child: Container(
// padding: const EdgeInsets.symmetric(
// horizontal: 16, vertical: 12),
// decoration: BoxDecoration(
// color: CupertinoColors.systemBackground,
// border: Border(
// bottom: BorderSide(
// color: CupertinoColors.separator.withOpacity(0.5),
// ),
// ),
// ),
// child: Row(
// children: [
// // Display contact name and phone number
// Expanded(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// contact['name'],
// style: const TextStyle(
// color: CupertinoColors.label,
// fontSize: 17,
// fontWeight: FontWeight.w500,
// ),
// ),
// Text(
// controller.formatPhoneNumber(
// contact['phones'][0].toString()),
// style: const TextStyle(
// color: CupertinoColors.secondaryLabel,
// fontSize: 15,
// ),
// ),
// ],
// ),
// ),
// // Chevron icon for selection
// const Icon(
// CupertinoIcons.chevron_forward,
// color: CupertinoColors.systemGrey2,
// ),
// ],
// ),
// ),
// );
// },
// ),
// ),
// ],
// ),
// ),
// );
}
}

View File

@@ -0,0 +1,90 @@
import 'dart:io';
import 'package:siro_rider/controller/home/trip_monitor_controller.dart';
import 'package:siro_rider/env/env.dart';
import 'package:siro_rider/views/widgets/my_scafold.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:intaleq_maps/intaleq_maps.dart';
import 'package:vibration/vibration.dart';
import '../../../../constant/colors.dart';
import '../../../../constant/style.dart';
import '../../../widgets/elevated_btn.dart';
class TripMonitor extends StatelessWidget {
const TripMonitor({super.key});
@override
Widget build(BuildContext context) {
final params = Get.parameters;
// Use params to initialize your controller or pass data
Get.put(TripMonitorController()).init();
return GetBuilder<TripMonitorController>(builder: (tripMonitorController) {
return MyScafolld(
title: 'Trip Monitor'.tr,
body: [
IntaleqMap(
apiKey: Env.mapSaasKey,
onMapCreated: tripMonitorController.onMapCreated,
onStyleLoaded: tripMonitorController.onStyleLoaded,
initialCameraPosition: CameraPosition(
target: tripMonitorController.parentLocation,
zoom: 16,
tilt: 40,
),
markers: tripMonitorController.markers,
),
speedCircle()
],
isleading: true,
);
});
}
}
GetBuilder<TripMonitorController> speedCircle() {
if (Get.find<TripMonitorController>().speed > 100) {
if (Platform.isIOS) {
HapticFeedback.selectionClick();
} else {
Vibration.vibrate(duration: 1000);
}
Get.defaultDialog(
barrierDismissible: false,
titleStyle: AppStyle.title,
title: 'Speed Over'.tr,
middleText: 'Please slow down'.tr,
middleTextStyle: AppStyle.title,
confirm: MyElevatedButton(
title: 'I will slow down'.tr,
onPressed: () => Get.back(),
),
);
}
return GetBuilder<TripMonitorController>(
builder: (tripMonitorController) {
return Positioned(
bottom: 25,
right: 100,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: tripMonitorController.speed > 100
? Colors.red
: AppColor.secondaryColor,
border: Border.all(width: 3, color: AppColor.redColor),
),
height: 60,
width: 60,
child: Center(
child: Text(
tripMonitorController.speed.toStringAsFixed(0),
style: AppStyle.number,
),
),
),
);
},
);
}

View File

@@ -0,0 +1,97 @@
import 'dart:io';
import 'package:siro_rider/controller/home/trip_monitor_controller.dart';
import 'package:siro_rider/env/env.dart';
import 'package:siro_rider/views/widgets/my_scafold.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:intaleq_maps/intaleq_maps.dart';
import 'package:vibration/vibration.dart';
import '../../../../constant/colors.dart';
import '../../../../constant/style.dart';
import '../../../widgets/elevated_btn.dart';
class TripMonitor extends StatelessWidget {
const TripMonitor({super.key});
@override
Widget build(BuildContext context) {
final params = Get.parameters;
final arguments = Get.arguments as Map<String, dynamic>?;
// Use params or arguments to initialize your controller
final controller = Get.put(TripMonitorController());
controller.init(
rideId: params['rideId'] ?? arguments?['rideId'],
driverId: params['driverId'] ?? arguments?['driverId'],
);
return GetBuilder<TripMonitorController>(builder: (tripMonitorController) {
return MyScafolld(
title: 'Trip Monitor'.tr,
body: [
IntaleqMap(
apiKey: Env.mapSaasKey,
onMapCreated: tripMonitorController.onMapCreated,
onStyleLoaded: controller.onStyleLoaded,
initialCameraPosition: CameraPosition(
target: tripMonitorController.parentLocation,
zoom: 16,
tilt: 40,
),
markers: tripMonitorController.markers,
),
speedCircle()
],
isleading: true,
);
});
}
}
GetBuilder<TripMonitorController> speedCircle() {
if (Get.find<TripMonitorController>().speed > 100) {
if (Platform.isIOS) {
HapticFeedback.selectionClick();
} else {
Vibration.vibrate(duration: 1000);
}
Get.defaultDialog(
barrierDismissible: false,
titleStyle: AppStyle.title,
title: 'Speed Over'.tr,
middleText: 'Please slow down'.tr,
middleTextStyle: AppStyle.title,
confirm: MyElevatedButton(
title: 'I will slow down'.tr,
onPressed: () => Get.back(),
),
);
}
return GetBuilder<TripMonitorController>(
builder: (tripMonitorController) {
return Positioned(
bottom: 25,
right: 100,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: tripMonitorController.speed > 100
? Colors.red
: AppColor.secondaryColor,
border: Border.all(width: 3, color: AppColor.redColor),
),
height: 60,
width: 60,
child: Center(
child: Text(
tripMonitorController.speed.toStringAsFixed(0),
style: AppStyle.number,
),
),
),
);
},
);
}

View File

@@ -0,0 +1,263 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:path/path.dart' as path;
import 'package:share_plus/share_plus.dart';
import '../../../controller/functions/audio_record1.dart';
class TripsRecordedPage extends StatelessWidget {
const TripsRecordedPage({super.key});
@override
Widget build(BuildContext context) {
// Ensure the controller is available.
// If it's not initialized elsewhere, you can use Get.put() or Get.lazyPut() here.
// Get.lazyPut(() => AudioRecorderController());
return Scaffold(
appBar: AppBar(
title: Text('Trips recorded'.tr),
backgroundColor: Colors.white,
elevation: 1,
actions: [
GetBuilder<AudioRecorderController>(
builder: (controller) => IconButton(
tooltip: 'Delete All'.tr,
icon: const Icon(Icons.delete_sweep_outlined),
onPressed: () {
_showDeleteConfirmation(context, controller, isDeleteAll: true);
},
),
)
],
),
body: GetBuilder<AudioRecorderController>(
builder: (controller) {
return Column(
children: [
Expanded(
child: _buildRecordingsList(controller),
),
// Show player controls only when a file is selected
if (controller.selectedFilePath != null)
_buildPlayerControls(context, controller),
],
);
},
),
);
}
/// Builds the list of recorded audio files.
Widget _buildRecordingsList(AudioRecorderController controller) {
return FutureBuilder<List<String>>(
future: controller.getRecordedFiles(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'.tr));
}
if (!snapshot.hasData || snapshot.data!.isEmpty) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.mic_off_outlined, size: 80, color: Colors.grey[400]),
const SizedBox(height: 16),
Text(
'No Recordings Found'.tr,
style: TextStyle(fontSize: 18, color: Colors.grey[600]),
),
const SizedBox(height: 8),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 40.0),
child: Text(
'Record your trips to see them here.'.tr,
textAlign: TextAlign.center,
style: TextStyle(color: Colors.grey[500]),
),
),
],
),
);
}
final recordedFiles = snapshot.data!;
return ListView.builder(
padding: const EdgeInsets.only(top: 8, bottom: 8),
itemCount: recordedFiles.length,
itemBuilder: (context, index) {
final file = recordedFiles[index];
final fileName = path.basename(file);
final isSelected = controller.selectedFilePath == file;
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
elevation: isSelected ? 4 : 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12)),
child: ListTile(
leading: Icon(
isSelected && controller.isPlaying
? Icons.pause_circle_filled
: Icons.play_circle_fill,
color:
isSelected ? Theme.of(context).primaryColor : Colors.grey,
size: 40,
),
title: Text(fileName,
style: const TextStyle(fontWeight: FontWeight.w500)),
subtitle: Text("Audio Recording".tr),
onTap: () {
if (isSelected) {
controller.isPlaying
? controller.pausePlayback()
: controller.resumePlayback();
} else {
controller.playRecordedFile(file);
}
},
selected: isSelected,
selectedTileColor:
Theme.of(context).primaryColor.withOpacity(0.1),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12)),
),
);
},
);
},
);
}
/// Builds the player UI at the bottom of the screen.
Widget _buildPlayerControls(
BuildContext context, AudioRecorderController controller) {
final fileName = path.basename(controller.selectedFilePath!);
final positionText = Duration(seconds: controller.currentPosition.toInt())
.toString()
.split('.')
.first
.padLeft(8, '0')
.substring(3);
final durationText = Duration(seconds: controller.totalDuration.toInt())
.toString()
.split('.')
.first
.padLeft(8, '0')
.substring(3);
return Material(
elevation: 10,
child: Container(
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(fileName,
style:
const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
textAlign: TextAlign.center),
const SizedBox(height: 8),
Row(
children: [
Text(positionText),
Expanded(
child: Slider(
value: (controller.totalDuration > 0)
? controller.currentPosition / controller.totalDuration
: 0.0,
onChanged: (value) {
final newPosition = value * controller.totalDuration;
controller.audioPlayer
.seek(Duration(seconds: newPosition.toInt()));
},
),
),
Text(durationText),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
icon: const Icon(Icons.share_outlined),
tooltip: 'Share'.tr,
onPressed: () {
Share.shareXFiles([XFile(controller.selectedFilePath!)]);
},
iconSize: 28,
),
IconButton(
icon: Icon(controller.isPlaying
? Icons.pause_circle_filled
: Icons.play_circle_filled),
onPressed: () {
controller.isPlaying
? controller.pausePlayback()
: controller.resumePlayback();
},
iconSize: 56,
color: Theme.of(context).primaryColor,
),
IconButton(
icon:
const Icon(Icons.delete_outline, color: Colors.redAccent),
tooltip: 'Delete'.tr,
onPressed: () {
_showDeleteConfirmation(context, controller,
isDeleteAll: false);
},
iconSize: 28,
),
],
)
],
),
),
);
}
/// Shows a confirmation dialog for deleting one or all files.
void _showDeleteConfirmation(
BuildContext context,
AudioRecorderController controller, {
required bool isDeleteAll,
}) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(isDeleteAll
? 'Delete All Recordings?'.tr
: 'Delete Recording?'.tr),
content: Text(isDeleteAll
? 'This action cannot be undone.'.tr
: 'Are you sure you want to delete this file?'.tr),
actions: [
TextButton(
child: Text('Cancel'.tr),
onPressed: () => Navigator.of(context).pop(),
),
TextButton(
child:
Text('Delete'.tr, style: const TextStyle(color: Colors.red)),
onPressed: () async {
if (isDeleteAll) {
await controller.deleteAllRecordedFiles();
} else {
// NOTE: You may need to add this method to your controller
// if it doesn't exist.
// await controller.deleteFile(controller.selectedFilePath!);
}
Navigator.of(context).pop();
},
),
],
);
},
);
}
}