2026-03-10-1
This commit is contained in:
@@ -1,234 +1,237 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sefer_admin1/constant/box_name.dart';
|
||||
import 'package:sefer_admin1/constant/links.dart';
|
||||
import 'package:sefer_admin1/controller/firebase/firbase_messge.dart';
|
||||
import 'package:sefer_admin1/controller/functions/crud.dart';
|
||||
import 'package:sefer_admin1/main.dart';
|
||||
import 'package:sefer_admin1/views/widgets/elevated_btn.dart';
|
||||
import 'package:sefer_admin1/views/widgets/my_textField.dart';
|
||||
|
||||
import '../constant/style.dart';
|
||||
import '../print.dart';
|
||||
import 'firebase/notification_service.dart';
|
||||
|
||||
class NotificationController extends GetxController {
|
||||
final formKey = GlobalKey<FormState>();
|
||||
final title = TextEditingController();
|
||||
final body = TextEditingController();
|
||||
List<String> tokensDriver = [];
|
||||
List<String> tokensPassengers = [];
|
||||
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
||||
final TextEditingController titleController = TextEditingController();
|
||||
final TextEditingController bodyController = TextEditingController();
|
||||
|
||||
// getTokensDrivers() async {
|
||||
// await FirebaseMessagesController().loadAllPagesAndSendNotifications();
|
||||
// }
|
||||
// ألوان الثيم (متناسقة مع باقي الصفحات المحسنة)
|
||||
final Color _dialogColor = const Color(0xFF1A1F3A);
|
||||
final Color _inputColor = const Color(0xFF0A0E27);
|
||||
final Color _primaryAccent = const Color(0xFF6366F1);
|
||||
|
||||
// getTokensPassengers() async {
|
||||
// await FirebaseMessagesController()
|
||||
// .loadAllPagesAndSendNotificationsPassengers();
|
||||
// }
|
||||
|
||||
Future<dynamic> sendNotificationDrivers() {
|
||||
return Get.defaultDialog(
|
||||
title: 'send notification'.tr,
|
||||
titleStyle: AppStyle.title,
|
||||
content: Form(
|
||||
key: formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: MyTextForm(
|
||||
controller: title,
|
||||
label: 'title notification'.tr,
|
||||
hint: 'title notification'.tr,
|
||||
type: TextInputType.name),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: MyTextForm(
|
||||
controller: body,
|
||||
label: 'body notification'.tr,
|
||||
hint: 'body notification'.tr,
|
||||
type: TextInputType.name),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'send'.tr,
|
||||
onPressed: () async {
|
||||
// tokensDriver = box.read(BoxName.tokensDrivers)['message'];
|
||||
// Log.print('tokensDriver: ${tokensDriver}');
|
||||
// if (formKey.currentState!.validate()) {
|
||||
// box.read(BoxName.tokensDrivers)['message'].length;
|
||||
// for (var i = 0;
|
||||
// i < box.read(BoxName.tokensDrivers)['message'].length;
|
||||
// i++) {
|
||||
// // for (var i = 0; i < 2; i++) {
|
||||
// // print(i);
|
||||
// var res = await CRUD()
|
||||
// .post(link: AppLink.addNotificationCaptain, payload: {
|
||||
// "driverID": box
|
||||
// .read(BoxName.tokensDrivers)['message'][i]['id']
|
||||
// .toString(),
|
||||
// "title": title.text,
|
||||
// "body": body.text,
|
||||
// "isPin": 'unPin',
|
||||
// });
|
||||
// Log.print(
|
||||
// 'res: ${res}for ${box.read(BoxName.tokensDrivers)['message'][i]['id']}');
|
||||
// // Log.print('tokensDriver[i]: ${tokensDriver[i]}');
|
||||
// Future.delayed(const Duration(microseconds: 50));
|
||||
NotificationService.sendNotification(
|
||||
target: 'drivers', // الإرسال لجميع المشتركين في "service"
|
||||
title: title.text,
|
||||
body: body.text,
|
||||
isTopic: true,
|
||||
category: 'fromAdmin', // فئة توضح نوع الإشعار
|
||||
);
|
||||
// FirebaseMessagesController().sendNotificationToAnyWithoutData(
|
||||
// title.text,
|
||||
// body.text,
|
||||
// box
|
||||
// .read(BoxName.tokensDrivers)['message'][i]['token']
|
||||
// .toString(),
|
||||
// 'tone2.wav');
|
||||
// }
|
||||
Get.back();
|
||||
// }
|
||||
}),
|
||||
cancel: MyElevatedButton(
|
||||
title: 'cancel',
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
}));
|
||||
@override
|
||||
void onClose() {
|
||||
titleController.dispose();
|
||||
bodyController.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
Future<dynamic> sendNotificationPassengers() {
|
||||
return Get.defaultDialog(
|
||||
title: 'send notification'.tr,
|
||||
titleStyle: AppStyle.title,
|
||||
content: Form(
|
||||
key: formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: MyTextForm(
|
||||
controller: title,
|
||||
label: 'title notification'.tr,
|
||||
hint: 'title notification'.tr,
|
||||
type: TextInputType.name),
|
||||
/// تنظيف الحقول
|
||||
void _clearFields() {
|
||||
titleController.clear();
|
||||
bodyController.clear();
|
||||
}
|
||||
|
||||
/// إرسال إشعار للسائقين
|
||||
Future<void> sendNotificationDrivers() async {
|
||||
_clearFields();
|
||||
await _showCustomDialog(
|
||||
dialogTitle: 'إشعار للسائقين',
|
||||
targetAudience: 'drivers',
|
||||
icon: Icons.drive_eta_rounded,
|
||||
iconColor: Colors.orangeAccent,
|
||||
);
|
||||
}
|
||||
|
||||
/// إرسال إشعار للركاب
|
||||
Future<void> sendNotificationPassengers() async {
|
||||
_clearFields();
|
||||
await _showCustomDialog(
|
||||
dialogTitle: 'إشعار للركاب',
|
||||
targetAudience: 'passengers',
|
||||
icon: Icons.people_alt_rounded,
|
||||
iconColor: Colors.blueAccent,
|
||||
);
|
||||
}
|
||||
|
||||
/// دالة عامة لإظهار نافذة الإرسال بتصميم عصري
|
||||
Future<void> _showCustomDialog({
|
||||
required String dialogTitle,
|
||||
required String targetAudience,
|
||||
required IconData icon,
|
||||
required Color iconColor,
|
||||
}) {
|
||||
return Get.dialog(
|
||||
Dialog(
|
||||
backgroundColor: _dialogColor,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||||
elevation: 10,
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Form(
|
||||
key: formKey,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// 1. أيقونة العنوان
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: iconColor.withOpacity(0.15),
|
||||
shape: BoxShape.circle,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: iconColor.withOpacity(0.1),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Icon(icon, color: iconColor, size: 32),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 2. العنوان
|
||||
Text(
|
||||
dialogTitle,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Segoe UI',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// 3. حقول الإدخال
|
||||
_buildModernTextField(
|
||||
controller: titleController,
|
||||
hint: 'عنوان الإشعار',
|
||||
icon: Icons.title_rounded,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_buildModernTextField(
|
||||
controller: bodyController,
|
||||
hint: 'نص الرسالة',
|
||||
icon: Icons.message_rounded,
|
||||
maxLines: 3,
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
|
||||
// 4. الأزرار
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextButton(
|
||||
onPressed: () => Get.back(),
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: Colors.white54,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
),
|
||||
child: const Text('إلغاء'),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
if (titleController.text.trim().isEmpty ||
|
||||
bodyController.text.trim().isEmpty) {
|
||||
Get.snackbar(
|
||||
"تنبيه",
|
||||
"الرجاء تعبئة جميع الحقول",
|
||||
backgroundColor: Colors.amber.withOpacity(0.8),
|
||||
colorText: Colors.white,
|
||||
snackPosition: SnackPosition.TOP,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Get.back(); // إغلاق النافذة
|
||||
await _processSending(targetAudience);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: _primaryAccent,
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
elevation: 0,
|
||||
),
|
||||
child: const Text('إرسال'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: MyTextForm(
|
||||
controller: body,
|
||||
label: 'body notification'.tr,
|
||||
hint: 'body notification'.tr,
|
||||
type: TextInputType.name),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'send'.tr,
|
||||
onPressed: () async {
|
||||
// tokensPassengers = box.read(BoxName.tokensPassengers);
|
||||
// var tokensPassengersData =
|
||||
// box.read(BoxName.tokensPassengers)['data'];
|
||||
),
|
||||
barrierColor: Colors.black.withOpacity(0.7), // تعتيم الخلفية
|
||||
);
|
||||
}
|
||||
|
||||
// // Debug print to check structure of the 'data' field
|
||||
// print('Tokens Passengers Data: $tokensPassengersData');
|
||||
/// تنفيذ عملية الإرسال الفعلية
|
||||
Future<void> _processSending(String target) async {
|
||||
// إظهار تنبيه بدء العملية
|
||||
Get.snackbar(
|
||||
"جاري الإرسال",
|
||||
"يتم إرسال الإشعار لـ $target...",
|
||||
backgroundColor: _primaryAccent.withOpacity(0.2),
|
||||
colorText: Colors.white,
|
||||
duration: const Duration(seconds: 2),
|
||||
);
|
||||
|
||||
// if (tokensPassengersData is List) {
|
||||
// for (var i = 0; i < tokensPassengersData.length; i++) {
|
||||
// if (formKey.currentState!.validate()) {
|
||||
// var res = await CRUD()
|
||||
// .post(link: AppLink.addNotificationPassenger, payload: {
|
||||
// "passenger_id":
|
||||
// tokensPassengersData[i]['passengerID'].toString(),
|
||||
// "title": title.text,
|
||||
// "body": body.text,
|
||||
// });
|
||||
// Log.print('res: ${res}');
|
||||
// FirebaseMessagesController()
|
||||
// .sendNotificationToAnyWithoutData(
|
||||
// title.text,
|
||||
// body.text,
|
||||
// tokensPassengersData[i]['token']
|
||||
// .toString(), // Access token correctly
|
||||
// 'order.wav',
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
NotificationService.sendNotification(
|
||||
target: 'passengers', // الإرسال لجميع المشتركين في "service"
|
||||
title: title.text,
|
||||
body: body.text,
|
||||
isTopic: true,
|
||||
category: 'fromAdmin', // فئة توضح نوع الإشعار
|
||||
);
|
||||
Get.back();
|
||||
// } else {
|
||||
// // Handle the case where 'data' is not a list
|
||||
// print('Data is not a list: $tokensPassengersData');
|
||||
// }
|
||||
}),
|
||||
cancel: MyElevatedButton(
|
||||
title: 'cancel',
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
}));
|
||||
try {
|
||||
// استدعاء خدمة الإرسال
|
||||
await NotificationService.sendNotification(
|
||||
target: target,
|
||||
title: titleController.text,
|
||||
body: bodyController.text,
|
||||
isTopic: true,
|
||||
category: 'fromAdmin',
|
||||
);
|
||||
|
||||
Get.snackbar(
|
||||
"نجاح",
|
||||
"تم إرسال الإشعار بنجاح",
|
||||
backgroundColor: Colors.green.withOpacity(0.5),
|
||||
colorText: Colors.white,
|
||||
);
|
||||
} catch (e) {
|
||||
Get.snackbar(
|
||||
"خطأ",
|
||||
"فشل إرسال الإشعار: $e",
|
||||
backgroundColor: Colors.red.withOpacity(0.5),
|
||||
colorText: Colors.white,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// تصميم حقل الإدخال المخصص (Dark Input Field)
|
||||
Widget _buildModernTextField({
|
||||
required TextEditingController controller,
|
||||
required String hint,
|
||||
required IconData icon,
|
||||
int maxLines = 1,
|
||||
}) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: _inputColor,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: Colors.white.withOpacity(0.1)),
|
||||
),
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
style: const TextStyle(color: Colors.white),
|
||||
maxLines: maxLines,
|
||||
decoration: InputDecoration(
|
||||
hintText: hint,
|
||||
hintStyle:
|
||||
TextStyle(color: Colors.white.withOpacity(0.3), fontSize: 14),
|
||||
prefixIcon: Icon(icon, color: Colors.white38, size: 20),
|
||||
border: InputBorder.none,
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
// يلا دلوقتي! تطبيق سفر جاهز عشان تبدأ تستقبل الطلبات
|
||||
// • افتح التطبيق دلوقتي، واستعد إنك تستقبل طلبات أكتر. كل ما تكون فاتح، فرصتك في الطلبات بتزيد!
|
||||
// 2. خليك فاتح واستقبل طلبات أكتر مع تطبيق سفر
|
||||
// • وجودك متصل في التطبيق هيخليك تستقبل طلبات أكتر. افتح التطبيق دلوقتي وما تفوتش الفرصة!
|
||||
// 3. فرصتك لزيادة دخلك مع تطبيق سفر تبدأ من دلوقتي!
|
||||
// • مجرد إنك تفتح التطبيق مش هيأثر عليك، بالعكس، هيزود فرصتك في طلبات أكتر. افتح التطبيق واشترك دلوقتي!
|
||||
|
||||
//sms
|
||||
// link sefer driver is https://shorturl.at/IHJcm1.
|
||||
// // ميزات الأمان بعد 500 رحلة:
|
||||
// • “بعد 500 رحلة مع سفر، تحصل على مميزات أمان إضافية لضمان راحتك.”
|
||||
// • “نوفر لك ميزات أمان متقدمة بعد 500 رحلة لتجربة قيادة أكثر أمانًا.”
|
||||
// • “مع 500 رحلة، تحصل على دعم أمني متقدم لتوفير أفضل تجربة قيادة.”
|
||||
// 2. ميزات الصيانة:
|
||||
// • “احصل على خدمات صيانة مجانية بعد عدد معين من الرحلات مع سفر.”
|
||||
// • “استمتع بخدمات صيانة حصرية عند الوصول إلى عدد محدد من الرحلات.”
|
||||
// • “مع سفر، نقدم لك عروض صيانة مميزة لتحافظ على سيارتك في أفضل حال.”
|
||||
// 3. ميزات فتح حسابات البنوك:
|
||||
// • “مع سفر، يمكنك فتح حساب بنكي بسهولة واستفادة من عروض مميزة.”
|
||||
// • “افتح حساب بنكي مع تطبيق سفر واستفد من خدمات مالية حصرية.”
|
||||
// • “نساعدك على فتح حساب بنكي بأفضل العروض بالتعاون مع البنوك المحلية.”
|
||||
// 4. ميزات ورود السيارات ومعارض السيارات الخاصة بنا:
|
||||
// • “استمتع بعروض مميزة لشراء السيارات من معارض سفر الحصرية.”
|
||||
// • “اختر سيارتك المثالية من معارض سفر بأسعار تنافسية وخدمات مميزة.”
|
||||
// • “نقدم لك أفضل عروض السيارات من معارضنا لتسهيل امتلاك سيارتك الجديدة.”
|
||||
// 5. ميزات أوفر كار:
|
||||
// • “أوفر كار من سفر توفر لك سيارات اقتصادية لزيادة دخلك بكفاءة.”
|
||||
// • “مع أوفر كار، يمكنك العمل بسيارات اقتصادية وتحقيق أرباح أكبر.”
|
||||
// • “تطبيق سفر يقدم لك أوفر كار، الخيار الاقتصادي المثالي لزيادة دخلك.”
|
||||
// 6. مستوى الدخل المحدود والطلبات الاقتصادية:
|
||||
// • “لأصحاب الدخل المحدود، وفرنا طلبات اقتصادية تضمن لك زيادة دخلك.”
|
||||
// • “الطلبات الاقتصادية من سفر تساعدك على زيادة دخلك بسهولة وفعالية.”
|
||||
// • “استفد من طلبات اقتصادية تناسب أصحاب الدخل المحدود لزيادة أرباحك.”
|
||||
// 7. طلبات الليل:
|
||||
// • “مع طلبات الليل من سفر، زود دخلك واستفد من فرص إضافية في المساء.”
|
||||
// • “لا تفوت فرصة طلبات الليل مع سفر، زود دخلك في أي وقت.”
|
||||
// • “طلبات الليل من سفر توفر لك فرصًا إضافية لتحقيق دخل أعلى.”
|
||||
// 8. طلبات الكمفورت الأكثر راحة والسيارات المكيفة:
|
||||
// • “قدّم خدمة مريحة مع طلبات الكمفورت من سفر والسيارات المكيفة.”
|
||||
// • “طلبات الكمفورت توفر تجربة راقية للركاب بسيارات مكيفة ومريحة.”
|
||||
// • “مع سفر، سيارات الكمفورت المكيفة تضمن راحة الركاب وزيادة الطلبات.”
|
||||
// 9. طلبات السبيد:
|
||||
// • “استقبل طلبات السبيد مع سفر لتقديم رحلات أسرع وزيادة دخلك.”
|
||||
// • “طلبات السبيد توفر لك فرصة إكمال المزيد من الرحلات في وقت أقل.”
|
||||
// • “مع طلبات السبيد من سفر، تقدم خدمة سريعة وفعالة لزيادة الأرباح.”
|
||||
// 10. الطلبات الثابتة والمعتدلة السعر والنسبة الثابتة 8%:
|
||||
// • “مع نسبة ثابتة 8%، تحصل على أفضل عروض الأسعار مع سفر.”
|
||||
// • “استمتع بنسبة ثابتة 8%، أقل نسبة بين المنافسين لزيادة دخلك.”
|
||||
// • “طلبات سفر الثابتة تضمن لك دخلاً مستقراً بنسبة أقل من 8%.”
|
||||
|
||||
Reference in New Issue
Block a user