This commit is contained in:
Hamza-Ayed
2024-11-09 10:49:04 +02:00
parent fc81405b7a
commit 213c2724aa
44 changed files with 3009 additions and 1130 deletions

View File

@@ -1,101 +1,153 @@
import 'package:SEFER/constant/box_name.dart';
import 'package:SEFER/constant/style.dart';
import 'package:SEFER/main.dart';
import 'package:SEFER/views/widgets/my_scafold.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter/cupertino.dart';
class AboutPage extends StatelessWidget {
const AboutPage({super.key});
@override
Widget build(BuildContext context) {
return MyScafolld(
title: 'About Us'.tr,
body: [
// Company Logo (consider adding an image asset)
ListView(
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('About Us'.tr),
),
child: SafeArea(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Company Logo
Center(
child: Image.asset(
'assets/images/logo.png', // Replace with your logo image asset path
height: 100.0,
width: 100.0,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Image.asset(
'assets/images/logo.png', // Replace with your logo image asset path
height: 100.0,
width: 100.0,
),
),
), // Company Name and Location
),
// Company Name and Location
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'SEFER LLC\n${box.read(BoxName.countryCode).toString().tr}',
style: AppStyle.headTitle2,
style:
CupertinoTheme.of(context).textTheme.textStyle.copyWith(
fontSize: 22.0,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
),
// About Us Description
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
'SEFER 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,
style:
CupertinoTheme.of(context).textTheme.textStyle.copyWith(
fontSize: 16.0,
),
textAlign: TextAlign.center,
),
), // Security Features List
const SizedBox(
height: 20,
),
const SizedBox(height: 20),
// Security Features
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
children: [
Row(
children: [
const Icon(Icons.lock, color: Colors.blue),
const Icon(CupertinoIcons.lock_fill,
color: CupertinoColors.activeBlue),
const SizedBox(width: 8.0),
Text(
'Most Secure Methods'.tr,
style: AppStyle.title,
Expanded(
child: Text(
'Most Secure Methods'.tr,
style: CupertinoTheme.of(context)
.textTheme
.textStyle
.copyWith(
fontSize: 16.0,
fontWeight: FontWeight.w500,
),
),
),
],
),
const SizedBox(height: 8.0),
Row(
children: [
const Icon(Icons.phone, color: Colors.blue),
const Icon(CupertinoIcons.phone_fill,
color: CupertinoColors.activeBlue),
const SizedBox(width: 8.0),
Text(
'In-App VOIP Calls'.tr,
style: AppStyle.title,
Expanded(
child: Text(
'In-App VOIP Calls'.tr,
style: CupertinoTheme.of(context)
.textTheme
.textStyle
.copyWith(
fontSize: 16.0,
fontWeight: FontWeight.w500,
),
),
),
],
),
const SizedBox(height: 8.0),
Row(
children: [
const Icon(Icons.videocam, color: Colors.blue),
const Icon(CupertinoIcons.videocam_fill,
color: CupertinoColors.activeBlue),
const SizedBox(width: 8.0),
Text(
'Recorded Trips for Safety'.tr,
style: AppStyle.title,
Expanded(
child: Text(
'Recorded Trips for Safety'.tr,
style: CupertinoTheme.of(context)
.textTheme
.textStyle
.copyWith(
fontSize: 16.0,
fontWeight: FontWeight.w500,
),
),
),
],
),
],
),
), // Affordability Highlight
),
// Affordability Highlight
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
'\nWe also prioritize affordability, offering competitive pricing to make your rides accessible.'
.tr,
style: AppStyle.title,
style:
CupertinoTheme.of(context).textTheme.textStyle.copyWith(
fontSize: 16.0,
fontWeight: FontWeight.w500,
),
textAlign: TextAlign.center,
),
),
const SizedBox(height: 20),
],
),
// About Us Text
],
isleading: true);
),
),
);
}
}

View File

@@ -0,0 +1,437 @@
import 'package:SEFER/constant/style.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../constant/box_name.dart';
import '../../../constant/colors.dart';
import '../../../controller/home/profile/invit_controller.dart';
import '../../../main.dart';
class ShareAppPage extends StatelessWidget {
final InviteController controller = Get.put(InviteController());
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: CupertinoColors.systemBackground,
appBar: AppBar(
backgroundColor: CupertinoColors.systemBackground,
elevation: 0,
title: Text(
'Invite'.tr,
style: const TextStyle(color: CupertinoColors.label),
),
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios, color: AppColor.blueColor),
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: CupertinoColors.systemGrey6,
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: const TextStyle(
color: CupertinoColors.secondaryLabel,
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 _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.blueColor,
borderRadius: BorderRadius.circular(10),
padding: const EdgeInsets.symmetric(vertical: 14),
onPressed: controller.sendInviteToPassenger,
child: Text(
'Send Invite'.tr,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: CupertinoColors.white,
),
),
),
),
),
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.blueColor,
borderRadius: BorderRadius.circular(10),
padding: const EdgeInsets.symmetric(vertical: 14),
child: Text(
'Show Invitations'.tr,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: CupertinoColors.white,
),
),
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: const TextStyle(
color: CupertinoColors.secondaryLabel,
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: CupertinoColors.systemGrey6,
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
invitation['passengerName']
.toString(), // Handle null or missing data
style: const TextStyle(
fontSize: 17,
fontWeight: FontWeight.w600,
color: CupertinoColors.label,
),
),
const SizedBox(height: 8),
ClipRRect(
borderRadius: BorderRadius.circular(4),
child: LinearProgressIndicator(
value: progressValue,
backgroundColor: CupertinoColors.systemGrey4,
valueColor:
const AlwaysStoppedAnimation<Color>(AppColor.blueColor),
minHeight: 6,
),
),
const SizedBox(height: 4),
Text(
'$countOfInvitDriver / 2 ${'Trip'.tr}', // Show trips completed
style: const TextStyle(
fontSize: 13,
color: CupertinoColors.secondaryLabel,
),
),
],
),
),
);
}
Widget _buildPassengerStats(BuildContext context) {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: CupertinoColors.systemGrey6,
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Your Rewards".tr,
style: const TextStyle(
fontSize: 17,
fontWeight: FontWeight.w600,
color: CupertinoColors.label,
),
),
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: const TextStyle(
color: CupertinoColors.label,
fontSize: 15,
),
),
Text(
value,
style: const TextStyle(
fontWeight: FontWeight.w600,
color: AppColor.blueColor,
fontSize: 15,
),
),
],
),
);
}
void _showContactsDialog(BuildContext context) {
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

@@ -1,14 +1,11 @@
import 'package:SEFER/views/widgets/my_scafold.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:share/share.dart';
import 'package:path/path.dart' as path;
import '../../../constant/colors.dart';
import '../../../constant/style.dart';
import '../../../controller/functions/audio_record1.dart';
import '../../../controller/functions/tts.dart';
import '../../widgets/elevated_btn.dart';
class TripsRecordedPage extends StatelessWidget {
const TripsRecordedPage({
@@ -21,132 +18,193 @@ class TripsRecordedPage extends StatelessWidget {
title: 'Trips recorded'.tr,
body: [
GetBuilder<AudioRecorderController>(builder: (audio) {
return Column(
children: [
FutureBuilder<List<String>>(
future: audio.getRecordedFiles(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
} else if (snapshot.hasData) {
final recordedFiles = snapshot.data!;
return DropdownButton<String>(
value: audio.selectedFilePath,
onChanged: (value) {
audio.selectedFilePath = value;
audio.playRecordedFile(value!);
audio.update();
},
items: recordedFiles
.map((file) => DropdownMenuItem<String>(
value: file,
child: Text(path.basename(file)),
))
.toList(),
);
} else {
return Text('Error: ${snapshot.error}');
}
},
),
Slider(
value: audio.currentPosition,
max: audio.totalDuration,
inactiveColor: AppColor.accentColor,
label: audio.currentPosition.toString(),
onChanged: (value) {
audio.currentPosition = value;
audio.audioPlayer.seek(Duration(seconds: value.toInt()));
},
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
icon: Icon(
audio.isPlaying ? Icons.pause : Icons.play_arrow),
onPressed: () {
if (audio.isPlaying) {
audio.pausePlayback();
} else {
audio.resumePlayback();
}
audio.update();
},
),
IconButton(
icon: const Icon(Icons.stop),
onPressed: () {
audio.stopPlayback();
audio.update();
},
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () async {
Get.defaultDialog(
title: 'Are you sure to delete recorded files'.tr,
content: Column(
children: [
IconButton(
onPressed: () {
Get.find<TextToSpeechController>().speakText(
'this will delete all files from your device'
.tr);
},
icon: const Icon(Icons.headphones),
),
Text(
'this will delete all files from your device'
.tr,
textAlign: TextAlign.center,
style: AppStyle.title,
),
],
),
titleStyle: AppStyle.title,
confirm: MyElevatedButton(
title: 'Delete'.tr,
kolor: AppColor.redColor,
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
FutureBuilder<List<String>>(
future: audio.getRecordedFiles(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CupertinoActivityIndicator());
} else if (snapshot.hasData) {
final recordedFiles = snapshot.data!;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: CupertinoButton(
padding: EdgeInsets.zero,
onPressed: () async {
await audio.deleteAllRecordedFiles();
Get.back();
Get.back();
String? selectedFile =
await showCupertinoModalPopup<String>(
context: context,
builder: (BuildContext context) {
return CupertinoActionSheet(
title: Text('Select a File'.tr),
actions: recordedFiles
.map(
(file) => CupertinoActionSheetAction(
child: Text(path.basename(file)),
onPressed: () {
Navigator.of(context).pop(file);
},
),
)
.toList(),
);
},
);
if (selectedFile != null) {
audio.selectedFilePath = selectedFile;
audio.playRecordedFile(selectedFile);
audio.update();
}
},
child: Text(
audio.selectedFilePath != null
? path.basename(audio.selectedFilePath!)
: 'Select a File'.tr,
style: CupertinoTheme.of(context)
.textTheme
.actionTextStyle
.copyWith(color: CupertinoColors.activeBlue),
),
),
);
} else {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Text('Error: ${snapshot.error}'),
);
}
},
),
// Cupertino-style slider for seeking audio
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: CupertinoSlider(
value: audio.totalDuration > 0
? audio.currentPosition / audio.totalDuration
: 0.0, // Normalize to a value between 0.0 and 1.0
min: 0.0,
max: 1.0, // Maximum value is now 1.0
activeColor: CupertinoColors.activeBlue,
onChanged: (value) {
final newPosition = value * audio.totalDuration;
audio.currentPosition = newPosition;
audio.audioPlayer
.seek(Duration(seconds: newPosition.toInt()));
audio.update();
},
),
],
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
padding: const EdgeInsets.all(16.0),
color: Colors.grey[200],
),
// iOS-style playback controls
Padding(
padding: const EdgeInsets.symmetric(
vertical: 16.0, horizontal: 16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
audio.selectedFilePath != null
? '${'Selected file:'.tr} ${path.basename(audio.selectedFilePath!)}'
: 'No file selected'.tr,
style: AppStyle.subtitle,
),
if (audio.selectedFilePath != null)
IconButton(
icon: const Icon(Icons.share),
onPressed: () {
Share.shareFiles([audio.selectedFilePath!]);
},
CupertinoButton(
padding: EdgeInsets.zero,
child: Icon(
audio.isPlaying
? CupertinoIcons.pause
: CupertinoIcons.play_arrow,
color: CupertinoColors.activeBlue,
),
onPressed: () {
if (audio.isPlaying) {
audio.pausePlayback();
} else {
audio.resumePlayback();
}
audio.update();
},
),
CupertinoButton(
padding: EdgeInsets.zero,
child: const Icon(CupertinoIcons.stop,
color: CupertinoColors.destructiveRed),
onPressed: () {
audio.stopPlayback();
audio.update();
},
),
CupertinoButton(
padding: EdgeInsets.zero,
child: const Icon(CupertinoIcons.delete,
color: CupertinoColors.destructiveRed),
onPressed: () async {
showCupertinoModalPopup(
context: context,
builder: (BuildContext context) {
return CupertinoActionSheet(
title: Text('Are you sure?'.tr),
message: Text(
'This will delete all recorded files from your device.'
.tr,
textAlign: TextAlign.center,
),
actions: [
CupertinoActionSheetAction(
isDestructiveAction: true,
onPressed: () async {
await audio.deleteAllRecordedFiles();
Navigator.pop(context);
audio.update();
},
child: Text('Delete'.tr),
),
],
cancelButton: CupertinoActionSheetAction(
onPressed: () {
Navigator.pop(context);
},
child: Text('Cancel'.tr),
),
);
},
);
},
),
],
),
),
),
],
// File selection and sharing
if (audio.selectedFilePath != null)
Align(
alignment: Alignment.bottomCenter,
child: Container(
padding: const EdgeInsets.all(16.0),
color: CupertinoColors.systemGrey6,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Selected file: ${path.basename(audio.selectedFilePath!)}',
style: CupertinoTheme.of(context)
.textTheme
.textStyle,
),
CupertinoButton(
padding: EdgeInsets.zero,
child: const Icon(CupertinoIcons.share),
onPressed: () {
Share.shareFiles([audio.selectedFilePath!]);
},
),
],
),
),
),
],
),
);
}),
})
],
isleading: true);
}

View File

@@ -8,6 +8,7 @@ import 'package:SEFER/views/widgets/my_scafold.dart';
import 'HomePage/about_page.dart';
import 'HomePage/frequentlyQuestionsPage.dart';
import 'HomePage/share_app_page.dart';
import 'HomePage/trip_record_page.dart';
import 'profile/passenger_profile_page.dart';
@@ -21,7 +22,7 @@ class HomePage extends StatelessWidget {
isleading: true,
title: 'Home Page'.tr,
body: [
Column(
ListView(
children: [
ListTile(
onTap: () {
@@ -116,6 +117,19 @@ class HomePage extends StatelessWidget {
),
onTap: () => Get.to(() => const AboutPage()),
),
ListTile(
leading: const Icon(Icons.share),
title: Text(
'Share App'.tr,
style: AppStyle.headTitle2,
),
subtitle: Text(
'You can share the SEFER App with your friends and earn rewards for rides they take using your code'
.tr,
style: AppStyle.title,
),
onTap: () => Get.to(() => ShareAppPage()),
),
],
),
],

View File

@@ -27,7 +27,7 @@ class ApplyOrderWidget extends StatelessWidget {
right: 0,
child: Container(
decoration: AppStyle.boxDecoration,
height: Get.height * .35,
height: Get.height * .36,
child: ListView(
children: [
InkWell(
@@ -87,11 +87,11 @@ class ApplyOrderWidget extends StatelessWidget {
width: 10,
),
Container(
height: Get.height * .3,
height: Get.height * .34,
width: Get.width * .9,
decoration: AppStyle.boxDecoration,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
@@ -241,12 +241,13 @@ class ApplyOrderWidget extends StatelessWidget {
InkWell(
onTap: () {
FirebaseMessagesController()
.sendNotificationToAnyWithoutData(
'message From passenger',
.sendNotificationToDriverMAP(
'message From passenger'.tr,
'Hello, I\'m at the agreed-upon location'
.tr,
controller.driverToken
.toString(),
[],
'ding.wav',
);
Get.back();
@@ -272,11 +273,12 @@ class ApplyOrderWidget extends StatelessWidget {
InkWell(
onTap: () {
FirebaseMessagesController()
.sendNotificationToAnyWithoutData(
.sendNotificationToDriverMAP(
'message From passenger'.tr,
'My location is correct. You can search for me using the navigation app'
.tr,
controller.driverToken,
[],
'ding.wav',
);
Get.back();
@@ -302,11 +304,12 @@ class ApplyOrderWidget extends StatelessWidget {
InkWell(
onTap: () {
FirebaseMessagesController()
.sendNotificationToAnyWithoutData(
.sendNotificationToDriverMAP(
'message From passenger',
'My location is correct. You can search for me using the navigation app'
.tr,
controller.driverToken,
[],
'ding.wav',
);
Get.back();
@@ -331,11 +334,12 @@ class ApplyOrderWidget extends StatelessWidget {
InkWell(
onTap: () {
FirebaseMessagesController()
.sendNotificationToAnyWithoutData(
.sendNotificationToDriverMAP(
'message From passenger',
"How much longer will you be?"
.tr,
controller.driverToken,
[],
'ding.wav',
);
Get.back();
@@ -385,13 +389,14 @@ class ApplyOrderWidget extends StatelessWidget {
IconButton(
onPressed: () {
FirebaseMessagesController()
.sendNotificationToAnyWithoutData(
.sendNotificationToDriverMAP(
'message From passenger',
controller
.messageToDriver
.text,
controller
.driverToken,
[],
'ding.wav');
controller
.messageToDriver
@@ -466,7 +471,7 @@ class DriverArrivePassengerAndWaitMinute extends StatelessWidget {
color: controller.remainingTimeDriverWaitPassenger5Minute < 60
? AppColor.redColor
: AppColor.greenColor,
minHeight: 25,
minHeight: 15,
borderRadius: BorderRadius.circular(15),
value:
controller.progressTimerDriverWaitPassenger5Minute.toDouble(),
@@ -513,7 +518,7 @@ class TimeDriverToPassenger extends StatelessWidget {
Container(
decoration: AppStyle.boxDecoration,
width: Get.width * .7,
height: 35,
height: 15,
// color: AppColor.yellowColor,
),
Stack(

View File

@@ -3,11 +3,11 @@ import 'package:get/get.dart';
import 'package:SEFER/constant/colors.dart';
import 'package:SEFER/constant/style.dart';
import 'package:SEFER/controller/home/map_passenger_controller.dart';
import '../../widgets/elevated_btn.dart';
GetBuilder<MapPassengerController> cancelRidePage() {
Get.put(MapPassengerController());
final List<String> reasons = [
"I don't need a ride anymore".tr,
"I was just trying the application".tr,
@@ -16,80 +16,74 @@ GetBuilder<MapPassengerController> cancelRidePage() {
"I don't have a reason".tr,
"Other".tr,
];
return GetBuilder<MapPassengerController>(
builder: (controller) => controller.isCancelRidePageShown
? Positioned(
left: Get.width * .1,
top: Get.width * .2,
right: Get.width * .1,
bottom: Get.width * .15,
left: 20,
top: Get.height * 0.15,
right: 20,
bottom: Get.height * 0.15,
child: Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: AppColor.secondaryColor,
color: Colors.white,
boxShadow: [
const BoxShadow(
color: AppColor.accentColor,
offset: Offset(2, 2),
blurRadius: 5),
BoxShadow(
color: AppColor.accentColor.withOpacity(.4),
offset: const Offset(-2, -2),
blurRadius: 5)
color: Colors.black.withOpacity(0.2),
offset: const Offset(0, 8),
blurRadius: 16,
),
],
borderRadius: const BorderRadius.all(Radius.circular(15)),
borderRadius: BorderRadius.circular(20),
),
height: Get.height * .7,
width: Get.width * .7,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Text(
'Can we know why you want to cancel Ride ?'.tr,
style: AppStyle.title,
textAlign: TextAlign.center,
),
Text(
'Can we know why you want to cancel Ride ?'.tr,
style: AppStyle.title
.copyWith(fontSize: 18, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
SizedBox(
height: 380,
width: 300,
child: ListView.builder(
const SizedBox(height: 20),
Expanded(
child: ListView.separated(
itemCount: reasons.length,
separatorBuilder: (context, index) => const Divider(),
itemBuilder: (context, index) {
return ListTile(
title: InkWell(
onTap: () {
controller.selectReason(
index,
reasons[index].toString(),
);
},
child: Text(
reasons[index],
style: AppStyle.title,
)),
title: Text(
reasons[index],
style: AppStyle.title.copyWith(fontSize: 16),
),
leading: Radio(
value: index,
groupValue: controller.selectedReason,
onChanged: (int? value) {
controller.selectReason(
value!,
reasons[index].toString(),
);
controller.selectReason(value!, reasons[index]);
},
activeColor: AppColor.primaryColor,
),
onTap: () {
controller.selectReason(index, reasons[index]);
},
);
},
),
),
const SizedBox(height: 20),
MyElevatedButton(
title: 'Cancel Ride'.tr,
onPressed: () {
if (controller.selectedReason == -1) {
Get.snackbar('You Should be select reason.'.tr, '',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: AppColor.redColor);
Get.snackbar(
'You Should be select reason.'.tr,
'',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: AppColor.redColor,
colorText: Colors.white,
);
} else {
controller.cancelRide();
}

View File

@@ -586,7 +586,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
textToSpeechController,
image: 'assets/images/freeRide.png',
text:
'Perfect for adventure seekers who want to experience something new and exciting'
"Perfect for passengers seeking the latest car models with the freedom to choose any route they desire"
.tr),
confirm: MyElevatedButton(
kolor: AppColor.greenColor,
@@ -656,8 +656,10 @@ class CarDetailsTypeToChoose extends StatelessWidget {
title: 'Next'.tr,
onPressed: () {
Get.back();
if (box.read(BoxName.gender) !=
null) {
if (box
.read(BoxName.gender)
.toString() !=
'') {
mapPassengerController
.isBottomSheetShown = false;
mapPassengerController.update();
@@ -710,59 +712,108 @@ class CarDetailsTypeToChoose extends StatelessWidget {
MainAxisAlignment
.spaceBetween,
children: [
Container(
decoration: AppStyle
.boxDecoration1,
child: Padding(
padding:
const EdgeInsets
.all(8.0),
child: Column(
children: [
Text('Awfar Car'
.tr),
Text(mapPassengerController
.totalPassengerRayehGaiBalash
.toStringAsFixed(
0)),
],
),
)),
Container(
decoration: AppStyle
.boxDecoration1,
child: Padding(
padding:
const EdgeInsets
.all(8.0),
child: Column(
children: [
Text('Speed'.tr),
Text(mapPassengerController
.totalPassengerRayehGai
.toStringAsFixed(
0)),
],
),
)),
Container(
decoration: AppStyle
.boxDecoration1,
child: Padding(
padding:
const EdgeInsets
.all(8.0),
child: Column(
children: [
Text(
'Comfort'.tr),
Text(mapPassengerController
.totalPassengerRayehGaiComfort
.toStringAsFixed(
0)),
],
),
))
GestureDetector(
onTap: () {
Get.back();
mapPassengerController
.totalPassenger =
mapPassengerController
.totalPassengerRayehGaiBalash;
mapPassengerController
.isBottomSheetShown =
false;
mapPassengerController
.update();
mapPassengerController
.changeCashConfirmPageShown();
},
child: Container(
decoration: AppStyle
.boxDecoration1,
child: Padding(
padding:
const EdgeInsets
.all(8.0),
child: Column(
children: [
Text('Awfar Car'
.tr),
Text(mapPassengerController
.totalPassengerRayehGaiBalash
.toStringAsFixed(
0)),
],
),
)),
),
GestureDetector(
onTap: () {
Get.back();
mapPassengerController
.totalPassenger =
mapPassengerController
.totalPassengerRayehGai;
mapPassengerController
.isBottomSheetShown =
false;
mapPassengerController
.update();
mapPassengerController
.changeCashConfirmPageShown();
},
child: Container(
decoration: AppStyle
.boxDecoration1,
child: Padding(
padding:
const EdgeInsets
.all(8.0),
child: Column(
children: [
Text(
'Speed'.tr),
Text(mapPassengerController
.totalPassengerRayehGai
.toStringAsFixed(
0)),
],
),
)),
),
GestureDetector(
onTap: () {
Get.back();
mapPassengerController
.totalPassenger =
mapPassengerController
.totalPassengerRayehGaiComfort;
mapPassengerController
.isBottomSheetShown =
false;
mapPassengerController
.update();
mapPassengerController
.changeCashConfirmPageShown();
},
child: Container(
decoration: AppStyle
.boxDecoration1,
child: Padding(
padding:
const EdgeInsets
.all(8.0),
child: Column(
children: [
Text('Comfort'
.tr),
Text(mapPassengerController
.totalPassengerRayehGaiComfort
.toStringAsFixed(
0)),
],
),
)),
)
],
),
cancel: MyElevatedButton(
@@ -951,9 +1002,16 @@ class BurcMoney extends StatelessWidget {
}
}
class HeaderDestination extends StatelessWidget {
class HeaderDestination extends StatefulWidget {
const HeaderDestination({super.key});
@override
_HeaderDestinationState createState() => _HeaderDestinationState();
}
class _HeaderDestinationState extends State<HeaderDestination> {
bool _isExpanded = false;
@override
Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(
@@ -965,95 +1023,64 @@ class HeaderDestination extends StatelessWidget {
top: Get.height * .08,
left: 5,
right: 5,
child: Container(
decoration: AppStyle.boxDecoration1,
height: Get.height * .15,
width: Get.width * .8,
child: InkWell(
onTap: () {
// mapPassengerController
// .getDialog('Are you want to change'.tr, '', () {
// Get.back();
// mapPassengerController.cancelRide();
// });
MyDialog().getDialog(
"Change Route".tr,
'You can change the destination by long-pressing any point on the map'
.tr, () {
Get.back();
});
},
child: GestureDetector(
onTap: () {
setState(() {
_isExpanded = !_isExpanded;
});
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
decoration: AppStyle.boxDecoration1,
height: _isExpanded ? Get.height * .13 : Get.height * .06,
width: Get.width * .9,
padding: const EdgeInsets.all(8),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 2),
child: SizedBox(
height: Get.height * .08,
child: ListView(
// crossAxisAlignment: CrossAxisAlignment.start,
//
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'🟢 ',
_isExpanded
? Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text('🟢 ', style: AppStyle.subtitle),
Expanded(
child: Text(
mapPassengerController.startNameAddress,
style: AppStyle.subtitle,
overflow: TextOverflow.ellipsis,
),
SizedBox(
// height: Get.height * .03,
width: Get.width * .8,
child: Text(
mapPassengerController.startNameAddress,
style: AppStyle.subtitle,
),
),
],
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'🔴 ',
style: AppStyle.subtitle,
),
SizedBox(
// height: Get.height * .03,
width: Get.width * .8,
child: Text(
mapPassengerController.endNameAddress,
style: AppStyle.subtitle,
),
),
],
),
],
),
],
)
: const SizedBox(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('🔴 ', style: AppStyle.subtitle),
Expanded(
child: Text(
mapPassengerController.endNameAddress,
style: AppStyle.subtitle,
overflow: TextOverflow.ellipsis,
),
),
),
],
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Row(
if (_isExpanded)
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'📍 ',
style: AppStyle.subtitle,
),
SizedBox(
width: Get.width * .8,
Text('📍', style: AppStyle.subtitle),
Expanded(
child: Text(
'${mapPassengerController.distance} ${'KM'.tr}${mapPassengerController.hours > 0 ? '${'Your Ride Duration is '.tr}${mapPassengerController.hours} ${'H and'.tr} ${mapPassengerController.minutes} ${'m'.tr}' : '${'Your Ride Duration is '.tr} ${mapPassengerController.minutes} ${'m'.tr}'}',
style: AppStyle.subtitle,
overflow: TextOverflow.ellipsis,
),
),
],
),
),
],
),
),

View File

@@ -29,7 +29,8 @@ class CashConfirmPageShown extends StatelessWidget {
? controller.cashConfirmPageShown
: 0,
decoration: BoxDecoration(
color: box.read(BoxName.carType) == 'Lady'
color: box.read(BoxName.carType) == 'Lady' ||
box.read(BoxName.carType) == 'Pink Bike'
? Colors.pink.shade100
: AppColor.secondaryColor,
borderRadius: BorderRadius.circular(15)),

View File

@@ -419,7 +419,7 @@ class GoogleMapPassengerWidget extends StatelessWidget {
},
mapType:
controller.mapType ? MapType.satellite : MapType.normal,
controller.mapType ? MapType.satellite : MapType.terrain,
myLocationButtonEnabled: true,
// liteModeEnabled: true, tiltGesturesEnabled: false,

View File

@@ -1,7 +1,13 @@
import 'dart:math';
import 'package:SEFER/views/auth/login_page.dart';
import 'package:SEFER/views/auth/sms_verfy_page.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import '../../../constant/colors.dart';
import '../../../constant/notification.dart';
import '../../../controller/firebase/local_notification.dart';
import '../../../controller/functions/tts.dart';
import '../../../controller/home/map_passenger_controller.dart';
@@ -89,17 +95,14 @@ GetBuilder<MapPassengerController> leftMainMenuIcons() {
// borderRadius: BorderRadius.circular(15)),
// child: IconButton(
// onPressed: () async {
// FirebaseMessagesController().sendNotificationToAnyWithoutData(
// 'Order'.tr,
// 'from: ',
// // jsonDecode(value)['message'].toString(),
// 'dEugS-JOT4Ka5riF4s5TEN:APA91bEDL_W7BuEQGbyL-RMaKiMWDlURXhFuaybe5WurTUV8K5eIooSGe22yY22_U2hEZcfPr46ig1v--l00dbOGiivazxvmTyhUyQQW6lJsuIN-wordGtBxtREyeYtEKvxIa1J4ApEu',
// 'order.wav'
// // polylineCoordinates.toString()
// );
// // print(box.read(BoxName.tokenFCM));
// //
// final random = Random();
// final randomMessage =
// messages[random.nextInt(messages.length)];
// NotificationController().showNotification(
// randomMessage.split(':')[0],
// randomMessage.split(':')[1],
// "ding",
// );
// },
// icon: const Icon(
// Icons.voice_chat,

View File

@@ -30,7 +30,7 @@ class RideBeginPassenger extends StatelessWidget {
return Positioned(
left: 10,
right: 10,
bottom: 4,
bottom: 10,
child: Container(
decoration: AppStyle.boxDecoration,
height: controller.statusRide == 'Begin' ? Get.height * .33 : 0,

View File

@@ -8,6 +8,121 @@ import 'package:SEFER/views/widgets/my_textField.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../constant/links.dart';
// class SearchingCaptainWindow extends StatelessWidget {
// const SearchingCaptainWindow({super.key});
// Widget _buildDriverAvatars(MapPassengerController controller) {
// // If no drivers yet, show loading indicator
// if (controller.isSearchingWindow) {
// // Check if dataCarsLocationByPassenger or its 'data' is null
// if (controller.dataCarsLocationByPassenger == null ||
// controller.dataCarsLocationByPassenger['data'] == null ||
// controller.dataCarsLocationByPassenger['data'].isEmpty) {
// return const SizedBox(
// height: 60,
// child: Center(
// child: CircularProgressIndicator(
// valueColor:
// AlwaysStoppedAnimation<Color>(AppColor.secondaryColor),
// ),
// ),
// );
// }
// }
// return SizedBox(
// height: 60,
// child: ListView.builder(
// scrollDirection: Axis.horizontal,
// itemCount: controller.dataCarsLocationByPassenger['data'].length,
// padding: const EdgeInsets.symmetric(horizontal: 16),
// itemBuilder: (context, index) {
// final driver = controller.dataCarsLocationByPassenger['data'][index];
// return Padding(
// padding: const EdgeInsets.only(right: 8),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// CircleAvatar(
// radius: 25,
// backgroundColor: AppColor.secondaryColor,
// child: ClipOval(
// child: Image.network(
// '${AppLink.server}/portrate_captain_image/${driver['driver_id']}.jpg',
// width: 50,
// height: 50,
// fit: BoxFit.cover,
// errorBuilder: (context, error, stackTrace) {
// return const Icon(
// Icons.person,
// color: Colors.white,
// size: 30,
// );
// },
// ),
// ),
// ),
// ],
// ),
// );
// },
// ),
// );
// }
// @override
// Widget build(BuildContext context) {
// return GetBuilder<MapPassengerController>(
// builder: (mapPassengerController) {
// return mapPassengerController.isSearchingWindow
// ? Positioned(
// bottom: 0,
// left: 0,
// right: 0,
// child: Container(
// decoration: AppStyle.boxDecoration1,
// height: Get.height *
// .3, // Increased height to accommodate avatars
// child: Column(
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
// children: [
// SizedBox(
// width: Get.width * .7,
// child: const LinearProgressIndicator(
// minHeight: 6,
// backgroundColor: AppColor.yellowColor,
// color: AppColor.secondaryColor,
// ),
// ),
// mapPassengerController.driverOrderStatus == 'recive'
// ? Text(
// "Drivers received orders".tr,
// style: AppStyle.title,
// )
// : Text(
// "We are searching for the nearest driver to you"
// .tr,
// style: AppStyle.title,
// ),
// Text(
// 'please wait till driver accept your order'.tr,
// style: AppStyle.title,
// ),
// // New: Driver avatars section
// _buildDriverAvatars(mapPassengerController),
// _buildTimer(mapPassengerController),
// ],
// ),
// ),
// )
// : const SizedBox();
// },
// );
// }
// }
class SearchingCaptainWindow extends StatelessWidget {
const SearchingCaptainWindow({super.key});

View File

@@ -116,9 +116,10 @@ class CupertinoDriverListWidget extends StatelessWidget {
width: 20,
height: 20,
decoration: BoxDecoration(
color: hexToColor(
driver['color_hex'].toString()) ??
Colors.amber,
color: driver['color_hex'].toString() == 'null'
? Colors.amber
: hexToColor(
driver['color_hex'].toString()),
borderRadius: BorderRadius.circular(4),
border: Border.all(),
),
@@ -151,9 +152,11 @@ class CupertinoDriverListWidget extends StatelessWidget {
width: 20,
height: 20,
decoration: BoxDecoration(
color: hexToColor(
driver['color_hex'].toString()) ??
AppColor.bronze,
color:
driver['color_hex'].toString() == 'null'
? Colors.amber
: hexToColor(
driver['color_hex'].toString()),
borderRadius: BorderRadius.circular(4),
border: Border.all(),
),
@@ -204,7 +207,9 @@ class CupertinoDriverListWidget extends StatelessWidget {
width: 20,
height: 20,
decoration: BoxDecoration(
color: hexToColor(driver['color_hex'].toString()),
color: driver['color_hex'].toString() == 'null'
? Colors.amber
: hexToColor(driver['color_hex'].toString()),
borderRadius: BorderRadius.circular(4),
border: Border.all(),
),

View File

@@ -1,64 +1,199 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:SEFER/views/widgets/my_scafold.dart';
import 'package:SEFER/views/widgets/mycircular.dart';
import 'dart:convert';
import '../../../controller/home/profile/complaint_controller.dart';
import '../../widgets/elevated_btn.dart';
import 'package:SEFER/constant/colors.dart';
import 'package:SEFER/constant/style.dart';
import 'package:SEFER/controller/functions/crud.dart';
import 'package:SEFER/controller/home/profile/complaint_controller.dart';
import 'package:SEFER/views/widgets/my_dialog.dart';
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
import 'dart:io';
import '../../../controller/functions/audio_record1.dart';
class ComplaintPage extends StatelessWidget {
// Rename class
ComplaintPage({super.key});
ComplaintController complaintController =
Get.put(ComplaintController()); // Update controller instance
final ComplaintController complaintController =
Get.put(ComplaintController());
final AudioRecorderController audioRecorderController =
Get.put(AudioRecorderController());
@override
Widget build(BuildContext context) {
return MyScafolld(
title: 'Complaint'.tr,
body: [
Padding(
padding: const EdgeInsets.all(26),
child: Form(
key: complaintController.formKey,
child: Column(
children: [
TextFormField(
controller: complaintController.complaintController,
decoration: InputDecoration(
border: const OutlineInputBorder(),
hintText: 'Enter your complaint here'.tr,
labelText: 'Complaint'.tr, // Update label
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your complaint.'.tr;
}
return null;
},
),
const SizedBox(height: 20),
complaintController.isLoading
? const MyCircularProgressIndicator()
: MyElevatedButton(
onPressed: () {
if (complaintController.formKey.currentState!
.validate()) {
complaintController
.addComplaint(); // Update method name
// Clear the complaint form
complaintController.formKey.currentState!.reset();
}
},
title: 'Submit'.tr,
),
],
),
),
return GetBuilder<ComplaintController>(builder: (complaintController) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('Complaint'.tr, style: AppStyle.title),
),
],
isleading: true,
);
child: complaintController.isLoading
? const Center(child: CupertinoActivityIndicator())
: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16),
child: Form(
key: complaintController.formKey,
child: ListView(
children: [
// Complaint Text Field
CupertinoFormSection(
header: Text('Submit Your Complaint'.tr),
children: [
CupertinoTextField(
controller:
complaintController.complaintController,
placeholder: 'Enter your complaint here'.tr,
padding: const EdgeInsets.symmetric(
vertical: 12, horizontal: 16),
maxLines: 5,
decoration: BoxDecoration(
border: Border.all(
color: CupertinoColors.systemGrey4),
borderRadius: BorderRadius.circular(10),
color: CupertinoColors.white,
),
style: AppStyle.subtitle,
),
],
),
const SizedBox(height: 24),
// FutureBuilder to load recorded audio files
FutureBuilder<List<String>>(
future: audioRecorderController.getRecordedFiles(),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return const Center(
child: CupertinoActivityIndicator());
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}',
style: AppStyle.subtitle);
} else if (snapshot.hasData &&
snapshot.data!.isEmpty) {
return Text('No audio files recorded.'.tr,
style: AppStyle.subtitle);
}
// List of recorded audio files
return CupertinoFormSection(
header: Text('attach audio of complain'.tr),
children: snapshot.data!.map((audioFilePath) {
final audioFile = File(audioFilePath);
return CupertinoListTile(
title: Text(audioFilePath.split('/').last,
style: AppStyle.title),
trailing: const Icon(
CupertinoIcons.play_arrow,
color: AppColor.accentColor),
onTap: () async {
MyDialogContent().getDialog(
'be sure'.tr,
Text('attach correct audio'.tr),
() async {
await complaintController
.uploadAudioFile(audioFile);
},
);
},
);
}).toList(),
);
},
),
const SizedBox(height: 24),
// Trip Details Section
CupertinoFormSection(
header: Text('Trip Details'.tr),
children: [
CupertinoListTile(
title: complaintController.feedBack.isEmpty
? Text('No Ride found yet'.tr)
: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'${'Date'.tr}: ${complaintController.feedBack[0]['date']}',
style: AppStyle.title),
Text(
'${'Price'.tr}: ${complaintController.feedBack[0]['price']}',
style: AppStyle.title),
],
),
),
],
),
const SizedBox(height: 24),
CupertinoFormSection(
header: Text('SEFER answer'.tr),
children: [
SizedBox(
height: 100,
child: ListView(
children: [
// Check if passengerReport is not null
if (complaintController.passengerReport !=
null)
// Access the 'solution' key safely
Text(
complaintController
.passengerReport!['solution']
?.toString() ??
'No solution available',
style: AppStyle.title,
)
else
const SizedBox(), // Fallback if passengerReport is null
],
),
),
],
),
const SizedBox(height: 24),
// Submit Button
CupertinoButton(
color: AppColor.blueColor,
padding: const EdgeInsets.symmetric(
vertical: 14, horizontal: 30),
onPressed: () async {
if (complaintController.formKey.currentState!
.validate()) {
if (complaintController.audioLink.toString() ==
'') {
MyDialogContent().getDialog(
'title',
Text(
'the audio file not uploaded yet \nDo you want to upload without audio file'
.tr), () async {
await complaintController.geminiAudio(
jsonEncode(complaintController.feedBack),
complaintController.audioLink,
complaintController
.complaintController.text);
complaintController.formKey.currentState!
.reset();
});
Get.back();
} else {
await complaintController.geminiAudio(
jsonEncode(complaintController.feedBack),
complaintController.audioLink,
complaintController
.complaintController.text);
complaintController.formKey.currentState!
.reset();
}
complaintController.addComplaint();
}
},
child: Text('Submit'.tr, style: AppStyle.title),
),
],
),
),
),
),
);
});
}
}