refactor: إعادة تسمية التطبيقات الأربعة siro_* → intaleq_*
المجلدات وأسماء حزم dart واستيراداتها: siro_rider → intaleq_rider siro_driver → intaleq_driver siro_admin → intaleq_admin siro_service → intaleq_service شمل ذلك `name:` في كل pubspec وكل `package:siro_*` في الاستيرادات (115 ملفاً في rider وحده)، وإشارات أسماء المجلدات في docs/ وتعليق في backend/Admin/notifications/broadcast.php. لم تبقَ إشارة واحدة (تحقّقت). + ضُمّت حزم get و get_storage داخل intaleq_driver/packages/ وحُوّلت مساراتها الثلاثة من `../../Intaleq/packages/*` إلى `./packages/*`. كانت تُحل عرضاً إلى مجلد App/Intaleq القديم المجاور — تبعية خارج المستودع تنكسر بأول نقل. لم يبقَ في أي تطبيق تبعية مسار خارج الشجرة. ⚠️ لم تُمسّ بعد: هويات المتاجر (applicationId · PRODUCT_BUNDLE_IDENTIFIER · shorebird app_id) ولا الألوان ولا النصوص المرئية ولا النطاقات — كل منها كوميت منفصل، والهويات تحتاج قرار المالك. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
92dc6b3641
commit
0aab85c732
@@ -0,0 +1,202 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intaleq_rider/controller/home/profile/promos_controller.dart';
|
||||
import 'package:intaleq_rider/views/widgets/my_scafold.dart';
|
||||
import 'package:intaleq_rider/views/widgets/error_snakbar.dart';
|
||||
import 'dart:ui'; // لاستخدامه في الفاصل
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/style.dart';
|
||||
import '../../widgets/mycircular.dart';
|
||||
import 'package:dotted_line/dotted_line.dart'; // ستحتاج لإضافة هذا الباكج
|
||||
|
||||
// ملاحظة: ستحتاج لإضافة هذا الباكج إلى ملف pubspec.yaml الخاص بك
|
||||
// flutter pub add dotted_line
|
||||
|
||||
// --- الويدجت الرئيسية بالتصميم الجديد ---
|
||||
class PromosPassengerPage extends StatelessWidget {
|
||||
const PromosPassengerPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Get.put(PromosController()); // نفس منطقك القديم
|
||||
return MyScafolld(
|
||||
title: "Today's Promos".tr, // عنوان أكثر جاذبية
|
||||
isleading: true,
|
||||
body: [
|
||||
GetBuilder<PromosController>(
|
||||
builder: (controller) {
|
||||
if (controller.isLoading) {
|
||||
return const MyCircularProgressIndicator();
|
||||
}
|
||||
if (controller.promoList.isEmpty) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(Icons.local_offer_outlined,
|
||||
size: 80, color: Colors.grey),
|
||||
const SizedBox(height: 16),
|
||||
Text("No promos available right now.".tr,
|
||||
style: AppStyle.headTitle2),
|
||||
Text("Check back later for new offers!".tr,
|
||||
style: AppStyle.subtitle),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
itemCount: controller.promoList.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final promo = controller.promoList[index];
|
||||
// --- استدعاء ويدجت الكوبون الجديدة ---
|
||||
return _buildPromoTicket(context, promo);
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// --- ويدجت بناء كوبون الخصم ---
|
||||
Widget _buildPromoTicket(BuildContext context, Map<String, dynamic> promo) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 20.0),
|
||||
child: Container(
|
||||
height: 140, // ارتفاع ثابت للكوبون
|
||||
decoration: BoxDecoration(
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.15),
|
||||
blurRadius: 12,
|
||||
offset: const Offset(0, 6),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ClipPath(
|
||||
clipper: TicketClipper(), // Clipper مخصص لرسم شكل التذكرة
|
||||
child: Container(
|
||||
color: AppColor.secondaryColor,
|
||||
child: Row(
|
||||
children: [
|
||||
// --- الجزء الأيسر: تفاصيل العرض ---
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
promo['description']?.toString() ?? '',
|
||||
style: AppStyle.headTitle.copyWith(fontSize: 18),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const Spacer(),
|
||||
Row(
|
||||
children: [
|
||||
const Icon(Icons.calendar_today_outlined,
|
||||
size: 14, color: Colors.grey),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
'${'Valid Until:'.tr} ${promo['validity_end_date']?.toString() ?? ''}',
|
||||
style: AppStyle.subtitle
|
||||
.copyWith(fontSize: 12, color: Colors.grey),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
// --- الفاصل المنقط ---
|
||||
SizedBox(
|
||||
height: 110,
|
||||
child: DottedLine(
|
||||
direction: Axis.vertical,
|
||||
lineThickness: 2.0,
|
||||
dashLength: 8.0,
|
||||
dashColor: AppColor.writeColor.withOpacity(0.2),
|
||||
dashGapLength: 4.0,
|
||||
),
|
||||
),
|
||||
// --- الجزء الأيمن: كود الخصم وزر النسخ ---
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
// --- نفس منطقك القديم للنسخ ---
|
||||
Clipboard.setData(ClipboardData(
|
||||
text: promo['promo_code']?.toString() ?? ''));
|
||||
mySnackbarSuccess(
|
||||
'${'Code'.tr} ${promo['promo_code']?.toString() ?? ''} ${'copied to clipboard'.tr}');
|
||||
},
|
||||
child: Container(
|
||||
color: AppColor.primaryColor.withOpacity(0.1),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'CODE'.tr,
|
||||
style: AppStyle.subtitle.copyWith(
|
||||
color: AppColor.primaryColor, letterSpacing: 2),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
promo['promo_code']?.toString() ?? '',
|
||||
style: AppStyle.headTitle.copyWith(
|
||||
fontSize: 24, color: AppColor.primaryColor),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(Icons.copy,
|
||||
size: 14, color: AppColor.primaryColor),
|
||||
const SizedBox(width: 4),
|
||||
Text('Copy'.tr,
|
||||
style: AppStyle.subtitle
|
||||
.copyWith(color: AppColor.primaryColor)),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// --- كلاس مخصص لرسم شكل التذكرة ---
|
||||
class TicketClipper extends CustomClipper<Path> {
|
||||
@override
|
||||
Path getClip(Size size) {
|
||||
Path path = Path();
|
||||
|
||||
path.lineTo(0.0, size.height);
|
||||
path.lineTo(size.width, size.height);
|
||||
path.lineTo(size.width, 0.0);
|
||||
|
||||
double radius = 10;
|
||||
path.addOval(
|
||||
Rect.fromCircle(center: Offset(0, size.height / 2), radius: radius));
|
||||
path.addOval(Rect.fromCircle(
|
||||
center: Offset(size.width, size.height / 2), radius: radius));
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
|
||||
}
|
||||
Reference in New Issue
Block a user