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);
}