Update: 2026-07-02 05:27:04
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// CompetitorPriceBadge
|
||||
/// ─────────────────────
|
||||
/// ويدجت يعرض مقارنة ذكية بين سعر سيرو وسعر المنافسين.
|
||||
/// يُستخدم في شاشة عرض الأسعار (bottomSheet) ويظهر فقط إذا توفرت
|
||||
/// بيانات المنافسين من API (has_competitor_data = true).
|
||||
class CompetitorPriceBadge extends StatelessWidget {
|
||||
/// نسبة التوفير للراكب (مثال: 8.5 تعني "أوفر بـ 8.5%")
|
||||
final double? savingsPercent;
|
||||
|
||||
/// النص التوضيحي الجاهز من السيرفر (مثال: "أوفر بـ 8% من التطبيقات الأخرى ⚡")
|
||||
final String? savingsLabel;
|
||||
|
||||
/// اسم أكبر منافس للمقارنة (مثال: "Careem")
|
||||
final String? topCompetitor;
|
||||
|
||||
const CompetitorPriceBadge({
|
||||
super.key,
|
||||
this.savingsPercent,
|
||||
this.savingsLabel,
|
||||
this.topCompetitor,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// لا تُظهر الويدجت إذا لم تتوفر بيانات
|
||||
if (savingsLabel == null || savingsLabel!.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
final double pct = savingsPercent ?? 0.0;
|
||||
final bool isSignificant = pct >= 5.0;
|
||||
final bool isModerate = pct >= 2.0 && pct < 5.0;
|
||||
|
||||
// اختيار ألوان حسب قوة التوفير
|
||||
final Color bgColor = isSignificant
|
||||
? const Color(0xFF1A3A2A)
|
||||
: isModerate
|
||||
? const Color(0xFF1A2A3A)
|
||||
: const Color(0xFF1F1F2E);
|
||||
final Color borderColor = isSignificant
|
||||
? const Color(0xFF34D399)
|
||||
: isModerate
|
||||
? const Color(0xFF60A5FA)
|
||||
: const Color(0xFF818CF8);
|
||||
final Color textColor = isSignificant
|
||||
? const Color(0xFF34D399)
|
||||
: isModerate
|
||||
? const Color(0xFF60A5FA)
|
||||
: const Color(0xFFA5B4FC);
|
||||
|
||||
return AnimatedOpacity(
|
||||
opacity: 1.0,
|
||||
duration: const Duration(milliseconds: 400),
|
||||
child: Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: bgColor,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: borderColor.withOpacity(0.5), width: 1),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: borderColor.withOpacity(0.12),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
// أيقونة التوفير
|
||||
Container(
|
||||
width: 32,
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
color: borderColor.withOpacity(0.15),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
isSignificant ? Icons.trending_down_rounded : Icons.price_check_rounded,
|
||||
color: textColor,
|
||||
size: 18,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
// نص المقارنة
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
savingsLabel!,
|
||||
style: TextStyle(
|
||||
color: textColor,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w700,
|
||||
height: 1.3,
|
||||
),
|
||||
),
|
||||
if (topCompetitor != null && topCompetitor!.isNotEmpty) ...[
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
'مقارنةً بـ ${_formatCompetitorName(topCompetitor!)} والتطبيقات الأخرى',
|
||||
style: TextStyle(
|
||||
color: textColor.withOpacity(0.6),
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
// شارة النسبة
|
||||
if (pct >= 2.0)
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: borderColor.withOpacity(0.18),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Text(
|
||||
'-${pct.toStringAsFixed(1)}%',
|
||||
style: TextStyle(
|
||||
color: textColor,
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _formatCompetitorName(String raw) {
|
||||
final names = {
|
||||
'careem': 'كريم',
|
||||
'uber': 'أوبر',
|
||||
'yallago': 'يلاكو',
|
||||
'zaken': 'زاكن',
|
||||
'tufaddal': 'تفضل',
|
||||
'jeeny': 'جيني',
|
||||
'taxif': 'تاكسيف',
|
||||
};
|
||||
return names[raw.toLowerCase()] ?? raw;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user