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,144 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../controller/rate/rate_app_controller.dart';
class RatingScreen extends StatelessWidget {
final RatingController ratingController = Get.put(RatingController());
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text(
"Rate Our App".tr,
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
child: SafeArea(
child: SingleChildScrollView(
child: Center(
child: Obx(() {
return Padding(
padding:
const EdgeInsets.symmetric(horizontal: 20, vertical: 30),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// App logo or visual
ClipRRect(
borderRadius: BorderRadius.circular(16),
child: Image.asset(
'assets/images/logo.gif',
height: 120,
),
),
const SizedBox(height: 20),
// Rating Prompt
Text(
"How would you rate our app?".tr,
textAlign: TextAlign.center,
style: CupertinoTheme.of(context)
.textTheme
.navTitleTextStyle
.copyWith(fontSize: 18, fontWeight: FontWeight.w600),
),
const SizedBox(height: 20),
// Comment Box
CupertinoTextField(
controller: ratingController.comment,
placeholder: 'Write your comment here'.tr,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(color: CupertinoColors.systemGrey4),
borderRadius: BorderRadius.circular(12),
color: CupertinoColors.white,
),
prefix: Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Icon(CupertinoIcons.pencil_ellipsis_rectangle,
color: CupertinoColors.systemGrey),
),
),
const SizedBox(height: 20),
// Star Rating Section
_buildRatingStars(),
const SizedBox(height: 30),
// Submit Button
CupertinoButton(
padding: const EdgeInsets.symmetric(
horizontal: 24, vertical: 14),
borderRadius: BorderRadius.circular(12),
color: CupertinoColors.activeGreen,
onPressed: () {
if (ratingController.userRating.value > 0) {
ratingController
.submitRating(ratingController.userRating.value);
Get.snackbar(
"Thank You!".tr,
"Your rating has been submitted.".tr,
backgroundColor: CupertinoColors.systemGrey6,
snackPosition: SnackPosition.BOTTOM,
margin: const EdgeInsets.all(16),
borderRadius: 12,
);
} else {
Get.snackbar(
"Error".tr,
"Please select a rating before submitting.".tr,
backgroundColor: CupertinoColors.systemRed,
snackPosition: SnackPosition.BOTTOM,
margin: const EdgeInsets.all(16),
borderRadius: 12,
);
}
},
child: Text(
"Submit Rating".tr,
style: const TextStyle(
color: CupertinoColors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
],
),
);
}),
),
),
),
);
}
// Widget for building rating stars with animations
Widget _buildRatingStars() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(5, (index) {
return GestureDetector(
onTap: () {
ratingController.userRating.value = index + 1;
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.symmetric(horizontal: 4),
child: Icon(
CupertinoIcons.star_fill,
size: 40,
color: index < ratingController.userRating.value
? CupertinoColors.systemYellow
: CupertinoColors.systemGrey3,
),
),
);
}),
);
}
}

View File

@@ -0,0 +1,331 @@
import 'package:siro_driver/controller/home/captin/map_driver_controller.dart';
import 'package:siro_driver/views/widgets/my_textField.dart';
import 'package:flutter/material.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart'; // Import this for formatting
import 'package:siro_driver/constant/colors.dart';
import 'package:siro_driver/views/widgets/elevated_btn.dart';
import '../../constant/style.dart';
import '../../controller/rate/rate_conroller.dart';
class RatePassenger extends StatelessWidget {
final RateController controller = Get.put(RateController());
// Format: 1,234.5
final NumberFormat currencyFormatter = NumberFormat("#,##0.0", "en_US");
RatePassenger({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: AppBar(
title: Text('Trip Completed'.tr),
centerTitle: true,
automaticallyImplyLeading: false,
elevation: 0,
),
body: GetBuilder<RateController>(
builder: (controller) {
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// 1. The HERO Section: Big Price Display
_buildHeroPriceDisplay(context),
const SizedBox(height: 24),
// 2. Wallet Section (Conditional)
if (controller.walletChecked != 'true')
_buildWalletSection(context, controller),
const SizedBox(height: 24),
// 3. Rating Section
_buildRatingSection(context, controller),
const SizedBox(height: 30),
// 4. Submit Button
SizedBox(
height: 55,
child: MyElevatedButton(
title: 'Finish & Submit'.tr,
onPressed: () => controller.addRateToPassenger(),
// isFullWidth: true,
),
),
],
),
),
);
},
),
);
}
// --- WIDGETS ---
Widget _buildHeroPriceDisplay(BuildContext context) {
final MapDriverController mapController = Get.find<MapDriverController>();
// Parse the string to double to format it correctly
double amount =
double.tryParse(mapController.paymentAmount.toString()) ?? 0.0;
String formattedAmount = currencyFormatter.format(amount);
return Container(
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
decoration: BoxDecoration(
color: AppColor.primaryColor, // Use your brand color or a dark color
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: AppColor.primaryColor.withOpacity(0.3),
blurRadius: 15,
offset: const Offset(0, 10),
),
],
),
child: Column(
children: [
Text(
'Collect Cash'.tr.toUpperCase(),
style: const TextStyle(
color: Colors.white70,
fontSize: 16,
fontWeight: FontWeight.w600,
letterSpacing: 1.2,
),
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Currency Symbol (Small)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
'SYP'.tr, // Replace with your local currency symbol if needed
style: TextStyle(
color: Colors.white.withOpacity(0.8),
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(width: 4),
// The Price (Huge)
Text(
formattedAmount,
style: const TextStyle(
color: Colors.white,
fontSize: 56, // Very Large Font
fontWeight: FontWeight.w900,
height: 1.0,
),
),
],
),
const SizedBox(height: 10),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(20),
),
child: Text(
'Passenger: ${mapController.passengerName}',
style: const TextStyle(color: Colors.white, fontSize: 14),
),
),
],
),
);
}
Widget _buildWalletSection(BuildContext context, RateController controller) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).cardColor,
borderRadius: BorderRadius.circular(16),
border: Border.all(color: Theme.of(context).dividerColor),
),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: controller.ispassengerWantWalletFromDriver
? _buildAmountInput(context, controller)
: _buildWalletQuery(context, controller),
),
),
);
}
Widget _buildWalletQuery(BuildContext context, RateController controller) {
return Column(
key: const ValueKey('walletQuery'),
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.amber.withOpacity(0.1),
shape: BoxShape.circle,
),
child:
const Icon(Icons.account_balance_wallet, color: Colors.amber),
),
const SizedBox(width: 15),
Expanded(
child: Text(
"Pay remaining to Wallet?".tr,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
],
),
const SizedBox(height: 20),
Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () {}, // Optional logic
style: OutlinedButton.styleFrom(
foregroundColor: Theme.of(context).hintColor,
side: BorderSide(color: Theme.of(context).dividerColor),
padding: const EdgeInsets.symmetric(vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
),
child: Text('No'.tr),
),
),
const SizedBox(width: 12),
Expanded(
child: ElevatedButton(
onPressed: () => controller.passengerWantPay(),
style: ElevatedButton.styleFrom(
backgroundColor: AppColor.primaryColor,
padding: const EdgeInsets.symmetric(vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
),
child: Text('Yes, Pay'.tr,
style: const TextStyle(color: Colors.white)),
),
),
],
)
],
);
}
Widget _buildAmountInput(BuildContext context, RateController controller) {
return Column(
key: const ValueKey('amountInput'),
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Enter Amount Paid".tr,
style: Theme.of(context)
.textTheme
.titleMedium
?.copyWith(fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
Form(
key: controller.formKey,
child: MyTextForm(
controller: controller.passengerPayAmount,
label: "Amount".tr,
hint: "0.00",
type: const TextInputType.numberWithOptions(decimal: true),
// Suggestion: Add a suffix icon for currency if available in your widget
),
),
const SizedBox(height: 12),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () => controller.addPassengerWallet(),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
),
child: Text("Confirm Payment".tr,
style: const TextStyle(color: Colors.white)),
),
)
],
);
}
Widget _buildRatingSection(BuildContext context, RateController controller) {
return Column(
children: [
Text(
'Rate Passenger'.tr,
style: TextStyle(
color: Theme.of(context).hintColor,
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 12),
RatingBar.builder(
initialRating: 0,
minRating: 1,
direction: Axis.horizontal,
allowHalfRating: false,
itemCount: 5,
itemSize: 45, // Large stars
itemPadding: const EdgeInsets.symmetric(horizontal: 2.0),
itemBuilder: (context, _) => const Icon(
Icons.star_rounded,
color: Colors.amber,
),
onRatingUpdate: (rating) {
controller.selectRateItem(rating);
},
),
const SizedBox(height: 20),
// Simplified comment box
TextField(
controller: controller.comment,
maxLines: 2,
style: Theme.of(context).textTheme.bodyLarge,
decoration: InputDecoration(
hintText: 'Any comments about the passenger?'.tr,
filled: true,
fillColor: Theme.of(context).cardColor,
contentPadding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: Theme.of(context).dividerColor),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: Theme.of(context).dividerColor),
),
),
),
],
);
}
}

View File

@@ -0,0 +1,448 @@
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:siro_driver/constant/colors.dart';
import 'package:siro_driver/constant/info.dart';
import 'package:siro_driver/constant/style.dart';
import 'package:siro_driver/views/widgets/my_scafold.dart';
import 'package:siro_driver/views/widgets/mycircular.dart';
import 'package:intl/intl.dart';
import '../../controller/home/captin/duration_controller .dart';
class RideCalculateDriver extends StatelessWidget {
RideCalculateDriver({super.key});
// DurationController durationController = Get.put(DurationController());
@override
Widget build(BuildContext context) {
Get.put(DurationController());
return MyScafolld(
title: 'Ride Summaries'.tr,
body: [
GetBuilder<DurationController>(
builder: (durationController) {
if (durationController.isLoading) {
return const Center(child: MyCircularProgressIndicator());
}
bool hasDurations = durationController.jsonData1.isNotEmpty &&
durationController.jsonData1['message'] != null &&
(durationController.jsonData1['message'] as List).isNotEmpty;
bool hasRides = durationController.jsonData2.isNotEmpty &&
durationController.jsonData2['message'] != null &&
(durationController.jsonData2['message'] as List).isNotEmpty;
bool hasStats = durationController.monthlyList.isNotEmpty;
if (!hasDurations && !hasRides && !hasStats) {
return Center(
child: Text('No data yet!'.tr),
);
}
return ListView(
children: [
if (hasDurations) ...[
Text(
'${'Average of Hours of'.tr} ${AppInformation.appName}${' is ON for this month'.tr}${' ${durationController.jsonData1['message'][0]['day'].toString().split('-')[1]}'.tr}',
style: AppStyle.title,
textAlign: TextAlign.center,
),
Padding(
padding: const EdgeInsets.all(6),
child: Container(
decoration: AppStyle.boxDecoration1,
height: Get.height * .4,
child: LineChart(
duration: const Duration(milliseconds: 150),
curve: Curves.ease,
LineChartData(
lineBarsData: [
LineChartBarData(
isStepLineChart: true,
spots: durationController.chartData,
isCurved: true,
color: Colors.deepPurpleAccent,
barWidth: 3,
dotData: const FlDotData(show: true),
belowBarData: BarAreaData(
show: true,
color: AppColor.deepPurpleAccent,
),
isStrokeJoinRound: true,
shadow: const BoxShadow(
color: AppColor.yellowColor,
blurRadius: 4,
offset: Offset(2, 2),
),
),
],
showingTooltipIndicators: const [],
titlesData: FlTitlesData(
show: true,
topTitles: AxisTitles(
axisNameWidget:
Text('Days'.tr, style: AppStyle.title),
axisNameSize: 30,
),
bottomTitles: AxisTitles(
axisNameWidget: Text(
'Total Hours on month'.tr,
style: AppStyle.title),
axisNameSize: 30,
sideTitles: const SideTitles(
reservedSize: 30, showTitles: true)),
leftTitles: AxisTitles(
axisNameWidget: Text(
'Counts of Hours on days'.tr,
style: AppStyle.title),
axisNameSize: 30,
sideTitles: const SideTitles(
reservedSize: 30, showTitles: true)),
),
gridData: const FlGridData(show: true),
borderData: FlBorderData(
show: true,
border: const Border(
bottom: BorderSide(color: AppColor.accentColor),
left: BorderSide(color: AppColor.accentColor),
),
),
),
),
),
),
],
if (hasRides) ...[
const SizedBox(height: 5),
Padding(
padding: const EdgeInsets.all(6),
child: Container(
decoration: AppStyle.boxDecoration1,
height: Get.height * .4,
child: LineChart(
duration: const Duration(milliseconds: 150),
curve: Curves.ease,
LineChartData(
lineBarsData: [
LineChartBarData(
spots: durationController.chartRideCount,
color: Colors.deepPurpleAccent,
barWidth: 3,
dotData: const FlDotData(show: true),
belowBarData: BarAreaData(
show: true,
color: AppColor.deepPurpleAccent,
),
isStrokeJoinRound: true,
shadow: const BoxShadow(
color: AppColor.yellowColor,
blurRadius: 4,
offset: Offset(2, 2),
),
),
],
showingTooltipIndicators: const [],
titlesData: FlTitlesData(
show: true,
topTitles: AxisTitles(
axisNameWidget:
Text('Days'.tr, style: AppStyle.title),
axisNameSize: 30,
),
bottomTitles: AxisTitles(
axisNameWidget: Text(
'${"Total rides on month".tr} = ${durationController.jsonData2['message'][0]['totalCount'] ?? 0}'
.tr,
style: AppStyle.title,
),
axisNameSize: 30,
sideTitles: const SideTitles(
reservedSize: 30, showTitles: true)),
leftTitles: AxisTitles(
axisNameWidget: Text(
'Counts of rides on days'.tr,
style: AppStyle.title),
axisNameSize: 30,
sideTitles: const SideTitles(
reservedSize: 30, showTitles: true)),
),
gridData: const FlGridData(show: true),
borderData: FlBorderData(
show: true,
border: const Border(
bottom: BorderSide(color: AppColor.accentColor),
left: BorderSide(color: AppColor.accentColor),
),
),
),
),
),
),
const SizedBox(height: 5),
Padding(
padding: const EdgeInsets.all(6),
child: Container(
decoration: AppStyle.boxDecoration1,
height: Get.height * .4,
child: LineChart(
duration: const Duration(milliseconds: 150),
curve: Curves.ease,
LineChartData(
lineBarsData: [
LineChartBarData(
isStepLineChart: true,
spots: durationController.chartRidePriceDriver,
isCurved: true,
isStrokeCapRound: true,
preventCurveOverShooting: true,
color: Colors.deepPurpleAccent,
barWidth: 3,
dotData: const FlDotData(show: true),
belowBarData: BarAreaData(
show: true,
color: AppColor.deepPurpleAccent,
),
isStrokeJoinRound: true,
shadow: const BoxShadow(
color: AppColor.yellowColor,
blurRadius: 4,
offset: Offset(2, 2),
),
),
],
showingTooltipIndicators: const [],
titlesData: FlTitlesData(
show: true,
topTitles: AxisTitles(
axisNameWidget:
Text('Days'.tr, style: AppStyle.title),
axisNameSize: 30,
),
bottomTitles: AxisTitles(
axisNameWidget: Text(
'${"Total budgets on month".tr} = ${durationController.jsonData2['message'][0]['totalPrice'] ?? 0}'
.tr,
style: AppStyle.title,
),
axisNameSize: 30,
sideTitles: const SideTitles(
reservedSize: 30, showTitles: true)),
leftTitles: AxisTitles(
axisNameWidget: Text(
'Counts of budgets on days'.tr,
style: AppStyle.title),
axisNameSize: 30,
sideTitles: const SideTitles(
reservedSize: 30, showTitles: true)),
),
gridData: const FlGridData(show: true),
borderData: FlBorderData(
show: true,
border: const Border(
bottom: BorderSide(color: AppColor.accentColor),
left: BorderSide(color: AppColor.accentColor),
),
),
),
),
),
),
],
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: AppStyle.boxDecoration1,
child: !hasStats
? SizedBox(
height: Get.height * .2,
child: Center(
child: Text(
"No statistics yet".tr,
style: AppStyle.title,
),
),
)
: DriverStatsTable(
monthlyList: durationController.monthlyList,
)))
],
);
},
)
// BarChartWidget(),
],
isleading: true);
}
}
class DriverStatsTable extends StatelessWidget {
final List monthlyList;
const DriverStatsTable({Key? key, required this.monthlyList})
: super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 2,
blurRadius: 5,
offset: const Offset(0, 3),
),
],
),
padding: const EdgeInsets.all(16),
child: DataTable(
columnSpacing: 12,
columns: [
DataColumn(label: Text('Statistic'.tr)),
DataColumn(label: Text('Value'.tr)),
],
rows: _buildRows(),
),
);
}
List<DataRow> _buildRows() {
return [
DataRow(cells: [
DataCell(Text(
'Total Orders'.tr,
style: AppStyle.title,
)),
DataCell(Text(
monthlyList[0]['total_orders'].toString(),
style: AppStyle.number,
)),
]),
DataRow(cells: [
DataCell(Text(
'Completed'.tr,
style: AppStyle.title,
)),
DataCell(Text(
monthlyList[0]['completed_orders'].toString(),
style: AppStyle.number,
)),
]),
DataRow(cells: [
DataCell(Text(
'Canceled Orders'.tr,
style: AppStyle.title,
)),
DataCell(Text(
monthlyList[0]['canceled_orders'].toString(),
style: AppStyle.number,
)),
]),
DataRow(cells: [
DataCell(Text(
'Rejected Orders'.tr,
style: AppStyle.title,
)),
DataCell(Text(
monthlyList[0]['rejected_orders'].toString(),
style: AppStyle.number,
)),
]),
DataRow(cells: [
DataCell(Text(
'Percent Rejected'.tr,
style: AppStyle.title,
)),
DataCell(Text(
'${(monthlyList[0]['percent_rejected']).toString()}%',
style: AppStyle.number.copyWith(
color: double.parse(monthlyList[0]['percent_canceled']) < .3
? AppColor.greenColor
: AppColor.redColor),
)),
]),
DataRow(cells: [
DataCell(Text(
'Percent Canceled'.tr,
style: AppStyle.title,
)),
DataCell(Text(
'${(monthlyList[0]['percent_canceled']).toString()}%',
style: AppStyle.number.copyWith(
color: double.parse(monthlyList[0]['percent_canceled']) < .3
? AppColor.greenColor
: AppColor.redColor),
)),
]),
DataRow(cells: [
DataCell(Text(
'Percent Completed'.tr,
style: AppStyle.title,
)),
DataCell(Text(
'${(monthlyList[0]['percent_completed']).toString()}%',
style: AppStyle.number.copyWith(
color: double.parse(monthlyList[0]['percent_completed']) > .7
? AppColor.greenColor
: AppColor.redColor),
)),
]),
];
}
}
class StaticDriverOrder extends StatelessWidget {
const StaticDriverOrder({
Key? key,
required this.title,
required this.jsonTitle,
}) : super(key: key);
final String title, jsonTitle;
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(8.0),
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
spreadRadius: 3,
blurRadius: 5,
offset: const Offset(0, 3), // changes position of shadow
),
],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.black54,
),
),
const SizedBox(height: 8.0),
Text(
jsonTitle,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
],
),
);
}
}