ASSISTANT
بالطبع، إليك الكود الكامل بعد تصحيح الأخطاء التي ذُكرت سابقًا، مع إضافة التعاريف الناقصة وإصلاح التنسيقات وضبط بعض القيم، وإضافة دالة `dispose`:
```dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:telephony/telephony.dart';
import 'package:flutter_contacts/flutter_contacts.dart';
// ألوان التصميم الجديد
const primaryColor = Color(0xFF4361EE);
const secondaryColor = Color(0xFF3A0CA3);
const accentColor = Color(0xFFF72585);
const backgroundColor = Color(0xFFF8F9FA);
const cardColor = Colors.white;
const textColor = Color(0xFF212529);
const lightTextColor = Color(0xFF6C757D);
const successColor = Color(0xFF4BB543);
const errorColor = Color(0xFFDC3545);
// تعاريف إضافية للمفقودين
const borderColor = Color(0xFFE0E0E0);
const lightAccentColor = Color(0xFFE5E0FF);
const tajawalFont = 'Tajawal';
// تصميم جديد لفاصل الآلاف
class ThousandsSeparatorInputFormatter extends TextInputFormatter {
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue,
TextEditingValue newValue,
) {
String onlyDigits = newValue.text.replaceAll(RegExp(r'[^0-9]'), '');
if (onlyDigits.isEmpty) return newValue.copyWith(text: '');
final buffer = StringBuffer();
int len = onlyDigits.length;
for (int i = 0; i < len; i++) {
buffer.write(onlyDigits[i]);
int posFromRight = len - i - 1;
if (posFromRight % 3 == 0 && i != len - 1) buffer.write(',');
}
return TextEditingValue(
text: buffer.toString(),
selection: TextSelection.collapsed(offset: buffer.length),
);
}
}
class SplashScreen extends StatefulWidget {
const SplashScreen({super.key});
@override
State<SplashScreen> createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen>
with TickerProviderStateMixin {
bool _isLoading = true;
bool _hasSavedBalance = false;
bool _useSmsBalance = false;
int _previousBalance = 0;
int _currentBalance = 0;
int _totalBalance = 0;
int _savedPreviousBalance = 0;
late TextEditingController _balanceController;
late AnimationController _animationController;
late Animation<double> _logoScaleAnimation;
late Animation<Offset> _contentSlideAnimation;
late Animation<double> _fadeAnimation;
final Telephony telephony = Telephony.instance;
List<Contact> _contacts = [];
@override
void initState() {
super.initState();
_balanceController = TextEditingController();
_balanceController.addListener(_updateBalance);
_animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1000),
);
_logoScaleAnimation = Tween<double>(begin: 0.8, end: 1).animate(
CurvedAnimation(parent: _animationController, curve: Curves.easeOutBack),
);
_contentSlideAnimation = Tween<Offset>(
begin: const Offset(0, 0.3), // تم تصحيح القيمة
end: Offset.zero,
).animate(
CurvedAnimation(parent: _animationController, curve: Curves.easeOutQuart),
);
_fadeAnimation = Tween<double>(begin: 0, end: 1).animate(
CurvedAnimation(parent: _animationController, curve: Curves.easeInOut),
);
_animationController.forward();
_loadBalance();
_loadContacts();
}
@override
void dispose() {
_balanceController.removeListener(_updateBalance);
_balanceController.dispose();
_animationController.dispose();
super.dispose();
}
void _updateBalance() {
final input = _balanceController.text.replaceAll(',', '').trim();
int currentInput = int.tryParse(input) ?? 0;
setState(() {
_previousBalance = _savedPreviousBalance;
_currentBalance = currentInput;
_totalBalance = _currentBalance - _previousBalance;
});
}
Future<void> _loadContacts() async {
bool permissionGranted = await FlutterContacts.requestPermission();
if (!permissionGranted) {
if (mounted) {
_showSnackBar('يرجى السماح بالوصول إلى جهات الاتصال', isError: true);
}
return;
}
final contacts = await FlutterContacts.getContacts(withProperties: true);
if (mounted) {
setState(() {
_contacts =
contacts.where((contact) => contact.phones.isNotEmpty).toList();
});
}
}
Future<String?> _askUserForPhoneNumber() async {
String? phoneNumber;
await showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) {
final controller = TextEditingController();
String localSearchQuery = '';
return StatefulBuilder(
builder: (context, setStateDialog) {
List<Contact> filteredContacts =
_contacts.where((contact) {
final name = contact.displayName.toLowerCase();
final query = localSearchQuery.toLowerCase();
final matchesName = name.contains(query);
final matchesNumber = contact.phones.any(
(phone) => phone.number.toLowerCase().contains(query),
);
return matchesName || matchesNumber;
}).toList();
return Container(
decoration: BoxDecoration(
color: cardColor,
borderRadius: const BorderRadius.vertical(
top: Radius.circular(24),
),
),
padding: const EdgeInsets.all(20),
height: MediaQuery.of(context).size.height * 0.85,
child: Column(
children: [
Container(
width: 40,
height: 4,
margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
color: borderColor,
borderRadius: BorderRadius.circular(2),
),
),
Text(
'اختر جهة اتصال',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: primaryColor,
fontFamily: tajawalFont,
),
),
const SizedBox(height: 16),
Container(
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.circular(12),
),
child: TextField(
controller: controller,
decoration: InputDecoration(
hintText: 'ابحث بالاسم أو رقم الهاتف',
hintStyle: TextStyle(
color: lightTextColor,
fontFamily: tajawalFont,
),
prefixIcon: Icon(Icons.search, color: lightTextColor),
border: InputBorder.none,
contentPadding: const EdgeInsets.symmetric(
vertical: 16,
),
),
onChanged:
(val) => setStateDialog(() => localSearchQuery = val),
),
),
const SizedBox(height: 16),
Expanded(
child: filteredContacts.isEmpty
? Center(
child: Text(
'لا توجد جهات اتصال',
style: TextStyle(
color: lightTextColor,
fontFamily: tajawalFont,
),
),
)
: ListView.builder(
itemCount: filteredContacts.length,
itemBuilder: (_, index) {
final contact = filteredContacts[index];
return _buildContactItem(contact, controller);
},
),
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () => Navigator.pop(context),
style: OutlinedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
side: BorderSide(color: accentColor),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
child: Text(
'إلغاء',
style: TextStyle(
color: accentColor,
fontFamily: tajawalFont,
fontWeight: FontWeight.bold,
),
),
),
),
const SizedBox(width: 12),
Expanded(
child: ElevatedButton(
onPressed: () {
phoneNumber = controller.text.trim();
Navigator.pop(context);
},
style: ElevatedButton.styleFrom(
backgroundColor: accentColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 0,
),
child: Text(
'تأكيد',
style: TextStyle(
fontFamily: tajawalFont,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
],
),
);
},
);
},
);
return phoneNumber;
}
Widget _buildContactItem(Contact contact, TextEditingController controller) {
return Container(
margin: const EdgeInsets.only(bottom: 8),
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.circular(12),
),
child: ListTile(
leading: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: lightAccentColor,
shape: BoxShape.circle,
),
child: Icon(Icons.person, color: accentColor),
),
title: Text(
contact.displayName,
style: TextStyle(
fontWeight: FontWeight.bold,
color: textColor,
fontFamily: tajawalFont,
),
),
subtitle: contact.phones.isNotEmpty
? Text(
contact.phones.first.number,
style: TextStyle(
color: lightTextColor,
fontFamily: tajawalFont,
),
)
: null,
onTap: () {
if (contact.phones.isNotEmpty) {
controller.text = contact.phones.first.number;
}
},
),
);
}
Future<bool> _requestPermissions() async {
PermissionStatus smsStatus = await Permission.sms.status;
if (!smsStatus.isGranted) {
smsStatus = await Permission.sms.request();
}
return smsStatus.isGranted;
}
Future<String?> _getLatestSmsFromNumber(String senderNumber) async {
bool? permissionsGranted = await telephony.requestSmsPermissions();
if (permissionsGranted != true) return null;
String formatNumber(String number) {
return number.replaceAll(RegExp(r'[^0-9]'), '');
}
String formattedSenderNumber = formatNumber(senderNumber);
final List<SmsMessage> messages = await telephony.getInboxSms(
columns: [SmsColumn.ADDRESS, SmsColumn.BODY],
filter: SmsFilter.where(
SmsColumn.ADDRESS,
).like('%$formattedSenderNumber%'),
sortOrder: [OrderBy(SmsColumn.DATE_SENT, sort: Sort.DESC)],
);
return messages.isNotEmpty ? messages.first.body : null;
}
double? extractBalanceFromMessage(String message) {
RegExp regex = RegExp(r'(\d{1,3}(,\d{3})*(\.\d+)?|\d+(\.\d+)?)');
final matches = regex.allMatches(message);
double? maxValue;
for (var match in matches) {
final valueStr = match.group(0)?.replaceAll(',', '');
if (valueStr != null) {
final val = double.tryParse(valueStr);
if (val != null && (maxValue == null || val > maxValue)) {
maxValue = val;
}
}
}
return maxValue;
}
String _formatDoubleWithThousandsSeparator(double value) {
String fixed = value.toStringAsFixed(2);
final parts = fixed.split('.');
String integerPart = parts[0];
final buffer = StringBuffer();
for (int i = 0; i < integerPart.length; i++) {
buffer.write(integerPart[i]);
int posFromRight = integerPart.length - i - 1;
if (posFromRight % 3 == 0 && i != integerPart.length - 1)
buffer.write(',');
}
return parts[1] == '00'
? buffer.toString()
: '${buffer.toString()}.${parts[1]}';
}
Future<void> _fetchBalanceFromSms() async {
bool havePermissions = await _requestPermissions();
if (!havePermissions) {
_showSnackBar('يرجى السماح بصلاحيات قراءة الرسائل', isError: true);
return;
}
final senderNumber = await _askUserForPhoneNumber();
if (senderNumber == null || senderNumber.isEmpty) {
_showSnackBar('لم يتم إدخال رقم جهة اتصال', isError: true);
return;
}
String? smsText = await _getLatestSmsFromNumber(senderNumber);
if (smsText == null) {
_showSnackBar('لم يتم العثور على رسائل من جهة الاتصال', isError: true);
return;
}
double? balance = extractBalanceFromMessage(smsText);
if (balance != null) {
setState(() {
_balanceController.text =
_formatDoubleWithThousandsSeparator(balance).split('.').first;
_useSmsBalance = true;
});
_showSnackBar('تم جلب الرصيد من رسالة جهة الاتصال');
} else {
_showSnackBar('لم يتم العثور على رصيد صالح في الرسالة', isError: true);
}
}
void _showSnackBar(String message, {bool isError = false}) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message, style: const TextStyle(fontFamily: tajawalFont)),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
backgroundColor: isError ? Colors.red : Colors.green,
margin: const EdgeInsets.all(16),
),
);
}
Future<void> _loadBalance() async {
final prefs = await SharedPreferences.getInstance();
final savedData = prefs.getString('balance_data');
if (savedData != null) {
final Map<String, dynamic> jsonData = jsonDecode(savedData);
_savedPreviousBalance = jsonData['previous_balance'] ?? 0;
setState(() {
_previousBalance = _savedPreviousBalance;
_currentBalance = jsonData['current_balance'] ?? 0;
_totalBalance = jsonData['total_balance'] ?? _currentBalance;
_hasSavedBalance = true;
_balanceController.text = _formatWithThousandsSeparator(
_currentBalance,
);
});
} else {
setState(() => _hasSavedBalance = false);
}
setState(() => _isLoading = false);
}
String _formatWithThousandsSeparator(int value) {
// تعديل تنسيق الآلاف
return value.toString().replaceAllMapped(
RegExp(r'(\d)(?=(\d{3})+(?!\d))'),
(Match m) => '${m[1]},',
);
}
Future<void> _saveBalances({
required int previousBalance,
required int currentBalance,
required int totalBalance,
}) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(
'balance_data',
jsonEncode({
'previous_balance': previousBalance,
'current_balance': currentBalance,
'total_balance': totalBalance,
}),
);
}
void _onContinue() async {
final currentInput = _balanceController.text.replaceAll(',', '').trim();
final currentBalanceInput = int.tryParse(currentInput);
if (currentBalanceInput == null || currentBalanceInput < 0) {
_showSnackBar('يرجى إدخال مبلغ رصيد صالح (صفر أو أكثر)', isError: true);
return;
}
setState(() {
_previousBalance = _currentBalance;
_savedPreviousBalance = _previousBalance;
_currentBalance = currentBalanceInput;
_totalBalance = _currentBalance - _previousBalance; // منطق حسب حاجتك، قد تحتاج + بدلاً من -
_hasSavedBalance = true;
});
await _saveBalances(
previousBalance: _savedPreviousBalance,
currentBalance: _currentBalance,
totalBalance: _totalBalance,
);
Navigator.pushReplacementNamed(context, '/home');
}
Widget _smallBalanceInfo(String label, int value) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: BoxDecoration(
color: cardColor,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
label,
style: TextStyle(
fontFamily: tajawalFont,
color: lightTextColor,
fontSize: 12,
),
),
const SizedBox(height: 6),
Text(
_formatWithThousandsSeparator(value),
style: TextStyle(
fontFamily: tajawalFont,
fontWeight: FontWeight.bold,
color: primaryColor,
fontSize: 16,
),
),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: backgroundColor,
body: SafeArea(
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width * 0.05,
vertical: 16,
),
child: _isLoading
? Center(
child: CircularProgressIndicator(
color: accentColor,
strokeWidth: 2,
),
)
: Column(
children: [
Expanded(
child: CustomScrollView(
physics: const BouncingScrollPhysics(),
slivers: [
SliverToBoxAdapter(
child: Column(
children: [
const SizedBox(height: 20),
_buildAppLogo(),
const SizedBox(height: 30),
_buildWelcomeSection(),
const SizedBox(height: 40),
_buildBalanceInputSection(),
],
),
),
if (_hasSavedBalance)
SliverToBoxAdapter(
child: Column(
children: [
const SizedBox(height: 30),
_buildBalanceSummary(),
const SizedBox(height: 20),
],
),
),
const SliverFillRemaining(
hasScrollBody: false,
child: SizedBox(height: 20),
),
],
),
),
_buildContinueButton(),
],
),
),
),
);
}
Widget _buildAppLogo() {
return Container(
width: 120,
height: 120,
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [primaryColor, secondaryColor],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: primaryColor.withOpacity(0.2),
blurRadius: 20,
spreadRadius: 5,
),
],
),
child: Stack(
alignment: Alignment.center,
children: [
const Icon(Icons.account_balance_wallet, size: 50, color: Colors.white),
Positioned(
right: 10,
bottom: 10,
child: Container(
padding: const EdgeInsets.all(6),
decoration: BoxDecoration(
color: accentColor,
shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 2),
),
child: const Icon(Icons.bolt, size: 16, color: Colors.white),
),
),
],
),
);
}
Widget _buildWelcomeSection() {
return Column(
children: [
Text(
'مرحبًا بك في حوّلها فايبرافون',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: textColor,
fontFamily: tajawalFont,
),
),
const SizedBox(height: 12),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Text(
'أدخل رصيدك الحالي لبدء رحلة تحويل الأموال بسهولة وأمان',
style: TextStyle(
fontSize: 14,
color: lightTextColor,
fontFamily: tajawalFont,
height: 1.6,
),
textAlign: TextAlign.center,
),
),
],
);
}
Widget _buildBalanceInputSection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'طريقة إدخال الرصيد',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: textColor,
fontFamily: tajawalFont,
),
),
const SizedBox(height: 12),
Container(
decoration: BoxDecoration(
color: cardColor,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Column(
children: [
_buildInputMethodToggle(),
if (!_useSmsBalance) _buildManualInputField(),
],
),
),
],
);
}
Widget _buildInputMethodToggle() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Expanded(
child: InkWell(
onTap: () => setState(() => _useSmsBalance = false),
borderRadius: BorderRadius.circular(8),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 14),
decoration: BoxDecoration(
color:
!_useSmsBalance ? primaryColor.withOpacity(0.1) : Colors.transparent,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: !_useSmsBalance ? primaryColor : Colors.transparent,
width: 1.5,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.edit,
color: !_useSmsBalance ? primaryColor : lightTextColor,
size: 20,
),
const SizedBox(width: 8),
Text(
'إدخال يدوي',
style: TextStyle(
color: !_useSmsBalance ? primaryColor : lightTextColor,
fontWeight: FontWeight.bold,
fontFamily: tajawalFont,
),
),
],
),
),
),
),
const SizedBox(width: 10),
Expanded(
child: InkWell(
onTap: () {
setState(() => _useSmsBalance = true);
_fetchBalanceFromSms();
},
borderRadius: BorderRadius.circular(8),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 14),
decoration: BoxDecoration(
color:
_useSmsBalance ? primaryColor.withOpacity(0.1) : Colors.transparent,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: _useSmsBalance ? primaryColor : Colors.transparent,
width: 1.5,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.sms,
color: _useSmsBalance ? primaryColor : lightTextColor,
size: 20,
),
const SizedBox(width: 8),
Text(
'جلب من رسالة',
style: TextStyle(
color: _useSmsBalance ? primaryColor : lightTextColor,
fontWeight: FontWeight.bold,
fontFamily: tajawalFont,
),
),
],
),
),
),
),
],
),
);
}
Widget _buildManualInputField() {
return Padding(
padding: const EdgeInsets.all(16),
child: TextField(
controller: _balanceController,
keyboardType: TextInputType.number,
inputFormatters: [ThousandsSeparatorInputFormatter()],
textAlign: TextAlign.right,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: textColor,
fontFamily: tajawalFont,
),
decoration: InputDecoration(
filled: true,
fillColor: backgroundColor,
hintText: 'أدخل الرصيد الحالي',
hintStyle: TextStyle(
color: lightTextColor,
fontFamily: tajawalFont,
),
prefixIcon: Padding(
padding: const EdgeInsets.only(left: 16, right: 8),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.attach_money, color: primaryColor),
Container(
width: 1,
height: 20,
margin: const EdgeInsets.symmetric(horizontal: 8),
color: Colors.grey[300],
),
],
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none,
),
contentPadding: const EdgeInsets.symmetric(vertical: 16, horizontal: 20),
),
),
);
}
Widget _buildBalanceSummary() {
return Column(
children: [
Text(
'ملخص الرصيد',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: textColor,
fontFamily: tajawalFont,
),
),
const SizedBox(height: 16),
LayoutBuilder(
builder: (context, constraints) {
final isSmallScreen = constraints.maxWidth < 400;
return isSmallScreen
? Column(
children: [
_buildBalanceInfoCard('الرصيد السابق', _previousBalance),
const SizedBox(height: 10),
_buildBalanceInfoCard('الرصيد الحالي', _currentBalance),
const SizedBox(height: 10),
_buildBalanceInfoCard('الرصيد المضاف', _totalBalance),
],
)
: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Flexible(
child:
_buildBalanceInfoCard('الرصيد السابق', _previousBalance)),
Flexible(
child:
_buildBalanceInfoCard('الرصيد الحالي', _currentBalance)),
Flexible(
child: _buildBalanceInfoCard('الرصيد المضاف', _totalBalance)),
],
);
},
),
],
);
}
Widget _buildBalanceInfoCard(String title, int value) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12),
margin: const EdgeInsets.symmetric(horizontal: 4),
decoration: BoxDecoration(
color: cardColor,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 8,
offset: const Offset(0, 4),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
_getBalanceIcon(title),
color: _getBalanceColor(title),
size: 18,
),
const SizedBox(width: 6),
Text(
title,
style: TextStyle(
fontSize: 12,
color: lightTextColor,
fontFamily: tajawalFont,
),
),
],
),
const SizedBox(height: 8),
FittedBox(
child: Text(
_formatWithThousandsSeparator(value),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: textColor,
fontFamily: tajawalFont,
),
),
),
],
),
);
}
IconData _getBalanceIcon(String title) {
switch (title) {
case 'الرصيد السابق':
return Icons.history;
case 'الرصيد الحالي':
return Icons.account_balance_wallet;
case 'الرصيد المضاف':
return Icons.add_circle;
default:
return Icons.info;
}
}
Color _getBalanceColor(String title) {
switch (title) {
case 'الرصيد السابق':
return lightTextColor;
case 'الرصيد الحالي':
return primaryColor;
case 'الرصيد المضاف':
return _totalBalance >= 0 ? successColor : errorColor;
default:
return lightTextColor;
}
}
Widget _buildContinueButton() {
return Padding(
padding: const EdgeInsets.only(bottom: 20),
child: SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _onContinue,
style: ElevatedButton.styleFrom(
backgroundColor: primaryColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 18),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 0,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'ابدأ الآن',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
fontFamily: tajawalFont,
),
),
const SizedBox(width: 8),
const Icon(Icons.arrow_forward, size: 20),
],
),
),
),
);
}
}
```
---
### ملحوظات إضافية:
- إذا تحتاج تنسيق الأرقام عقب تغييرها بشكل أدق (خاصة للأرقام الكبيرة أو التي تحتوي فواصل عشرية)، أنصح باستخدام مكتبة `intl` مثل:
```dart
import 'package:intl/intl.dart';
final formatter = NumberFormat('#,##0');
String formatted = formatter.format(value);
```
- التأكد من منح صلاحيات الوصول للجهات والرسائل في إعدادات الجهاز عند الاختبار.
- مسار التنقل `'/home'` في `_onContinue` يجب أن يكون معرفاً في الـ Routes لديك.
---
إذا احتجت أي مساعدة إضافية أو أمثلة، أنا هنا للمساعدة.