fix marker rendering & modernize riding widgets for dark mode - 2026-04-11

This commit is contained in:
Hamza-Ayed
2026-04-11 01:14:09 +03:00
parent 3f03f25142
commit 454276d1e0
88 changed files with 50376 additions and 23310 deletions

View File

@@ -173,8 +173,8 @@ class RateDriverFromPassenger extends StatelessWidget {
decoration: InputDecoration(
labelText: 'Enter your Note'.tr,
hintText: 'Type something...'.tr,
prefixIcon: const Icon(
Icons.rate_review), // Add an icon as a prefix
prefixIcon: Icon(
Icons.rate_review, color: AppColor.grayColor), // Add an icon as a prefix
suffixIcon: IconButton(
icon: const Icon(
Icons.clear,
@@ -186,20 +186,20 @@ class RateDriverFromPassenger extends StatelessWidget {
),
border:
const OutlineInputBorder(), // Add a border around the input field
enabledBorder: const OutlineInputBorder(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
Colors.blue), // Customize the border color
AppColor.grayColor.withOpacity(0.5)), // Customize the border color
),
focusedBorder: const OutlineInputBorder(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors
.green), // Customize the border color when focused
color: AppColor
.greenColor), // Customize the border color when focused
),
errorBorder: const OutlineInputBorder(
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors
.red), // Customize the border color when there's an error
color: AppColor
.redColor), // Customize the border color when there's an error
),
),
),

View File

@@ -39,10 +39,10 @@ class RatingDriverBottomSheet extends StatelessWidget {
radius: 30,
backgroundImage: NetworkImage(
'${AppLink.server}/portrate_captain_image/${controller.driverId}.jpg'),
onBackgroundImageError: (exception, stackTrace) => const Icon(
onBackgroundImageError: (exception, stackTrace) => Icon(
Icons.person,
size: 30,
color: AppColor.blueColor),
color: AppColor.cyanBlue),
),
const SizedBox(height: 16),
@@ -60,7 +60,7 @@ class RatingDriverBottomSheet extends StatelessWidget {
'Your valuable feedback helps us improve our service quality.'
.tr,
style: AppStyle.title
.copyWith(color: Colors.grey.shade600, fontSize: 14),
.copyWith(color: AppColor.grayColor, fontSize: 14),
textAlign: TextAlign.center,
),
@@ -119,9 +119,9 @@ class RatingDriverBottomSheet extends StatelessWidget {
hintText:
'Share your experience to help us improve...'.tr,
prefixIcon:
const Icon(Icons.rate_review, color: Colors.blueGrey),
Icon(Icons.rate_review, color: AppColor.grayColor),
suffixIcon: IconButton(
icon: const Icon(Icons.clear, color: AppColor.redColor),
icon: Icon(Icons.clear, color: AppColor.redColor),
onPressed: () {
controller.comment.clear();
},
@@ -131,8 +131,8 @@ class RatingDriverBottomSheet extends StatelessWidget {
borderRadius: BorderRadius.circular(12)),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide:
const BorderSide(color: Colors.blueGrey, width: 1),
borderSide:
BorderSide(color: AppColor.grayColor.withOpacity(0.5), width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),

View File

@@ -54,8 +54,7 @@ class LoginPage extends StatelessWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.policy_outlined,
size: 80, color: AppColor.primaryColor),
Icon(Icons.policy_outlined, size: 80, color: AppColor.primaryColor),
const SizedBox(height: 20),
Text("passenger agreement".tr,
textAlign: TextAlign.center, style: AppStyle.headTitle2),
@@ -71,9 +70,9 @@ class LoginPage extends StatelessWidget {
.tr),
TextSpan(
text: 'Terms of Use'.tr,
style: const TextStyle(
style: TextStyle(
decoration: TextDecoration.underline,
color: AppColor.blueColor,
color: AppColor.cyanBlue,
fontWeight: FontWeight.bold),
recognizer: TapGestureRecognizer()
..onTap = () {
@@ -193,7 +192,7 @@ class LoginPage extends StatelessWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.location_on, size: 60, color: AppColor.primaryColor),
Icon(Icons.location_on, size: 60, color: AppColor.primaryColor),
const SizedBox(height: 20),
Text(
'Enable Location Access'.tr,

View File

@@ -23,8 +23,8 @@ class RegisterPage extends StatelessWidget {
padding: const EdgeInsets.all(16.0),
child: SingleChildScrollView(
child: Container(
decoration: const BoxDecoration(
boxShadow: [
decoration: BoxDecoration(
boxShadow: const [
BoxShadow(
offset: Offset(3, 3),
color: AppColor.accentColor,

View File

@@ -58,7 +58,7 @@ class SmsSignupEgypt extends StatelessWidget {
registerController.phoneController.text =
phone.completeNumber.toString();
Log.print(' phone.number: ${phone.number}');
print(
Log.print(
"Formatted phone number: ${registerController.phoneController.text}");
},
validator: (phone) {

View File

@@ -36,7 +36,7 @@ class ContactUsPage extends StatelessWidget {
child: Image.asset('assets/images/logo.gif')),
IconButton(
onPressed: () async {
Get.put(TextToSpeechController()).speakText(
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. 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);
},

View File

@@ -3,6 +3,7 @@ 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';
@@ -12,16 +13,16 @@ class ShareAppPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: CupertinoColors.systemBackground,
backgroundColor: AppColor.secondaryColor,
appBar: AppBar(
backgroundColor: CupertinoColors.systemBackground,
backgroundColor: AppColor.secondaryColor,
elevation: 0,
title: Text(
'Invite'.tr,
style: const TextStyle(color: CupertinoColors.label),
style: AppStyle.headTitle2.copyWith(fontSize: 20),
),
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios, color: AppColor.blueColor),
icon: Icon(Icons.arrow_back_ios, color: AppColor.cyanBlue),
onPressed: () => Get.back(),
),
),
@@ -51,7 +52,7 @@ class ShareAppPage extends StatelessWidget {
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: CupertinoColors.systemGrey6,
color: AppColor.grayColor.withOpacity(0.08),
borderRadius: BorderRadius.circular(12),
),
child: Column(
@@ -60,8 +61,8 @@ class ShareAppPage extends StatelessWidget {
"Share this code with your friends and earn rewards when they use it!"
.tr,
textAlign: TextAlign.center,
style: const TextStyle(
color: CupertinoColors.secondaryLabel,
style: TextStyle(
color: AppColor.grayColor,
fontSize: 13,
),
),
@@ -116,8 +117,9 @@ class ShareAppPage extends StatelessWidget {
Widget _buildPhoneInput() {
return Container(
decoration: BoxDecoration(
color: CupertinoColors.systemGrey6,
borderRadius: BorderRadius.circular(8),
color: AppColor.grayColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColor.grayColor.withOpacity(0.1)),
),
child: Row(
children: [
@@ -125,13 +127,16 @@ class ShareAppPage extends StatelessWidget {
child: CupertinoTextField.borderless(
controller: controller.invitePhoneController,
placeholder: 'Enter phone'.tr,
padding: const EdgeInsets.all(12),
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: const Icon(CupertinoIcons.person_badge_plus,
color: AppColor.blueColor),
child: Icon(CupertinoIcons.person_badge_plus,
color: AppColor.cyanBlue),
onPressed: () async {
await controller.pickContacts();
Log.print('contacts: ${controller.contacts}');
@@ -169,16 +174,16 @@ class ShareAppPage extends StatelessWidget {
],
),
child: CupertinoButton(
color: AppColor.blueColor,
color: AppColor.primaryColor,
borderRadius: BorderRadius.circular(10),
padding: const EdgeInsets.symmetric(vertical: 14),
onPressed: controller.sendInviteToPassenger,
child: Text(
'Send Invite'.tr,
style: const TextStyle(
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: CupertinoColors.white,
color: AppColor.secondaryColor,
),
),
),
@@ -198,15 +203,15 @@ class ShareAppPage extends StatelessWidget {
],
),
child: CupertinoButton(
color: AppColor.blueColor,
color: AppColor.cyanBlue,
borderRadius: BorderRadius.circular(10),
padding: const EdgeInsets.symmetric(vertical: 14),
child: Text(
'Show Invitations'.tr,
style: const TextStyle(
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: CupertinoColors.white,
color: AppColor.secondaryColor,
),
),
onPressed: () async {
@@ -227,8 +232,8 @@ class ShareAppPage extends StatelessWidget {
? Center(
child: Text(
"No invitation found yet!".tr,
style: const TextStyle(
color: CupertinoColors.secondaryLabel,
style: TextStyle(
color: AppColor.grayColor,
fontSize: 17,
),
),
@@ -258,8 +263,9 @@ class ShareAppPage extends StatelessWidget {
margin: const EdgeInsets.symmetric(vertical: 8.0),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: CupertinoColors.systemGrey6,
color: AppColor.grayColor.withOpacity(0.08),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColor.grayColor.withOpacity(0.05)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -267,10 +273,10 @@ class ShareAppPage extends StatelessWidget {
Text(
invitation['passengerName']
.toString(), // Handle null or missing data
style: const TextStyle(
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.w600,
color: CupertinoColors.label,
color: AppColor.writeColor,
),
),
const SizedBox(height: 8),
@@ -278,18 +284,18 @@ class ShareAppPage extends StatelessWidget {
borderRadius: BorderRadius.circular(4),
child: LinearProgressIndicator(
value: progressValue,
backgroundColor: CupertinoColors.systemGrey4,
backgroundColor: AppColor.grayColor.withOpacity(0.1),
valueColor:
const AlwaysStoppedAnimation<Color>(AppColor.blueColor),
AlwaysStoppedAnimation<Color>(AppColor.primaryColor),
minHeight: 6,
),
),
const SizedBox(height: 4),
Text(
'$countOfInvitDriver / 2 ${'Trip'.tr}', // Show trips completed
style: const TextStyle(
style: TextStyle(
fontSize: 13,
color: CupertinoColors.secondaryLabel,
color: AppColor.grayColor,
),
),
],
@@ -302,18 +308,19 @@ class ShareAppPage extends StatelessWidget {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: CupertinoColors.systemGrey6,
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: const TextStyle(
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.w600,
color: CupertinoColors.label,
color: AppColor.writeColor,
),
),
const SizedBox(height: 16),
@@ -342,8 +349,8 @@ class ShareAppPage extends StatelessWidget {
children: [
Text(
label,
style: const TextStyle(
color: CupertinoColors.label,
style: TextStyle(
color: AppColor.writeColor,
fontSize: 15,
),
),
@@ -362,7 +369,9 @@ class ShareAppPage extends StatelessWidget {
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,
@@ -409,10 +418,10 @@ class ShareAppPage extends StatelessWidget {
padding: const EdgeInsets.symmetric(
horizontal: 16, vertical: 12),
decoration: BoxDecoration(
color: CupertinoColors.systemBackground,
color: AppColor.secondaryColor,
border: Border(
bottom: BorderSide(
color: CupertinoColors.separator.withOpacity(0.5),
color: AppColor.grayColor.withOpacity(0.1),
),
),
),
@@ -425,16 +434,16 @@ class ShareAppPage extends StatelessWidget {
children: [
Text(
contact['name'],
style: const TextStyle(
color: CupertinoColors.label,
style: TextStyle(
color: AppColor.writeColor,
fontSize: 17,
fontWeight: FontWeight.w500,
),
),
Text(
(contact['phones'][0].toString()),
style: const TextStyle(
color: CupertinoColors.secondaryLabel,
style: TextStyle(
color: AppColor.grayColor,
fontSize: 15,
),
),
@@ -442,9 +451,9 @@ class ShareAppPage extends StatelessWidget {
),
),
// Chevron icon for selection
const Icon(
Icon(
CupertinoIcons.chevron_forward,
color: CupertinoColors.systemGrey2,
color: AppColor.grayColor.withOpacity(0.5),
),
],
),

View File

@@ -152,8 +152,8 @@ class CancelRidePageShow extends StatelessWidget {
decoration: BoxDecoration(
color: AppColor.redColor,
borderRadius: BorderRadius.circular(15)),
child: const Padding(
padding: EdgeInsets.all(3),
child: Padding(
padding: const EdgeInsets.all(3),
child: Icon(
Icons.clear,
size: 40,

View File

@@ -340,28 +340,31 @@ class ApplyOrderWidget extends StatelessWidget {
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 8),
decoration: BoxDecoration(
color: const Color(0xFFF5F5F5),
color: Get.isDarkMode ? Colors.grey[850] : const Color(0xFFF5F5F5),
borderRadius: BorderRadius.circular(6),
border: Border.all(color: Colors.grey.withOpacity(0.3)),
border: Border.all(
color: Get.isDarkMode
? Colors.white10
: Colors.grey.withOpacity(0.3)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
plateNumber,
style: const TextStyle(
style: TextStyle(
fontFamily: 'RobotoMono',
fontSize: 18, // تصغير الرقم
fontSize: 18,
fontWeight: FontWeight.w900,
color: Colors.black87,
color: AppColor.writeColor,
letterSpacing: 1.5,
),
),
const Text("SYR",
Text("SYR",
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: Colors.black54)),
color: AppColor.writeColor.withOpacity(0.6))),
],
),
);

View File

@@ -35,9 +35,9 @@ class CancelRidePageWidget extends StatelessWidget {
return Container(
height: Get.height * 0.7, // ارتفاع مناسب
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(25)),
decoration: BoxDecoration(
color: AppColor.secondaryColor,
borderRadius: const BorderRadius.vertical(top: Radius.circular(25)),
),
child: GetBuilder<MapPassengerController>(
builder: (controller) => Column(
@@ -82,7 +82,7 @@ class CancelRidePageWidget extends StatelessWidget {
: FontWeight.normal,
color: isSelected
? AppColor.primaryColor
: Colors.black87,
: AppColor.writeColor,
fontSize: 15),
),
trailing: isSelected
@@ -104,7 +104,9 @@ class CancelRidePageWidget extends StatelessWidget {
decoration: InputDecoration(
hintText: "Please write the reason...".tr,
filled: true,
fillColor: Colors.grey[100],
fillColor: Get.isDarkMode
? Colors.white.withOpacity(0.05)
: Colors.grey[100],
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none,
@@ -149,7 +151,7 @@ class CancelRidePageWidget extends StatelessWidget {
child: TextButton(
onPressed: () => Get.back(),
child: Text("Don't Cancel".tr,
style: TextStyle(color: Colors.grey[600])),
style: TextStyle(color: AppColor.grayColor)),
),
),
],

View File

@@ -60,7 +60,7 @@ List<CarType> carTypes = [
// ─────────────────────────────────────────────────────────────────────────────
class CarDetailsTypeToChoose extends StatelessWidget {
CarDetailsTypeToChoose({super.key});
final textToSpeechController = Get.put(TextToSpeechController());
final textToSpeechController = Get.find<TextToSpeechController>();
void _prepareCarTypes(MapPassengerController controller) {
if (controller.distance > 23) {
@@ -157,8 +157,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
// ── Promo Code & Actions ─────────────────────────────
_buildPromoButton(context, controller),
SizedBox(
height: MediaQuery.of(context).padding.bottom + 10),
SizedBox(height: MediaQuery.of(context).padding.bottom + 10),
],
),
),
@@ -199,11 +198,13 @@ class CarDetailsTypeToChoose extends StatelessWidget {
child: Container(
padding: const EdgeInsets.all(6),
decoration: BoxDecoration(
color: Colors.grey.shade100,
color: Get.isDarkMode
? Colors.white.withOpacity(0.08)
: Colors.grey.shade100,
shape: BoxShape.circle,
),
child: Icon(Icons.close_rounded,
size: 18, color: Colors.grey.shade600),
size: 18, color: AppColor.grayColor),
),
),
],
@@ -215,8 +216,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
// Distance chip
_buildStatChip(
icon: Icons.route_rounded,
value:
'${controller.distance.toStringAsFixed(1)} ${'KM'.tr}',
value: '${controller.distance.toStringAsFixed(1)} ${'KM'.tr}',
color: AppColor.primaryColor,
),
const SizedBox(width: 8),
@@ -313,11 +313,12 @@ class CarDetailsTypeToChoose extends StatelessWidget {
],
)
: null,
color: isSelected ? null : Colors.white,
color: isSelected ? null : AppColor.secondaryColor,
borderRadius: BorderRadius.circular(16),
border: Border.all(
color:
isSelected ? AppColor.primaryColor : Colors.grey.shade200,
color: isSelected
? AppColor.primaryColor
: AppColor.grayColor.withOpacity(0.2),
width: isSelected ? 2.0 : 1.0,
),
boxShadow: [
@@ -355,8 +356,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
),
],
),
child:
const Icon(Icons.check, size: 11, color: Colors.white),
child: const Icon(Icons.check, size: 11, color: Colors.white),
),
),
@@ -389,7 +389,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
fontSize: 13,
color: isSelected
? AppColor.primaryColor
: Colors.grey.shade800,
: AppColor.writeColor,
),
maxLines: 1,
),
@@ -399,16 +399,17 @@ class CarDetailsTypeToChoose extends StatelessWidget {
// Price tag
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 4),
padding:
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: isSelected
? AppColor.primaryColor
: Colors.grey.shade50,
: AppColor.writeColor.withOpacity(0.05),
borderRadius: BorderRadius.circular(10),
border: isSelected
? null
: Border.all(color: Colors.grey.shade200),
: Border.all(
color: AppColor.grayColor.withOpacity(0.2)),
),
child: FittedBox(
child: Text(
@@ -416,8 +417,9 @@ class CarDetailsTypeToChoose extends StatelessWidget {
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w700,
color:
isSelected ? Colors.white : Colors.grey.shade700,
color: isSelected
? Colors.white
: AppColor.writeColor.withOpacity(0.8),
),
),
),
@@ -446,8 +448,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
onTap: () => _showPromoCodeDialog(context, controller),
borderRadius: BorderRadius.circular(14),
child: Container(
padding:
const EdgeInsets.symmetric(vertical: 12, horizontal: 14),
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 14),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
@@ -730,8 +731,8 @@ class CarDetailsTypeToChoose extends StatelessWidget {
const SizedBox(height: 6),
// Price badge in dialog
Container(
padding: const EdgeInsets.symmetric(
horizontal: 14, vertical: 6),
padding:
const EdgeInsets.symmetric(horizontal: 14, vertical: 6),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
@@ -754,15 +755,20 @@ class CarDetailsTypeToChoose extends StatelessWidget {
Container(
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: Colors.grey.shade50,
color: Get.isDarkMode
? Colors.white.withOpacity(0.05)
: Colors.grey.shade50,
borderRadius: BorderRadius.circular(14),
border: Border.all(color: Colors.grey.shade100),
border: Border.all(
color: Get.isDarkMode
? Colors.white10
: Colors.grey.shade100),
),
child: Text(
_getCarDescription(mapPassengerController, carType),
textAlign: TextAlign.center,
style: AppStyle.subtitle.copyWith(
color: Colors.grey.shade700,
color: AppColor.writeColor.withOpacity(0.8),
fontSize: 14,
height: 1.5,
),
@@ -778,12 +784,12 @@ class CarDetailsTypeToChoose extends StatelessWidget {
padding: const EdgeInsets.symmetric(vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(14),
side: BorderSide(color: Colors.grey.shade200),
side: BorderSide(
color: AppColor.grayColor.withOpacity(0.2)),
),
),
child: Text('Back'.tr,
style:
TextStyle(color: Colors.grey.shade600)),
style: TextStyle(color: AppColor.grayColor)),
),
),
const SizedBox(width: 12),
@@ -810,11 +816,11 @@ class CarDetailsTypeToChoose extends StatelessWidget {
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.white,
color: AppColor.secondaryColor,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(20),
color: Colors.black.withAlpha(30),
blurRadius: 15,
offset: const Offset(0, 5),
),

View File

@@ -59,7 +59,7 @@ class CashConfirmPageShown extends StatelessWidget {
// زر الإغلاق (كان معلقاً في الكود القديم، تم تفعيله هنا)
IconButton(
onPressed: () => controller.changeCashConfirmPageShown(),
icon: const Icon(Icons.close, color: AppColor.writeColor),
icon: Icon(Icons.close, color: AppColor.writeColor),
),
],
),

View File

@@ -1,3 +1,4 @@
import 'package:Intaleq/print.dart';
import 'dart:async';
import 'package:flutter/material.dart';
@@ -131,7 +132,7 @@ class _SearchFieldState extends State<_SearchField> {
hintText: widget.controller.hintTextDestinationPoint,
hintStyle: AppStyle.subtitle.copyWith(color: Colors.grey[600]),
prefixIcon:
const Icon(Icons.search, color: AppColor.primaryColor),
Icon(Icons.search, color: AppColor.primaryColor),
// --- [إصلاح] تم استبدال Obx بشرط بسيط لأن `setState` يعيد بناء الواجهة الآن ---
suffixIcon: widget
.controller.placeDestinationController.text.isNotEmpty
@@ -383,20 +384,20 @@ Widget _buildQuickActionButton({
child: Container(
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: AppColor.blueColor.withOpacity(0.1),
color: AppColor.cyanBlue.withOpacity(0.1),
borderRadius: BorderRadius.circular(8.0),
border: Border.all(color: AppColor.blueColor.withOpacity(0.3)),
border: Border.all(color: AppColor.cyanBlue.withOpacity(0.3)),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, color: AppColor.blueColor),
Icon(icon, color: AppColor.cyanBlue),
const SizedBox(height: 4.0),
Text(
text,
textAlign: TextAlign.center,
style: AppStyle.title.copyWith(
color: AppColor.blueColor, fontWeight: FontWeight.w500),
color: AppColor.cyanBlue, fontWeight: FontWeight.w500),
),
],
),
@@ -451,7 +452,7 @@ void _handleQuickAction(
controller.showBottomSheet1();
} catch (e) {
// Handle error if parsing fails
print("Error handling quick action: $e");
Log.print("Error handling quick action: $e");
Toast.show(Get.context!, "Failed to get location".tr, AppColor.redColor);
}
}
}

View File

@@ -35,7 +35,7 @@ GetBuilder<MapPassengerController> formSearchPlacesStart() {
hintStyle:
AppStyle.subtitle.copyWith(color: Colors.grey[600]),
prefixIcon:
const Icon(Icons.search, color: AppColor.primaryColor),
Icon(Icons.search, color: AppColor.primaryColor),
suffixIcon: controller.placeStartController.text.isNotEmpty
? IconButton(
icon: Icon(Icons.clear, color: Colors.grey[400]),

View File

@@ -17,7 +17,7 @@ GetBuilder<MapPassengerController> formSearchPlaces(int index) {
padding: const EdgeInsets.all(16),
child: Container(
decoration:
const BoxDecoration(color: AppColor.secondaryColor),
BoxDecoration(color: AppColor.secondaryColor),
child: TextField(
decoration: InputDecoration(
border: const OutlineInputBorder(

View File

@@ -1,8 +1,10 @@
import 'package:Intaleq/print.dart';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:maplibre_gl/maplibre_gl.dart';
import 'package:Intaleq/controller/home/points_for_rider_controller.dart';
import 'package:Intaleq/services/offline_map_service.dart';
import '../../../constant/colors.dart';
import '../../../constant/style.dart';
@@ -30,7 +32,7 @@ class GoogleMapPassengerWidget extends StatelessWidget {
attributionButtonMargins: null,
onMapCreated: controller.onMapCreated,
onStyleLoadedCallback: () => controller.onStyleLoaded(),
styleString: "assets/style.json",
styleString: Get.isDarkMode ? "assets/style_dark.json" : "assets/style.json",
// ✅ Performance: Smoother zoom limits for low-end devices
minMaxZoomPreference: controller.lowPerf
@@ -51,10 +53,14 @@ class GoogleMapPassengerWidget extends StatelessWidget {
if (controller.mapController != null) {
final position = controller.mapController!.cameraPosition;
if (position != null) {
print('✅ onCameraIdle targeted: ${position.target}');
Log.print('✅ onCameraIdle targeted: ${position.target}');
// 1. Always update current view target (for pickers)
controller
.updateCurrentLocationFromCamera(position.target);
// 2. Cache explicitly when panning around
// Optional: Limit this to only cache smaller regions (1km) so it doesn't overload on fast panning
OfflineMapService.instance.downloadRegion(position.target, radiusKm: 1.0);
}
}
},
@@ -80,9 +86,9 @@ class GoogleMapPassengerWidget extends StatelessWidget {
colorText: AppColor.redColor,
duration: const Duration(seconds: 5),
backgroundColor: AppColor.secondaryColor,
icon: const Icon(Icons.error, color: AppColor.redColor),
icon: Icon(Icons.error, color: AppColor.redColor),
titleText: Text('Error'.tr,
style: const TextStyle(color: AppColor.redColor)),
style: TextStyle(color: AppColor.redColor)),
messageText: Text(
'We Are Sorry That we dont have cars in your Location!'
.tr,
@@ -99,4 +105,4 @@ class GoogleMapPassengerWidget extends StatelessWidget {
),
);
}
}
}

View File

@@ -17,7 +17,6 @@ import '../navigation/navigation_view.dart';
// --- الدالة الرئيسية بالتصميم الجديد ---
GetBuilder<MapPassengerController> leftMainMenuIcons() {
Get.put(TextToSpeechController());
return GetBuilder<MapPassengerController>(
builder: (controller) => Positioned(
// تم تعديل الموضع ليتناسب مع التصميم الجديد

View File

@@ -1,3 +1,4 @@
import 'package:Intaleq/print.dart';
import 'package:Intaleq/views/widgets/my_textField.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@@ -148,7 +149,9 @@ class MainBottomMenuMap extends StatelessWidget {
borderRadius: BorderRadius.circular(_D.radiusCard),
boxShadow: _D.cardShadow,
border: Border.all(
color: Colors.white.withOpacity(0.65),
color: Get.isDarkMode
? Colors.white.withOpacity(0.15)
: Colors.white.withOpacity(0.65),
width: 1.2,
),
),
@@ -216,123 +219,129 @@ class _CollapsedView extends StatelessWidget {
const SizedBox(height: 16),
// ── Main interactive search card ─────────────────────────────────────
Material(
color: Colors.transparent,
child: InkWell(
onTap: controller.changeMainBottomMenuMap,
borderRadius: BorderRadius.circular(_D.radiusInner),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 8),
child: Row(
children: [
// Animated search icon with glow
AnimatedContainer(
duration: _D.medium,
width: 48,
height: 48,
decoration: BoxDecoration(
gradient: _D.primaryGradient(),
borderRadius: BorderRadius.circular(_D.radiusPill),
boxShadow: _D.glowShadow(AppColor.primaryColor),
Semantics(
button: true,
label: 'Open destination search'.tr,
hint: 'Double tap to open search or enter destination'.tr,
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: controller.changeMainBottomMenuMap,
borderRadius: BorderRadius.circular(_D.radiusInner),
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 18, vertical: 8),
child: Row(
children: [
// Animated search icon with glow
AnimatedContainer(
duration: _D.medium,
width: 48,
height: 48,
decoration: BoxDecoration(
gradient: _D.primaryGradient(),
borderRadius: BorderRadius.circular(_D.radiusPill),
boxShadow: _D.glowShadow(AppColor.primaryColor),
),
child: const Icon(
Icons.search_rounded,
color: Colors.white,
size: 22,
),
),
child: const Icon(
Icons.search_rounded,
color: Colors.white,
size: 22,
),
),
const SizedBox(width: 16),
const SizedBox(width: 16),
// Dynamic text content
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text.rich(
TextSpan(
children: [
TextSpan(
text: '${'Where to'.tr} ',
style: AppStyle.title.copyWith(
fontWeight: FontWeight.w600,
fontSize: 16,
color: Colors.grey.shade700,
// Dynamic text content
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text.rich(
TextSpan(
children: [
TextSpan(
text: '${'Where to'.tr} ',
style: AppStyle.title.copyWith(
fontWeight: FontWeight.w600,
fontSize: 16,
color: Colors.grey.shade700,
),
),
),
TextSpan(
text: firstName,
style: AppStyle.title.copyWith(
fontWeight: FontWeight.w800,
fontSize: 16.5,
color: AppColor.primaryColor,
letterSpacing: -0.3,
TextSpan(
text: firstName,
style: AppStyle.title.copyWith(
fontWeight: FontWeight.w800,
fontSize: 16.5,
color: AppColor.primaryColor,
letterSpacing: -0.3,
),
),
),
const TextSpan(text: '؟'),
],
),
),
const SizedBox(height: 2),
if (!controller.noCarString)
AnimatedOpacity(
duration: _D.fast,
opacity: 1,
child: Text(
'Tap to search your destination'.tr,
style: AppStyle.subtitle.copyWith(
fontSize: 12,
color: Colors.grey.shade500,
fontWeight: FontWeight.w400,
),
const TextSpan(text: '؟'),
],
),
),
],
),
),
// Elegant expand indicator
Container(
padding:
const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
AppColor.primaryColor.withOpacity(0.12),
AppColor.primaryColor.withOpacity(0.06),
const SizedBox(height: 2),
if (!controller.noCarString)
AnimatedOpacity(
duration: _D.fast,
opacity: 1,
child: Text(
'Tap to search your destination'.tr,
style: AppStyle.subtitle.copyWith(
fontSize: 12,
color: Colors.grey.shade500,
fontWeight: FontWeight.w400,
),
),
),
],
),
borderRadius: BorderRadius.circular(_D.radiusPill),
border: Border.all(
color: AppColor.primaryColor.withOpacity(0.25),
width: 1,
),
// Elegant expand indicator
Container(
padding: const EdgeInsets.symmetric(
horizontal: 14, vertical: 8),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
AppColor.primaryColor.withOpacity(0.12),
AppColor.primaryColor.withOpacity(0.06),
],
),
borderRadius: BorderRadius.circular(_D.radiusPill),
border: Border.all(
color: AppColor.primaryColor.withOpacity(0.25),
width: 1,
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
AnimatedRotation(
duration: _D.fast,
turns: 0,
child: Icon(
Icons.keyboard_arrow_up_rounded,
color: AppColor.primaryColor,
size: 20,
),
),
const SizedBox(width: 4),
Text(
'Open'.tr,
style: TextStyle(
color: AppColor.primaryColor,
fontSize: 12.5,
fontWeight: FontWeight.w700,
letterSpacing: 0.3,
),
),
],
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
AnimatedRotation(
duration: _D.fast,
turns: 0,
child: Icon(
Icons.keyboard_arrow_up_rounded,
color: AppColor.primaryColor,
size: 20,
),
),
const SizedBox(width: 4),
Text(
'Open'.tr,
style: TextStyle(
color: AppColor.primaryColor,
fontSize: 12.5,
fontWeight: FontWeight.w700,
letterSpacing: 0.3,
),
),
],
),
),
],
],
),
),
),
),
@@ -438,30 +447,34 @@ class _ExpandedView extends StatelessWidget {
),
const Spacer(),
// Elegant close button
Material(
color: Colors.transparent,
child: InkWell(
onTap: controller.changeMainBottomMenuMap,
borderRadius: BorderRadius.circular(_D.radiusPill),
child: AnimatedContainer(
duration: _D.fast,
width: 38,
height: 38,
decoration: BoxDecoration(
color: Colors.grey.shade100,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.grey.shade200.withOpacity(0.5),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Icon(
Icons.keyboard_arrow_down_rounded,
size: 24,
color: Colors.grey.shade600,
Semantics(
button: true,
label: 'Close panel'.tr,
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: controller.changeMainBottomMenuMap,
borderRadius: BorderRadius.circular(_D.radiusPill),
child: AnimatedContainer(
duration: _D.fast,
width: 38,
height: 38,
decoration: BoxDecoration(
color: Colors.grey.shade100,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.grey.shade200.withOpacity(0.5),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Icon(
Icons.keyboard_arrow_down_rounded,
size: 24,
color: Colors.grey.shade600,
),
),
),
),
@@ -586,6 +599,13 @@ class _ExpandedView extends StatelessWidget {
),
const SizedBox(width: 12),
Expanded(
child: Semantics(
button: true,
label: isSet
? '${'Waypoint'.tr} $wpName'
: '${'Stop'.tr} ${index + 1}',
hint: 'Double tap to set or change this waypoint on the map'
.tr,
child: GestureDetector(
onTap: () {
controller.changeMainBottomMenuMap();
@@ -607,52 +627,60 @@ class _ExpandedView extends StatelessWidget {
overflow: TextOverflow.ellipsis,
),
),
),
)),
// Map button with hover effect simulation
GestureDetector(
onTap: () {
controller.changeMainBottomMenuMap();
controller.startPickingWaypointOnMap(index);
},
child: AnimatedContainer(
duration: _D.fast,
width: 34,
height: 34,
margin: const EdgeInsets.symmetric(horizontal: 4),
decoration: BoxDecoration(
color: accent.withOpacity(0.12),
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: accent.withOpacity(0.25),
width: 1,
Semantics(
button: true,
label: 'Pick location on map'.tr,
child: GestureDetector(
onTap: () {
controller.changeMainBottomMenuMap();
controller.startPickingWaypointOnMap(index);
},
child: AnimatedContainer(
duration: _D.fast,
width: 34,
height: 34,
margin: const EdgeInsets.symmetric(horizontal: 4),
decoration: BoxDecoration(
color: accent.withOpacity(0.12),
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: accent.withOpacity(0.25),
width: 1,
),
),
child: Icon(
Icons.map_outlined,
color: accent,
size: 17,
),
),
child: Icon(
Icons.map_outlined,
color: accent,
size: 17,
),
),
),
// Remove button with subtle animation
GestureDetector(
onTap: () => controller.removeMenuWaypoint(index),
child: AnimatedContainer(
duration: _D.fast,
width: 28,
height: 28,
decoration: BoxDecoration(
color: Colors.red.shade50,
shape: BoxShape.circle,
border: Border.all(
color: Colors.red.shade100,
width: 1,
Semantics(
button: true,
label: 'Remove waypoint'.tr,
child: GestureDetector(
onTap: () => controller.removeMenuWaypoint(index),
child: AnimatedContainer(
duration: _D.fast,
width: 28,
height: 28,
decoration: BoxDecoration(
color: Colors.red.shade50,
shape: BoxShape.circle,
border: Border.all(
color: Colors.red.shade100,
width: 1,
),
),
child: Icon(
Icons.close_rounded,
color: Colors.red.shade400,
size: 15,
),
),
child: Icon(
Icons.close_rounded,
color: Colors.red.shade400,
size: 15,
),
),
),
@@ -669,69 +697,73 @@ class _ExpandedView extends StatelessWidget {
isDotDashed: true,
showTopLine: true,
showBottomLine: true,
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () => controller.addMenuWaypoint(),
borderRadius: BorderRadius.circular(_D.radiusInner),
child: AnimatedContainer(
duration: _D.fast,
padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(_D.radiusInner),
border: Border.all(
color: Colors.orange.shade200,
style: BorderStyle.solid,
width: 1.5,
),
gradient: LinearGradient(
colors: [
Colors.orange.shade50.withOpacity(0.6),
Colors.orange.shade50.withOpacity(0.3),
],
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.add_location_alt_outlined,
color: Colors.orange.shade500,
size: 18,
child: Semantics(
button: true,
label: 'Add a new waypoint stop'.tr,
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () => controller.addMenuWaypoint(),
borderRadius: BorderRadius.circular(_D.radiusInner),
child: AnimatedContainer(
duration: _D.fast,
padding: const EdgeInsets.symmetric(
horizontal: 16, vertical: 12),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(_D.radiusInner),
border: Border.all(
color: Colors.orange.shade200,
style: BorderStyle.solid,
width: 1.5,
),
const SizedBox(width: 10),
Text(
'Add a Stop'.tr,
style: TextStyle(
color: Colors.orange.shade700,
fontSize: 13.5,
fontWeight: FontWeight.w600,
letterSpacing: 0.2,
),
gradient: LinearGradient(
colors: [
Colors.orange.shade50.withOpacity(0.6),
Colors.orange.shade50.withOpacity(0.3),
],
),
const SizedBox(width: 10),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 3),
decoration: BoxDecoration(
color: Colors.orange.shade100,
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: Colors.orange.shade200,
width: 1,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.add_location_alt_outlined,
color: Colors.orange.shade500,
size: 18,
),
child: Text(
'+5 ${'min'.tr}',
const SizedBox(width: 10),
Text(
'Add a Stop'.tr,
style: TextStyle(
color: Colors.orange.shade700,
fontSize: 10.5,
fontWeight: FontWeight.w700,
fontSize: 13.5,
fontWeight: FontWeight.w600,
letterSpacing: 0.2,
),
),
),
],
const SizedBox(width: 10),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 3),
decoration: BoxDecoration(
color: Colors.orange.shade100,
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: Colors.orange.shade200,
width: 1,
),
),
child: Text(
'+5 ${'min'.tr}',
style: TextStyle(
color: Colors.orange.shade700,
fontSize: 10.5,
fontWeight: FontWeight.w700,
),
),
),
],
),
),
),
),
@@ -990,7 +1022,9 @@ class _MapPickerOverlay extends StatelessWidget {
' ${controller.pickingWaypointIndex + 1}'.tr;
}
if (controller.passengerStartLocationFromMap) {
return 'Move map to your pickup point'.tr;
return controller.isAnotherOreder
? 'Now set the pickup point for the other person'.tr
: 'Move map to your pickup point'.tr;
} else if (controller.startLocationFromMap) {
return 'Move map to set start location'.tr;
} else if (controller.workLocationFromMap) {
@@ -1055,7 +1089,9 @@ class _MapPickerOverlay extends StatelessWidget {
borderRadius: BorderRadius.circular(_D.radiusCard),
boxShadow: _D.glowShadow(modeColor, intensity: 0.5),
border: Border.all(
color: Colors.white.withOpacity(0.35),
color: Get.isDarkMode
? Colors.white.withOpacity(0.15)
: Colors.white.withOpacity(0.35),
width: 1,
),
),
@@ -1105,7 +1141,9 @@ class _MapPickerOverlay extends StatelessWidget {
borderRadius: BorderRadius.circular(_D.radiusCard),
boxShadow: _D.cardShadow,
border: Border.all(
color: Colors.white.withOpacity(0.7),
color: Get.isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.white.withOpacity(0.7),
width: 1.3,
),
),
@@ -1339,24 +1377,15 @@ class _MapPickerOverlay extends StatelessWidget {
controller.newMyLocation.latitude,
controller.newMyLocation.longitude,
);
print(
Log.print(
'🌐 MAP PICKER CENTER: ${currentCameraPosition.latitude}, ${currentCameraPosition.longitude}');
print(
Log.print(
'✅ _onConfirmTap confirmed coordinates: ${currentCameraPosition.latitude}, ${currentCameraPosition.longitude}');
if (controller.isPickingWaypoint && controller.pickingWaypointIndex >= 0) {
final int wpIndex = controller.pickingWaypointIndex;
controller.setMenuWaypointFromMap(wpIndex, currentCameraPosition);
Get.snackbar(
'Stop ${wpIndex + 1} Set'.tr,
'Waypoint has been set successfully'.tr,
backgroundColor: Colors.orange.shade600,
colorText: Colors.white,
snackPosition: SnackPosition.TOP,
duration: const Duration(seconds: 2),
margin: const EdgeInsets.all(12),
borderRadius: 12,
);
mySnackbarSuccess('Waypoint has been set successfully'.tr);
return;
}
@@ -1403,10 +1432,7 @@ class _MapPickerOverlay extends StatelessWidget {
controller.workLocationFromMap = false;
controller.isPickerShown = false;
controller.update();
Get.snackbar('Work Saved'.tr, '',
backgroundColor: AppColor.greenColor,
colorText: Colors.white,
snackPosition: SnackPosition.BOTTOM);
mySnackbarSuccess('Work Saved'.tr);
return;
}
@@ -1418,10 +1444,7 @@ class _MapPickerOverlay extends StatelessWidget {
controller.homeLocationFromMap = false;
controller.isPickerShown = false;
controller.update();
Get.snackbar('Home Saved'.tr, '',
backgroundColor: AppColor.greenColor,
colorText: Colors.white,
snackPosition: SnackPosition.BOTTOM);
mySnackbarSuccess('Home Saved'.tr);
return;
}
@@ -1432,6 +1455,7 @@ class _MapPickerOverlay extends StatelessWidget {
controller.placesDestination = [];
controller.placeDestinationController.clear();
controller.passengerStartLocationFromMap = true;
controller.isPickerShown = true; // ✅ Keep picker UI open for pickup selection
controller.update();
try {
@@ -1450,7 +1474,9 @@ class _MapPickerOverlay extends StatelessWidget {
)),
);
}
} catch (_) {}
} catch (e) {
Log.print("Error occurred: $e");
}
Get.snackbar(
'Destination Set'.tr,

View File

@@ -22,14 +22,17 @@ import '../HomePage/share_app_page.dart';
import '../setting_page.dart';
import '../profile/passenger_profile_page.dart';
// ─── ألوان النظام ───────────────────────────────────────────────────────────
const _kBg = Color(0xFF060B18);
const _kBgSurface = Color(0xFF0D1525);
const _kCyan = Color(0xFF00D4FF);
// ─── ألوان النظام (Integrated with AppColor) ──────────────────────────────────
Color get _kCyan => AppColor.cyanBlue;
Color get _kBg =>
Get.isDarkMode ? const Color(0xFF060B18) : AppColor.secondaryColor;
Color get _kBgSurface => Get.isDarkMode
? const Color(0xFF0D1525)
: AppColor.secondaryColor.withOpacity(0.9);
const _kAmber = Color(0xFFFFB700);
const _kBorder = Color(0x1A00D4FF);
const _kText = Colors.white;
const _kTextMuted = Color(0xFF7A8FA8);
Color get _kBorder => _kCyan.withOpacity(0.15);
Color get _kText => AppColor.writeColor;
Color get _kTextMuted => AppColor.grayColor;
class MapMenuWidget extends StatelessWidget {
const MapMenuWidget({super.key});
@@ -259,8 +262,7 @@ class MapMenuWidget extends StatelessWidget {
border:
Border.all(color: _kCyan.withOpacity(0.35), width: 1.5),
),
child:
const Icon(Icons.person_rounded, color: _kCyan, size: 28),
child: Icon(Icons.person_rounded, color: _kCyan, size: 28),
),
// نقطة الحضور
Positioned(
@@ -291,7 +293,7 @@ class MapMenuWidget extends StatelessWidget {
children: [
Text(
box.read(BoxName.name) ?? 'Guest',
style: const TextStyle(
style: TextStyle(
color: _kText,
fontSize: 17,
fontWeight: FontWeight.w700,
@@ -305,13 +307,13 @@ class MapMenuWidget extends StatelessWidget {
Container(
width: 5,
height: 5,
decoration: const BoxDecoration(
color: _kCyan, shape: BoxShape.circle),
decoration:
BoxDecoration(color: _kCyan, shape: BoxShape.circle),
),
const SizedBox(width: 6),
Text(
"Intaleq Passenger".tr,
style: const TextStyle(
style: TextStyle(
color: _kTextMuted,
fontSize: 12,
letterSpacing: 0.4,
@@ -426,7 +428,7 @@ class _QuickBtn extends StatelessWidget {
const SizedBox(height: 6),
Text(
label,
style: const TextStyle(
style: TextStyle(
color: _kTextMuted,
fontSize: 11,
letterSpacing: 0.4,
@@ -518,7 +520,7 @@ class _MenuGridPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = const Color(0xFF00D4FF).withOpacity(0.025)
..color = AppColor.cyanBlue.withOpacity(0.04)
..strokeWidth = 0.5;
const spacing = 36.0;
for (double y = 0; y < size.height; y += spacing) {

View File

@@ -127,9 +127,9 @@ class MyCreditCardWidget extends StatelessWidget {
builder: (controller) => Container(
height: Get.height * .4,
width: Get.width * .9,
decoration: const BoxDecoration(
decoration: BoxDecoration(
color: AppColor.secondaryColor,
borderRadius: BorderRadius.all(Radius.circular(15)),
borderRadius: const BorderRadius.all(Radius.circular(15)),
gradient: LinearGradient(colors: [
AppColor.secondaryColor,
// AppColor.blueColor,
@@ -139,7 +139,7 @@ class MyCreditCardWidget extends StatelessWidget {
// AppColor.redColor,
// AppColor.yellowColor
]),
boxShadow: [
boxShadow: const [
BoxShadow(
spreadRadius: 3,
offset: Offset(3, 3),

View File

@@ -25,15 +25,15 @@ class PickerAnimtionContainerFormPlaces extends StatelessWidget {
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
height: controller.heightPickerContainer,
decoration: const BoxDecoration(
boxShadow: [
decoration: BoxDecoration(
boxShadow: const [
BoxShadow(
color: AppColor.accentColor, offset: Offset(2, 2)),
BoxShadow(
color: AppColor.accentColor, offset: Offset(-2, -2))
],
color: AppColor.secondaryColor,
borderRadius: BorderRadius.only(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(15),
topRight: Radius.circular(15),
)),

View File

@@ -132,7 +132,7 @@ class PointsPageForRider extends StatelessWidget {
},
)
: IconButton(
icon: const Icon(
icon: Icon(
Icons.close,
color: AppColor.secondaryColor,
),
@@ -264,7 +264,7 @@ void showAddLocationDialog(BuildContext context, int index) {
'Add Location'.tr,
style: AppStyle.title,
),
const Icon(
Icon(
Icons.clear,
color: AppColor.secondaryColor,
)
@@ -301,7 +301,7 @@ class AppBarPointsPageForRider extends StatelessWidget {
Container(
child: Row(
children: [
const CircleAvatar(
CircleAvatar(
backgroundColor: AppColor.primaryColor,
maxRadius: 15,
child: Icon(
@@ -319,7 +319,7 @@ class AppBarPointsPageForRider extends StatelessWidget {
],
),
),
const Icon(
Icon(
Icons.clear,
color: AppColor.secondaryColor,
)

View File

@@ -42,14 +42,16 @@ class RideBeginPassenger extends StatelessWidget {
right: 0,
child: Container(
decoration: BoxDecoration(
color: Colors.white,
color: AppColor.secondaryColor,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(25),
topRight: Radius.circular(25),
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
color: Get.isDarkMode
? Colors.black.withOpacity(0.4)
: Colors.black.withOpacity(0.1),
blurRadius: 20,
spreadRadius: 2,
offset: const Offset(0, -3),
@@ -67,7 +69,7 @@ class RideBeginPassenger extends StatelessWidget {
width: 40,
height: 4,
decoration: BoxDecoration(
color: Colors.grey[300],
color: AppColor.grayColor.withOpacity(0.3),
borderRadius: BorderRadius.circular(10),
),
),
@@ -80,8 +82,10 @@ class RideBeginPassenger extends StatelessWidget {
const SizedBox(height: 12),
// خط فاصل خفيف
const Divider(
height: 1, thickness: 0.5, color: Color(0xFFEEEEEE)),
Divider(
height: 1,
thickness: 0.5,
color: AppColor.grayColor.withOpacity(0.2)),
const SizedBox(height: 12),
@@ -129,10 +133,10 @@ class RideBeginPassenger extends StatelessWidget {
Flexible(
child: Text(
controller.driverName,
style: const TextStyle(
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
color: Colors.black87,
color: AppColor.writeColor,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
@@ -153,7 +157,7 @@ class RideBeginPassenger extends StatelessWidget {
Flexible(
child: Text(
'${controller.model}',
style: TextStyle(fontSize: 12, color: Colors.grey[700]),
style: TextStyle(fontSize: 12, color: AppColor.grayColor),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
@@ -162,8 +166,9 @@ class RideBeginPassenger extends StatelessWidget {
padding:
const EdgeInsets.symmetric(horizontal: 4, vertical: 1),
decoration: BoxDecoration(
color: Colors.grey[100],
border: Border.all(color: Colors.black12),
color: AppColor.writeColor.withOpacity(0.05),
border: Border.all(
color: AppColor.grayColor.withOpacity(0.2)),
borderRadius: BorderRadius.circular(4),
),
child: Text(
@@ -200,7 +205,7 @@ class RideBeginPassenger extends StatelessWidget {
),
),
Text('SYP',
style: TextStyle(fontSize: 9, color: Colors.grey[600])),
style: TextStyle(fontSize: 9, color: AppColor.grayColor)),
],
),
),
@@ -287,8 +292,8 @@ class RideBeginPassenger extends StatelessWidget {
_compactBtn(
icon: Icons.info_outline_rounded,
label: 'Report'.tr,
color: Colors.grey[700]!,
bgColor: Colors.grey[200]!,
color: AppColor.grayColor,
bgColor: AppColor.writeColor.withOpacity(0.1),
onTap: () => Get.to(() => ComplaintPage()),
),
],
@@ -322,7 +327,7 @@ class RideBeginPassenger extends StatelessWidget {
label,
style: TextStyle(
fontSize: 10,
color: Colors.grey[700],
color: AppColor.grayColor,
fontWeight: FontWeight.w500),
),
],

View File

@@ -50,18 +50,20 @@ class RideFromStartApp extends StatelessWidget {
bottom: 0, // ملتصق بالأسفل تماماً
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
decoration: const BoxDecoration(
color: Colors.white, // خلفية بيضاء نظيفة
decoration: BoxDecoration(
color: AppColor.secondaryColor, // خلفية متفاعلة
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25),
topRight: Radius.circular(25),
),
boxShadow: [
BoxShadow(
color: Colors.black12,
color: Get.isDarkMode
? Colors.black.withOpacity(0.4)
: Colors.black12,
blurRadius: 15.0,
spreadRadius: 5.0,
offset: Offset(0, -5),
offset: const Offset(0, -5),
),
],
),
@@ -76,7 +78,7 @@ class RideFromStartApp extends StatelessWidget {
height: 4,
margin: const EdgeInsets.only(bottom: 15),
decoration: BoxDecoration(
color: Colors.grey[300],
color: AppColor.grayColor.withOpacity(0.3),
borderRadius: BorderRadius.circular(10),
),
),
@@ -112,7 +114,7 @@ class RideFromStartApp extends StatelessWidget {
style: AppStyle.title.copyWith(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.black87,
color: AppColor.writeColor,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
@@ -129,12 +131,15 @@ class RideFromStartApp extends StatelessWidget {
fontSize: 13, fontWeight: FontWeight.bold),
),
const SizedBox(width: 8),
Container(width: 1, height: 12, color: Colors.grey),
Container(
width: 1,
height: 12,
color: AppColor.grayColor.withOpacity(0.3)),
const SizedBox(width: 8),
Text(
"$carType - $carModel",
style: AppStyle.title.copyWith(
fontSize: 13, color: Colors.grey[600]),
fontSize: 13, color: AppColor.grayColor),
),
],
),
@@ -266,22 +271,22 @@ class RideFromStartApp extends StatelessWidget {
return Column(
children: [
Icon(icon,
color: AppColor.secondaryColor,
color: AppColor.primaryColor,
size: 22), // افترضت أن السكندري لون داكن، أو استخدم Primary
const SizedBox(height: 4),
Text(
value,
style: const TextStyle(
style: TextStyle(
fontWeight: FontWeight.w800,
fontSize: 15,
color: Colors.black87,
color: AppColor.writeColor,
),
),
Text(
label,
style: TextStyle(
fontSize: 11,
color: Colors.grey[600],
color: AppColor.grayColor,
),
),
],
@@ -292,7 +297,7 @@ class RideFromStartApp extends StatelessWidget {
return Container(
height: 30,
width: 1,
color: Colors.grey[300],
color: AppColor.grayColor.withOpacity(0.2),
);
}

View File

@@ -210,7 +210,7 @@ class CupertinoDriverListWidget extends StatelessWidget {
Get.back();
showDateTimePickerDialog(driver);
}));
print('${'Selected driver'.tr}: ${driver['NAME']}');
Log.print('${'Selected driver'.tr}: ${driver['NAME']}');
// Get.back(); // Close the dialog
},
),

View File

@@ -207,7 +207,7 @@ class PassengerWallet extends StatelessWidget {
subtitle: Text(subtitle.tr,
style: AppStyle.subtitle
.copyWith(color: AppColor.writeColor.withOpacity(0.6))),
trailing: const Icon(Icons.arrow_forward_ios_rounded,
trailing: Icon(Icons.arrow_forward_ios_rounded,
size: 16, color: AppColor.writeColor),
);
}

View File

@@ -1,3 +1,4 @@
import 'package:Intaleq/print.dart';
import 'package:Intaleq/constant/style.dart';
import 'package:Intaleq/controller/functions/encrypt_decrypt.dart';
import 'package:flutter/cupertino.dart';
@@ -457,7 +458,7 @@ void showPaymentOptions(BuildContext context, PaymentController controller) {
);
if (!didAuthenticate) {
print("❌ User did not authenticate with biometrics");
Log.print("❌ User did not authenticate with biometrics");
return;
}
}
@@ -495,4 +496,4 @@ void showPaymentOptions(BuildContext context, PaymentController controller) {
),
),
);
}
}

View File

@@ -16,8 +16,12 @@ import '../../../controller/functions/tts.dart';
import '../../../controller/home/decode_polyline_isolate.dart';
import '../../../main.dart';
import '../../../print.dart';
import 'dart:ui';
class NavigationController extends GetxController {
import '../../../services/offline_map_service.dart';
class NavigationController extends GetxController
with GetSingleTickerProviderStateMixin {
// ==========================================================================
// ── Tunables ──────────────────────────────────────────────────────────────
// ==========================================================================
@@ -57,11 +61,17 @@ class NavigationController extends GetxController {
/// Updated every tick via angle-aware lerp to eliminate snap/jitter.
double _smoothedHeading = 0.0;
// Animation for smooth tracking
AnimationController? _animController;
LatLng? _oldLoc;
LatLng? _targetLoc;
double currentSpeed = 0.0; // km/h
double totalDistance = 0.0; // metres accumulated this session
// MapLibre objects
Symbol? carSymbol;
Symbol? originSymbol;
Symbol? destinationSymbol;
Line? remainingRouteLine;
Line? traveledRouteLine;
@@ -155,14 +165,31 @@ class NavigationController extends GetxController {
@override
void onInit() {
super.onInit();
_animController = AnimationController(
vsync: this, duration: const Duration(milliseconds: 1000));
_animController!.addListener(() {
if (_oldLoc != null && _targetLoc != null && _mapReady) {
final t = _animController!.value;
final lat = lerpDouble(_oldLoc!.latitude, _targetLoc!.latitude, t)!;
final lng = lerpDouble(_oldLoc!.longitude, _targetLoc!.longitude, t)!;
myLocation = LatLng(lat, lng);
if (isStyleLoaded) {
_updateCarMarker();
if (_fullRouteCoordinates.isNotEmpty && _cameraLockedToUser) {
animateCameraToPosition(myLocation!,
bearing: _smoothedHeading,
zoom: _targetZoom,
tilt: _targetTilt);
}
}
}
});
_initialize();
}
Future<void> _initialize() async {
await _getCurrentLocationAndStartUpdates();
if (!Get.isRegistered<TextToSpeechController>()) {
Get.put(TextToSpeechController());
}
}
@override
@@ -171,6 +198,7 @@ class NavigationController extends GetxController {
_recordTimer?.cancel();
_uploadBatchTimer?.cancel();
_debounce?.cancel();
_animController?.dispose();
mapController?.dispose();
placeDestinationController.dispose();
@@ -294,7 +322,10 @@ class NavigationController extends GetxController {
}
_lastDistanceLocation = newLoc;
myLocation = newLoc;
_oldLoc = myLocation ?? newLoc;
_targetLoc = newLoc;
_animController?.forward(from: 0.0);
_lastProcessedLocation = newLoc;
heading = position.heading;
@@ -306,23 +337,22 @@ class NavigationController extends GetxController {
currentSpeed = position.speed * 3.6;
if (isStyleLoaded) _updateCarMarker();
// Initial visual update if map is fresh
if (isStyleLoaded && myLocation == null) _updateCarMarker();
if (_fullRouteCoordinates.isNotEmpty) {
if (_cameraLockedToUser) {
animateCameraToPosition(myLocation!,
bearing: _smoothedHeading, zoom: _targetZoom, tilt: _targetTilt);
}
_updateTraveledPolylineSmart(myLocation!);
_checkNavigationStep(myLocation!);
_updateTraveledPolylineSmart(newLoc);
_checkNavigationStep(newLoc);
_recomputeETA();
// ── Off-route auto-recalculate ─────────────────────────────────────
_checkOffRoute(myLocation!);
_checkOffRoute(newLoc);
}
update();
} catch (_) {}
} catch (e) {
Log.print("Error occurred: $e");
}
}
// ==========================================================================
@@ -498,14 +528,14 @@ class NavigationController extends GetxController {
geometry: myLocation,
iconImage: 'car_icon',
iconSize: 1.0,
iconRotate: _smoothedHeading, // ← use smoothed heading
iconRotate: _smoothedHeading,
));
} else {
mapController!.updateSymbol(
carSymbol!,
SymbolOptions(
geometry: myLocation,
iconRotate: _smoothedHeading, // ← use smoothed heading
iconRotate: _smoothedHeading,
),
);
}
@@ -532,6 +562,50 @@ class NavigationController extends GetxController {
);
}
/// Safe wrapper for animateCamera Bounds to prevent native std::domain_error crash on iOS.
Future<void> _safeAnimateCameraBounds(LatLngBounds? bounds,
{double left = 60,
double top = 60,
double right = 60,
double bottom = 60}) async {
if (bounds == null || mapController == null) return;
try {
// Ensure the coordinates are valid (at least a small span)
final latSpan =
(bounds.northeast.latitude - bounds.southwest.latitude).abs();
final lngSpan =
(bounds.northeast.longitude - bounds.southwest.longitude).abs();
if (latSpan < 0.0001 && lngSpan < 0.0001) {
Log.print(
'⚠️ _safeAnimateCameraBounds: Point-sized bounds, zooming to center.');
mapController
?.animateCamera(CameraUpdate.newLatLngZoom(bounds.northeast, 16));
return;
}
// Small delay for view stabilization
await Future.delayed(const Duration(milliseconds: 200));
await mapController?.animateCamera(
CameraUpdate.newLatLngBounds(
bounds,
left: left,
top: top,
right: right,
bottom: bottom,
),
);
} catch (e) {
Log.print('❌ _safeAnimateCameraBounds CRASH PREVENTED in Nav: $e');
try {
await mapController
?.animateCamera(CameraUpdate.newLatLngZoom(bounds.northeast, 14));
} catch (_) {}
}
}
void onUserPanned() {
_cameraLockedToUser = false;
update();
@@ -625,38 +699,90 @@ class NavigationController extends GetxController {
// ==========================================================================
Future<void> getRoute(LatLng origin, LatLng destination) async {
// ── Routing Decision: Normal Points -> SaaS, Multi-Stop -> OSRM ──
// Note: NavigationController usually handles the active trip (normal points).
final Map<String, String> queryParams = {
'fromLat': origin.latitude.toString(),
'fromLng': origin.longitude.toString(),
'toLat': destination.latitude.toString(),
'toLng': destination.longitude.toString(),
};
final saasUri =
Uri.parse(AppLink.mapSaasRoute).replace(queryParameters: queryParams);
// Fallback OSRM URL
final coords = "${origin.longitude},${origin.latitude};"
"${destination.longitude},${destination.latitude}";
final url =
final osrmUrl =
"$_routeApiBaseUrl/$coords?steps=true&overview=full&geometries=polyline";
try {
final response = await http.get(Uri.parse(url));
// 1. Try SaaS first
http.Response response = await http.get(saasUri, headers: {
'x-api-key': 'intaleq_secret_2026',
});
bool useSaaS = response.statusCode == 200;
if (!useSaaS) {
Log.print("⚠️ SaaS Route failed. Falling back to OSRM...");
response = await http.get(Uri.parse(osrmUrl));
}
if (response.statusCode != 200) {
mySnackbarWarning('تعذر الاتصال بخدمة التوجيه.');
return;
}
final data = jsonDecode(response.body);
if (data['code'] != 'Ok' || (data['routes'] as List).isEmpty) {
final bool isSaaS = useSaaS;
// ── 2. Data Extraction Logic ──────────────────────────────────
String pointsString = "";
dynamic mainRoute;
if (isSaaS) {
pointsString = data['points']?.toString() ?? "";
mainRoute = data; // SaaS structure is top-level
} else {
if (data['code'] != 'Ok' || (data['routes'] as List).isEmpty) {
mySnackbarWarning('لم يتم العثور على مسار.');
return;
}
mainRoute = data['routes'][0];
pointsString = mainRoute['geometry']?.toString() ?? "";
}
if (pointsString.isEmpty) {
mySnackbarWarning('لم يتم العثور على مسار.');
return;
}
final route = data['routes'][0];
_fullRouteCoordinates = await compute<String, List<LatLng>>(
decodePolylineIsolate, route['geometry'].toString());
decodePolylineIsolate, pointsString);
_lastTraveledIndexInFullRoute = 0;
if (isStyleLoaded) _updatePolylinesSets([], _fullRouteCoordinates);
final legs = route['legs'] as List;
if (legs.isNotEmpty) {
routeSteps = List<Map<String, dynamic>>.from(legs[0]['steps'] as List);
// ── Offline Cache: Ensure destination area is stored in memory/disk ───
if (_fullRouteCoordinates.isNotEmpty) {
OfflineMapService.instance
.downloadRegion(_fullRouteCoordinates.last, radiusKm: 2.0);
}
// Handle legs/steps & totals
final legs = mainRoute['legs'] as List?;
if (legs != null && legs.isNotEmpty) {
routeSteps = List<Map<String, dynamic>>.from(legs[0]['steps'] as List);
_routeTotalDistanceM = (legs[0]['distance'] as num).toDouble();
_routeTotalDurationS = (legs[0]['duration'] as num).toDouble();
} else {
// Fallback for SaaS which might have top-level distance/duration
routeSteps = [];
_routeTotalDistanceM = (mainRoute['distance'] as num).toDouble();
_routeTotalDurationS = (mainRoute['duration'] as num).toDouble();
}
if (_routeTotalDistanceM > 0) {
totalDistanceRemaining = _routeTotalDistanceM > 1000
? "${(_routeTotalDistanceM / 1000).toStringAsFixed(1)} كم"
: "${_routeTotalDistanceM.toStringAsFixed(0)} م";
@@ -665,8 +791,6 @@ class NavigationController extends GetxController {
estimatedTimeRemaining = minutes > 60
? "${(minutes / 60).floor()} س ${minutes % 60} د"
: "$minutes د";
} else {
routeSteps = [];
}
for (final step in routeSteps) {
@@ -689,20 +813,18 @@ class NavigationController extends GetxController {
Get.find<TextToSpeechController>().speakText(currentInstruction);
}
// ── 5. Camera Update (Safe) ───────────────────────────────────
if (_fullRouteCoordinates.length >= 2) {
final bounds = _boundsFromLatLngList(_fullRouteCoordinates);
final bounds =
data['bbox'] != null && (data['bbox'] as List).length == 4
? LatLngBounds(
southwest: LatLng(data['bbox'][1], data['bbox'][0]),
northeast: LatLng(data['bbox'][3], data['bbox'][2]),
)
: _boundsFromLatLngList(_fullRouteCoordinates);
final latDiff =
(bounds.northeast.latitude - bounds.southwest.latitude).abs();
final lngDiff =
(bounds.northeast.longitude - bounds.southwest.longitude).abs();
if (latDiff > 0.0001 || lngDiff > 0.0001) {
mapController?.animateCamera(CameraUpdate.newLatLngBounds(bounds,
bottom: 220, top: 150, left: 50, right: 50));
} else {
animateCameraToPosition(_fullRouteCoordinates.first, zoom: 15.0);
}
await _safeAnimateCameraBounds(bounds,
bottom: 220, top: 150, left: 50, right: 50);
}
update();
@@ -741,6 +863,7 @@ class NavigationController extends GetxController {
await clearRoute(isNewRoute: true);
if (isStyleLoaded && mapController != null) {
// Destination Marker (B)
destinationSymbol = await mapController!.addSymbol(SymbolOptions(
geometry: destination,
iconImage: 'dest_icon',
@@ -748,6 +871,15 @@ class NavigationController extends GetxController {
textField: infoWindowTitle,
textOffset: const Offset(0, 2),
));
// Start Marker (A)
if (myLocation != null) {
originSymbol = await mapController!.addSymbol(SymbolOptions(
geometry: myLocation,
iconImage: 'start_icon',
iconSize: 1.0,
));
}
}
if (myLocation != null) await getRoute(myLocation!, destination);
@@ -777,6 +909,10 @@ class NavigationController extends GetxController {
await mapController!.removeSymbol(destinationSymbol!);
destinationSymbol = null;
}
if (originSymbol != null && mapController != null) {
await mapController!.removeSymbol(originSymbol!);
originSymbol = null;
}
if (remainingRouteLine != null && mapController != null) {
await mapController!.removeLine(remainingRouteLine!);
remainingRouteLine = null;
@@ -807,8 +943,11 @@ class NavigationController extends GetxController {
Future<void> _loadCustomIcons() async {
if (mapController == null) return;
final carBytes = await rootBundle.load('assets/images/car.png');
final startBytes = await rootBundle.load('assets/images/A.png');
final destBytes = await rootBundle.load('assets/images/b.png');
await mapController!.addImage('car_icon', carBytes.buffer.asUint8List());
await mapController!.addImage('start_icon', startBytes.buffer.asUint8List());
await mapController!.addImage('dest_icon', destBytes.buffer.asUint8List());
}

View File

@@ -7,12 +7,22 @@ import 'package:maplibre_gl/maplibre_gl.dart';
import 'navigation_controller.dart';
// ─── Brand colours ───────────────────────────────────────────────────────────
const Color _kBlue = Color(0xFF1A73E8);
const Color _kBlueDark = Color(0xFF0D47A1);
const Color _kSurface = Color(0xFFFFFFFF);
const Color _kText = Color(0xFF1C1C1E);
const Color _kSubtext = Color(0xFF6B7280);
const Color _kGreen = Color(0xFF34A853);
// ─── Theme-aware Brand colours ──────────────────────────────────────────────
Color get _kBlue => const Color(0xFF1A73E8);
Color get _kBlueDark => const Color(0xFF0D47A1);
Color get _kSurface =>
Get.isDarkMode ? const Color(0xFF1E1E1E) : const Color(0xFFFFFFFF);
Color get _kText =>
Get.isDarkMode ? const Color(0xFFF5F5F7) : const Color(0xFF1C1C1E);
Color get _kSubtext =>
Get.isDarkMode ? Colors.white60 : const Color(0xFF6B7280);
Color get _kGreen => const Color(0xFF34A853);
Color get _kGlassSurface => Get.isDarkMode
? Colors.black.withOpacity(0.7)
: Colors.white.withOpacity(0.92);
Color get _kGlassBorder => Get.isDarkMode
? Colors.white.withOpacity(0.12)
: Colors.white.withOpacity(0.5);
class NavigationView extends StatelessWidget {
const NavigationView({super.key});
@@ -33,7 +43,9 @@ class NavigationView extends StatelessWidget {
onMapCreated: c.onMapCreated,
onStyleLoadedCallback: c.onStyleLoaded,
onMapLongClick: c.onMapLongPressed,
styleString: "assets/style.json",
styleString: Get.isDarkMode
? "assets/style_dark.json"
: "assets/style.json",
initialCameraPosition: CameraPosition(
target: c.myLocation ?? const LatLng(33.5138, 36.2765),
zoom: 16.0,
@@ -106,7 +118,7 @@ class _SearchBar extends StatelessWidget {
controller: controller.placeDestinationController,
onChanged: controller.onSearchChanged,
textInputAction: TextInputAction.search,
style: const TextStyle(
style: TextStyle(
fontSize: 16,
color: _kText,
fontWeight: FontWeight.w500),
@@ -167,8 +179,10 @@ class _SearchResults extends StatelessWidget {
physics: const BouncingScrollPhysics(),
padding: EdgeInsets.zero,
itemCount: controller.placesDestination.length,
separatorBuilder: (_, __) =>
Divider(height: 1, color: Colors.grey[100], indent: 56),
separatorBuilder: (_, __) => Divider(
height: 1,
color: Get.isDarkMode ? Colors.white12 : Colors.grey[100],
indent: 56),
itemBuilder: (_, i) {
final place = controller.placesDestination[i];
final dist = place['distanceKm'] as double?;
@@ -187,8 +201,8 @@ class _SearchResults extends StatelessWidget {
color: _kBlue.withOpacity(0.08),
shape: BoxShape.circle,
),
child: const Icon(Icons.place_rounded,
color: _kBlue, size: 18),
child:
Icon(Icons.place_rounded, color: _kBlue, size: 18),
),
const SizedBox(width: 12),
Expanded(
@@ -196,7 +210,7 @@ class _SearchResults extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(place['name'] ?? '',
style: const TextStyle(
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 14.5,
color: _kText),
@@ -222,7 +236,7 @@ class _SearchResults extends StatelessWidget {
),
child: Text(
'${dist.toStringAsFixed(1)} كم',
style: const TextStyle(
style: TextStyle(
color: _kBlue,
fontSize: 12,
fontWeight: FontWeight.w600),
@@ -259,11 +273,14 @@ class _TurnBanner extends StatelessWidget {
padding: const EdgeInsets.fromLTRB(12, 10, 12, 0),
child: Container(
decoration: BoxDecoration(
color: _kBlueDark,
color: Get.isDarkMode
? Colors.grey[900]?.withOpacity(0.95)
: _kBlueDark,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: _kBlueDark.withOpacity(0.35),
color: (Get.isDarkMode ? Colors.black : _kBlueDark)
.withOpacity(0.35),
blurRadius: 20,
offset: const Offset(0, 6)),
],
@@ -274,14 +291,14 @@ class _TurnBanner extends StatelessWidget {
children: [
// Turn arrow icon
Container(
width: 52,
height: 52,
width: 64,
height: 64,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.15),
borderRadius: BorderRadius.circular(14),
borderRadius: BorderRadius.circular(16),
),
child: const Icon(Icons.turn_right_rounded,
color: Colors.white, size: 30),
color: Colors.white, size: 40),
),
const SizedBox(width: 14),
@@ -293,16 +310,16 @@ class _TurnBanner extends StatelessWidget {
Text(
controller.distanceToNextStep,
style: const TextStyle(
color: Colors.white70,
fontSize: 13,
fontWeight: FontWeight.w500),
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.w600),
),
const SizedBox(height: 2),
const SizedBox(height: 4),
Text(
controller.currentInstruction,
style: const TextStyle(
color: Colors.white,
fontSize: 19,
fontSize: 26,
fontWeight: FontWeight.bold,
height: 1.2),
maxLines: 2,
@@ -429,7 +446,7 @@ class _RouteSummaryCard extends StatelessWidget {
left: 0,
right: 0,
child: Container(
decoration: const BoxDecoration(
decoration: BoxDecoration(
color: _kSurface,
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
boxShadow: [
@@ -520,20 +537,20 @@ class _InfoPill extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
decoration: BoxDecoration(
color: color.withOpacity(0.08),
borderRadius: BorderRadius.circular(12),
borderRadius: BorderRadius.circular(14),
border: Border.all(color: color.withOpacity(0.2)),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, color: color, size: 15),
const SizedBox(width: 5),
Icon(icon, color: color, size: 22),
const SizedBox(width: 8),
Text(label,
style: TextStyle(
color: color, fontSize: 13.5, fontWeight: FontWeight.w700)),
color: color, fontSize: 18, fontWeight: FontWeight.w800)),
],
),
);
@@ -577,22 +594,27 @@ class _NavigationHUD extends StatelessWidget {
padding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration(
color: const Color(0xFFF8F9FA),
color: Get.isDarkMode
? Colors.white.withOpacity(0.05)
: const Color(0xFFF8F9FA),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.grey.withOpacity(0.15)),
border: Border.all(
color: Get.isDarkMode
? Colors.white10
: Colors.grey.withOpacity(0.15)),
),
child: Row(
children: [
Icon(Icons.arrow_forward_rounded,
size: 15, color: _kSubtext),
const SizedBox(width: 8),
size: 20, color: _kSubtext),
const SizedBox(width: 10),
Expanded(
child: Text(
controller.nextInstruction,
style: TextStyle(
color: _kSubtext,
fontSize: 13,
fontWeight: FontWeight.w500),
color: _kText,
fontSize: 16,
fontWeight: FontWeight.bold),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
@@ -636,13 +658,13 @@ class _NavigationHUD extends StatelessWidget {
child: Row(
children: [
const Icon(Icons.stop_rounded,
color: Colors.redAccent, size: 16),
const SizedBox(width: 5),
color: Colors.redAccent, size: 24),
const SizedBox(width: 6),
const Text('إيقاف',
style: TextStyle(
color: Colors.redAccent,
fontSize: 13,
fontWeight: FontWeight.w700)),
fontSize: 18,
fontWeight: FontWeight.bold)),
],
),
),
@@ -669,44 +691,61 @@ class _SpeedBadge extends StatelessWidget {
final bool fast = kmh > 100;
return Positioned(
bottom: MediaQuery.of(context).padding.bottom + 130,
left: 14,
child: Container(
width: 62,
height: 62,
decoration: BoxDecoration(
color: fast ? const Color(0xFFD93025) : _kSurface,
shape: BoxShape.circle,
border: Border.all(
color: fast ? Colors.red.withOpacity(0.3) : Colors.grey[200]!,
width: 2),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.12),
blurRadius: 12,
offset: const Offset(0, 4)),
],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'$kmh',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: fast ? Colors.white : _kText,
height: 1),
bottom: MediaQuery.of(context).padding.bottom + 150,
left: 16,
child: Stack(
alignment: Alignment.center,
children: [
// Circular progress mimicking a speedometer
SizedBox(
width: 86,
height: 86,
child: CircularProgressIndicator(
value: (kmh / 140.0)
.clamp(0.0, 1.0), // Assuming 140 is max speed shown
strokeWidth: 6,
backgroundColor: Get.isDarkMode
? Colors.white10
: Colors.grey.withOpacity(0.3),
valueColor: AlwaysStoppedAnimation<Color>(
fast ? Colors.redAccent : _kBlue),
),
Text(
'كم/س',
style: TextStyle(
fontSize: 9,
color: fast ? Colors.white70 : _kSubtext,
fontWeight: FontWeight.w500),
),
Container(
width: 74,
height: 74,
decoration: BoxDecoration(
color: fast ? const Color(0xFFD93025) : _kSurface,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.15),
blurRadius: 16,
offset: const Offset(0, 6)),
],
),
],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'$kmh',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.w900,
color: fast ? Colors.white : _kText,
height: 1),
),
Text(
'كم/س',
style: TextStyle(
fontSize: 13,
color: fast ? Colors.white70 : _kSubtext,
fontWeight: FontWeight.w600),
),
],
),
),
],
),
);
}
@@ -735,7 +774,7 @@ class _LoadingOverlay extends StatelessWidget {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const CircularProgressIndicator(
CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation(_kBlue),
strokeWidth: 3,
),
@@ -777,14 +816,14 @@ class _GlassCard extends StatelessWidget {
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.92),
color: _kGlassSurface,
borderRadius: BorderRadius.circular(borderRadius),
border: Border.all(color: Colors.white.withOpacity(0.5)),
border: Border.all(color: _kGlassBorder),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.07),
color: Colors.black.withOpacity(Get.isDarkMode ? 0.4 : 0.07),
blurRadius: 16,
offset: const Offset(0, 4)),
offset: const Offset(0, 8)),
],
),
padding: padding,

View File

@@ -8,13 +8,11 @@ import 'package:http/http.dart' as http;
import 'package:Intaleq/constant/api_key.dart';
import 'package:Intaleq/constant/box_name.dart';
import 'package:Intaleq/constant/colors.dart';
import 'package:Intaleq/constant/links.dart';
import 'package:Intaleq/controller/profile/profile_controller.dart';
import 'package:Intaleq/main.dart';
import 'package:Intaleq/views/widgets/elevated_btn.dart';
import 'package:Intaleq/views/widgets/my_textField.dart';
import 'package:Intaleq/views/widgets/mycircular.dart';
import '../../../constant/style.dart';
import '../../../controller/functions/log_out.dart';
// ─────────────────────────────────────────────────────────────────────────────
@@ -134,7 +132,7 @@ class _PassengerProfilePageState extends State<PassengerProfilePage> {
width: 40,
height: 4,
decoration: BoxDecoration(
color: Colors.grey[300],
color: AppColor.grayColor.withOpacity(0.3),
borderRadius: BorderRadius.circular(2)),
),
const SizedBox(height: 8),
@@ -182,14 +180,14 @@ class _PassengerProfilePageState extends State<PassengerProfilePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF4F6F9),
backgroundColor: AppColor.secondaryColor.withOpacity(0.96),
appBar: AppBar(
title: Text('My Profile'.tr,
style: const TextStyle(fontWeight: FontWeight.w700, fontSize: 20)),
backgroundColor: const Color(0xFFF4F6F9),
style: AppStyle.headTitle2.copyWith(fontSize: 20)),
backgroundColor: AppColor.secondaryColor,
elevation: 0,
centerTitle: true,
iconTheme: const IconThemeData(color: Colors.black87),
iconTheme: IconThemeData(color: AppColor.writeColor),
),
body: GetBuilder<ProfileController>(
builder: (controller) {
@@ -373,7 +371,7 @@ class _PassengerProfilePageState extends State<PassengerProfilePage> {
),
child: CircleAvatar(
radius: 52,
backgroundColor: Colors.grey[100],
backgroundColor: AppColor.secondaryColor,
child: ClipOval(
child: _isUploadingImage
? const SizedBox(
@@ -445,7 +443,8 @@ class _PassengerProfilePageState extends State<PassengerProfilePage> {
decoration: BoxDecoration(
color: AppColor.primaryColor,
shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 2.5),
border:
Border.all(color: AppColor.secondaryColor, width: 2.5),
boxShadow: [
BoxShadow(
color: AppColor.primaryColor.withOpacity(0.4),
@@ -470,10 +469,10 @@ class _PassengerProfilePageState extends State<PassengerProfilePage> {
children: [
Text(
fullName.isEmpty ? 'Passenger'.tr : fullName,
style: const TextStyle(
fontSize: 22,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.black87,
color: AppColor.writeColor,
),
),
const SizedBox(width: 6),
@@ -497,8 +496,8 @@ class _PassengerProfilePageState extends State<PassengerProfilePage> {
Text(
email,
style: TextStyle(
fontSize: 13,
color: Colors.grey[500],
fontSize: 14,
color: AppColor.grayColor,
fontWeight: FontWeight.w500),
),
],
@@ -546,18 +545,18 @@ class _PassengerProfilePageState extends State<PassengerProfilePage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(left: 4, bottom: 10),
padding: const EdgeInsets.only(left: 8, bottom: 12),
child: Row(
children: [
Icon(sectionIcon, size: 14, color: Colors.grey[500]),
const SizedBox(width: 6),
Icon(sectionIcon, size: 15, color: AppColor.grayColor),
const SizedBox(width: 8),
Text(
title.toUpperCase(),
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w700,
color: Colors.grey[500],
letterSpacing: 1.3,
fontSize: 15,
fontWeight: FontWeight.bold,
color: AppColor.grayColor,
letterSpacing: 1.2,
),
),
],
@@ -565,11 +564,13 @@ class _PassengerProfilePageState extends State<PassengerProfilePage> {
),
Container(
decoration: BoxDecoration(
color: Colors.white,
color: AppColor.secondaryColor,
borderRadius: BorderRadius.circular(18),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.04),
color: Get.isDarkMode
? Colors.black.withOpacity(0.2)
: Colors.black.withOpacity(0.04),
blurRadius: 12,
offset: const Offset(0, 4),
),
@@ -611,30 +612,34 @@ class _PassengerProfilePageState extends State<PassengerProfilePage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title,
style: const TextStyle(
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 14.5,
color: Colors.black87)),
fontSize: 16,
color: AppColor.writeColor)),
if (subtitle.isNotEmpty) ...[
const SizedBox(height: 3),
const SizedBox(height: 4),
Text(subtitle,
style:
TextStyle(color: Colors.grey[500], fontSize: 12.5)),
TextStyle(color: AppColor.grayColor, fontSize: 13)),
],
],
),
),
trailing ??
Icon(Icons.arrow_forward_ios_rounded,
size: 13, color: Colors.grey[350]),
size: 14, color: AppColor.grayColor.withOpacity(0.5)),
],
),
),
);
}
Widget _divider() =>
Divider(height: 1, thickness: 1, indent: 72, color: Colors.grey[100]);
Widget _divider() => Divider(
height: 1,
thickness: 1,
indent: 72,
endIndent: 16,
color: AppColor.grayColor.withOpacity(0.1));
// ─── Bottom Sheets ───────────────────────────────────────────────────────────
@@ -808,7 +813,8 @@ class _PassengerProfilePageState extends State<PassengerProfilePage> {
Expanded(
child: Text(
'This action is permanent and cannot be undone.'.tr,
style: TextStyle(color: Colors.red[700], fontSize: 13),
style: TextStyle(
color: Colors.red.withOpacity(0.8), fontSize: 13),
),
),
],
@@ -838,7 +844,7 @@ class _PassengerProfilePageState extends State<PassengerProfilePage> {
side: BorderSide(color: Colors.grey[300]!),
),
child: Text('Cancel'.tr,
style: TextStyle(color: Colors.grey[600])),
style: TextStyle(color: AppColor.grayColor)),
),
),
const SizedBox(width: 12),
@@ -895,27 +901,29 @@ class _PassengerProfilePageState extends State<PassengerProfilePage> {
return TextField(
controller: controller,
keyboardType: type,
style: const TextStyle(fontSize: 15, color: Colors.black87),
style: TextStyle(fontSize: 16, color: AppColor.writeColor),
decoration: InputDecoration(
labelText: label,
hintText: hint,
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 13),
prefixIcon: Icon(icon, size: 20, color: Colors.grey[500]),
hintStyle:
TextStyle(color: AppColor.grayColor.withOpacity(0.5), fontSize: 14),
prefixIcon: Icon(icon, size: 20, color: AppColor.grayColor),
filled: true,
fillColor: const Color(0xFFF8F9FA),
fillColor: AppColor.secondaryColor,
contentPadding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 15),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(13),
borderSide: BorderSide(color: Colors.grey[200]!)),
borderSide:
BorderSide(color: AppColor.grayColor.withOpacity(0.15))),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(13),
borderSide: BorderSide(color: Colors.grey[200]!)),
borderSide:
BorderSide(color: AppColor.grayColor.withOpacity(0.15))),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(13),
borderSide:
const BorderSide(color: AppColor.primaryColor, width: 1.5)),
labelStyle: TextStyle(color: Colors.grey[500], fontSize: 13),
borderSide: BorderSide(color: AppColor.primaryColor, width: 1.5)),
labelStyle: TextStyle(color: AppColor.grayColor, fontSize: 14),
),
);
}
@@ -971,7 +979,8 @@ class _PassengerProfilePageState extends State<PassengerProfilePage> {
title: Text(label,
style: TextStyle(
fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
color: isSelected ? AppColor.primaryColor : Colors.black87)),
fontSize: 16,
color: isSelected ? AppColor.primaryColor : AppColor.writeColor)),
);
}
}
@@ -1001,9 +1010,9 @@ class _SheetWrapper extends StatelessWidget {
24,
MediaQuery.of(context).viewInsets.bottom + 28,
),
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(26)),
decoration: BoxDecoration(
color: AppColor.secondaryColor,
borderRadius: const BorderRadius.vertical(top: Radius.circular(26)),
),
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
@@ -1018,7 +1027,7 @@ class _SheetWrapper extends StatelessWidget {
height: 4,
margin: const EdgeInsets.only(bottom: 20),
decoration: BoxDecoration(
color: Colors.grey[250],
color: AppColor.grayColor.withOpacity(0.3),
borderRadius: BorderRadius.circular(2),
),
),
@@ -1038,10 +1047,10 @@ class _SheetWrapper extends StatelessWidget {
const SizedBox(width: 12),
Text(
title,
style: const TextStyle(
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black87,
color: AppColor.writeColor,
),
),
],

View File

@@ -1,4 +1,7 @@
import 'package:Intaleq/controller/home/home_page_controller.dart';
import 'package:Intaleq/controller/local/local_controller.dart';
import 'package:Intaleq/constant/colors.dart';
import 'package:Intaleq/constant/style.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:Intaleq/views/lang/languages.dart';
@@ -32,16 +35,14 @@ class SettingPage extends StatelessWidget {
Get.lazyPut(() => HomePageController());
return Scaffold(
backgroundColor:
const Color(0xFFF5F5F7), // A slightly off-white background
backgroundColor: AppColor.secondaryColor.withOpacity(0.94),
appBar: AppBar(
title: Text('Setting'.tr,
style: const TextStyle(
color: Colors.black87, fontWeight: FontWeight.bold)),
backgroundColor: Colors.white,
style: AppStyle.headTitle2.copyWith(fontSize: 20)),
backgroundColor: AppColor.secondaryColor,
elevation: 0.5,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new, color: Colors.black87),
icon: Icon(Icons.arrow_back_ios_new, color: AppColor.writeColor),
onPressed: () => Get.back(),
),
),
@@ -59,14 +60,27 @@ class SettingPage extends StatelessWidget {
subtitle: 'To change Language the App'.tr,
onTap: () => Get.to(() => const Language()),
),
// const Divider(height: 1, indent: 68, endIndent: 16),
// _buildSettingsTile(
// icon: Icons.map_outlined,
// color: Colors.green,
// title: 'Change Country'.tr,
// subtitle: 'You can change the Country to get all features'.tr,
// onTap: () => Get.to(() => const CountryPickerFromSetting()),
// ),
Divider(
height: 1,
indent: 68,
endIndent: 16,
color: AppColor.grayColor.withOpacity(0.1)),
GetBuilder<LocaleController>(
builder: (localeController) {
return _buildSettingsTile(
icon: Icons.palette_outlined,
color: Colors.deepPurpleAccent,
title: 'Appearance'.tr,
subtitle: (localeController.themeMode == ThemeMode.system
? 'System Default'.tr
: localeController.themeMode == ThemeMode.dark
? 'Dark Mode'.tr
: 'Light Mode'.tr)
.tr,
onTap: () => _showThemeSheet(context, localeController),
);
},
),
],
),
const SizedBox(height: 24),
@@ -136,7 +150,7 @@ class SettingPage extends StatelessWidget {
child: Text(
title,
style: TextStyle(
color: Colors.grey[700],
color: AppColor.grayColor,
fontWeight: FontWeight.bold,
fontSize: 15,
),
@@ -144,11 +158,73 @@ class SettingPage extends StatelessWidget {
);
}
void _showThemeSheet(BuildContext context, LocaleController controller) {
final options = [
{'label': 'System Default'.tr, 'mode': ThemeMode.system},
{'label': 'Light Mode'.tr, 'mode': ThemeMode.light},
{'label': 'Dark Mode'.tr, 'mode': ThemeMode.dark},
];
Get.bottomSheet(
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: AppColor.secondaryColor,
borderRadius: const BorderRadius.vertical(top: Radius.circular(20)),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 40,
height: 4,
margin: const EdgeInsets.only(bottom: 20),
decoration: BoxDecoration(
color: AppColor.grayColor.withOpacity(0.3),
borderRadius: BorderRadius.circular(2),
),
),
Text('Select Appearance'.tr,
style: AppStyle.headTitle2.copyWith(fontSize: 18)),
const SizedBox(height: 20),
...options.map((opt) {
final isSelected = controller.themeMode == opt['mode'];
return ListTile(
title: Text(opt['label'] as String,
style: TextStyle(
color: isSelected
? AppColor.primaryColor
: AppColor.writeColor,
fontWeight:
isSelected ? FontWeight.bold : FontWeight.normal)),
trailing: isSelected
? Icon(Icons.check_circle, color: AppColor.primaryColor)
: null,
onTap: () {
Get.back();
controller.changeThemeMode(opt['mode'] as ThemeMode);
},
);
}).toList(),
const SizedBox(height: 20),
],
),
),
);
}
Widget _buildSettingsCard({required List<Widget> children}) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
color: AppColor.secondaryColor,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 4),
)
],
),
clipBehavior: Clip.antiAlias,
child: Column(
@@ -175,10 +251,14 @@ class SettingPage extends StatelessWidget {
child: Icon(icon, color: color, size: 22),
),
title: Text(title,
style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 16)),
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 16,
color: AppColor.writeColor)),
subtitle: Text(subtitle,
style: TextStyle(color: Colors.grey[600], fontSize: 13)),
trailing: Icon(Icons.chevron_right, color: Colors.grey[400]),
style: TextStyle(color: AppColor.grayColor, fontSize: 13)),
trailing:
Icon(Icons.chevron_right, color: AppColor.grayColor.withOpacity(0.5)),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
);
}
@@ -201,9 +281,12 @@ class SettingPage extends StatelessWidget {
child: Icon(icon, color: color, size: 22),
),
title: Text(title,
style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 16)),
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 16,
color: AppColor.writeColor)),
subtitle: Text(subtitle,
style: TextStyle(color: Colors.grey[600], fontSize: 13)),
style: TextStyle(color: AppColor.grayColor, fontSize: 13)),
value: value,
onChanged: onChanged,
activeColor: const Color(0xFF007AFF), // iOS-like blue

View File

@@ -6,14 +6,14 @@ import 'mydialoug.dart';
class MyCircleContainer extends StatelessWidget {
final Widget child;
final Color backgroundColor;
final Color borderColor;
final Color? backgroundColor;
final Color? borderColor;
MyCircleContainer({
Key? key,
required this.child,
this.backgroundColor = AppColor.secondaryColor,
this.borderColor = AppColor.accentColor,
this.backgroundColor,
this.borderColor,
}) : super(key: key);
final controller = Get.put(CircleController());
@@ -40,9 +40,9 @@ class MyCircleContainer extends StatelessWidget {
height: controller.size,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: controller.backgroundColor,
color: controller.isAccented ? AppColor.accentColor : (backgroundColor ?? AppColor.secondaryColor),
border: Border.all(
color: borderColor,
color: borderColor ?? AppColor.accentColor,
width: 1,
),
),
@@ -53,12 +53,10 @@ class MyCircleContainer extends StatelessWidget {
}
class CircleController extends GetxController {
Color backgroundColor = AppColor.secondaryColor;
bool isAccented = false;
double size = 40;
void changeColor() {
backgroundColor = backgroundColor == AppColor.secondaryColor
? AppColor.accentColor
: AppColor.secondaryColor;
isAccented = !isAccented;
size = 60;
update();
}

View File

@@ -26,18 +26,18 @@ class IconWidgetMenu extends StatelessWidget {
children: [
Container(
width: 40,
decoration: const BoxDecoration(
decoration: BoxDecoration(
color: AppColor.secondaryColor,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: AppColor.secondaryColor,
offset: Offset(-2, -2),
offset: const Offset(-2, -2),
blurRadius: 0,
spreadRadius: 0,
blurStyle: BlurStyle.outer,
),
BoxShadow(
const BoxShadow(
color: AppColor.accentColor,
offset: Offset(3, 3),
blurRadius: 0,

View File

@@ -1,6 +1,7 @@
import 'dart:async';
import 'package:flutter/material.dart';
import '../../constant/style.dart';
import 'package:get/get.dart';
import '../../constant/colors.dart';
class MyCircularProgressIndicatorWithTimer extends StatefulWidget {
final Color backgroundColor;
@@ -8,7 +9,7 @@ class MyCircularProgressIndicatorWithTimer extends StatefulWidget {
const MyCircularProgressIndicatorWithTimer({
Key? key,
this.backgroundColor = Colors.white,
this.backgroundColor = Colors.transparent,
required this.isLoading,
}) : super(key: key);
@@ -88,7 +89,7 @@ class _MyCircularProgressIndicatorWithTimerState
height: 200,
decoration: BoxDecoration(
color: widget.backgroundColor == Colors.transparent
? Colors.white.withOpacity(0.96)
? AppColor.secondaryColor.withOpacity(0.96)
: widget.backgroundColor,
shape: BoxShape.circle,
boxShadow: [
@@ -110,7 +111,9 @@ class _MyCircularProgressIndicatorWithTimerState
child: CircularProgressIndicator(
value: progress,
strokeWidth: 6,
backgroundColor: Colors.grey.shade100,
backgroundColor: Get.isDarkMode
? Colors.grey.shade800
: Colors.grey.shade100,
valueColor: AlwaysStoppedAnimation<Color>(timerColor),
strokeCap: StrokeCap.round,
),
@@ -139,9 +142,8 @@ class _MyCircularProgressIndicatorWithTimerState
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.w600,
color: _isLowTime
? Colors.orangeAccent
: Colors.blueGrey.shade800,
color:
_isLowTime ? Colors.orangeAccent : AppColor.writeColor,
letterSpacing: 1.2,
fontFeatures: const [FontFeature.tabularFigures()],
),

View File

@@ -9,16 +9,13 @@ class MyScafolld extends StatelessWidget {
super.key,
required this.title,
required this.body,
this.action = const Icon(
Icons.clear,
color: AppColor.secondaryColor,
),
this.action,
required this.isleading,
});
final String title;
final List<Widget> body;
final Widget action;
final Widget? action;
final bool isleading;
@override
@@ -33,13 +30,18 @@ class MyScafolld extends StatelessWidget {
onPressed: () {
Get.back();
},
icon: const Icon(
icon: Icon(
Icons.arrow_back_ios_new,
color: AppColor.primaryColor,
),
)
: const SizedBox(),
actions: [action],
actions: [
action ?? Icon(
Icons.clear,
color: AppColor.secondaryColor,
)
],
title: Text(
title,
style: AppStyle.title.copyWith(fontSize: 30),

View File

@@ -62,8 +62,8 @@ class _GlassCard extends StatelessWidget {
borderRadius: BorderRadius.circular(_DC.radius),
gradient: LinearGradient(
colors: [
Colors.white.withOpacity(0.95),
Colors.white.withOpacity(0.88),
AppColor.secondaryColor.withOpacity(0.95),
AppColor.secondaryColor.withOpacity(0.88),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
@@ -82,7 +82,7 @@ class _GlassCard extends StatelessWidget {
),
],
border: Border.all(
color: Colors.white.withOpacity(0.6),
color: AppColor.secondaryColor.withOpacity(0.6),
width: 1.2,
),
),
@@ -247,7 +247,7 @@ class _SpeakButtonState extends State<_SpeakButton>
setState(() => _speaking = true);
_pulse.repeat(reverse: true);
final tts = Get.put(TextToSpeechController());
final tts = Get.find<TextToSpeechController>();
for (final t in widget.texts) {
await tts.speakText(t);
}
@@ -367,7 +367,7 @@ class MyDialog extends GetxController {
fontSize: 18,
fontWeight: FontWeight.w700,
letterSpacing: -0.4,
color: Colors.black87,
color: AppColor.writeColor,
),
),
@@ -467,7 +467,7 @@ class MyDialogContent extends GetxController {
fontSize: 17,
fontWeight: FontWeight.w700,
letterSpacing: -0.3,
color: Colors.black87,
color: AppColor.writeColor,
),
),
),