Update: 2026-08-03 11:32:12
This commit is contained in:
@@ -60,6 +60,9 @@ class FinancialV2Page extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildMainFinancialStats(ctrl.stats, cs),
|
||||
const SizedBox(height: 32),
|
||||
_buildSectionTitle('محفظة سيرو', cs),
|
||||
_buildSiroWalletSection(ctrl.walletSummary, cs),
|
||||
const SizedBox(height: 24),
|
||||
_buildSectionTitle('طرق الدفع', cs),
|
||||
_buildPaymentMethodBreakdown(ctrl.stats, cs),
|
||||
@@ -78,6 +81,116 @@ class FinancialV2Page extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
/// تنسيق مبلغ بفواصل آلاف وخانتين عشريتين.
|
||||
/// بلا رمز عملة عمداً: هذا النشر أردني بينما بطاقات هذه الشاشة الأخرى
|
||||
/// ما زالت تكتب "ج.م" ثابتة — راجع صحّتها قبل توحيد الرمز.
|
||||
String _money(double v) {
|
||||
final neg = v < 0;
|
||||
final parts = v.abs().toStringAsFixed(2).split('.');
|
||||
final digits = parts[0];
|
||||
final buf = StringBuffer();
|
||||
for (int i = 0; i < digits.length; i++) {
|
||||
if (i > 0 && (digits.length - i) % 3 == 0) buf.write(',');
|
||||
buf.write(digits[i]);
|
||||
}
|
||||
return '${neg ? '-' : ''}$buf.${parts[1]}';
|
||||
}
|
||||
|
||||
/// محفظة سيرو من خادم المدفوعات: الشهر الجاري مقابل الشهر السابق،
|
||||
/// والإجمالي التراكمي، مع فصل الإيداع عن الصرف.
|
||||
Widget _buildSiroWalletSection(
|
||||
Map<String, dynamic> summary, ColorScheme cs) {
|
||||
if (summary.isEmpty) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: cs.surfaceContainerHighest,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: cs.outline),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.account_balance_wallet_outlined,
|
||||
color: cs.onSurfaceVariant, size: 18),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'تعذّر جلب ملخّص المحفظة من خادم المدفوعات',
|
||||
style: TextStyle(color: cs.onSurfaceVariant, fontSize: 13),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final mtd = (summary['month_to_date'] as Map?) ?? {};
|
||||
final allTime = (summary['all_time'] as Map?) ?? {};
|
||||
final growth = summary['growth_percent'];
|
||||
|
||||
double n(dynamic v) => double.tryParse('${v ?? 0}') ?? 0;
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildFinancialCard(
|
||||
'صافي هذا الشهر',
|
||||
_money(n(mtd['net'])),
|
||||
Icons.calendar_month_rounded,
|
||||
cs.primary,
|
||||
cs,
|
||||
// المؤشّر يظهر فقط عند وجود شهر سابق يُقارن به
|
||||
subtitle: growth == null
|
||||
? null
|
||||
: '${n(growth) >= 0 ? '▲' : '▼'} ${n(growth).abs().toStringAsFixed(1)}% عن الشهر السابق',
|
||||
subtitleColor: growth == null
|
||||
? null
|
||||
: (n(growth) >= 0 ? cs.success : cs.danger),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: _buildFinancialCard(
|
||||
'الإجمالي التراكمي',
|
||||
_money(n(allTime['net'])),
|
||||
Icons.savings_rounded,
|
||||
cs.tertiary,
|
||||
cs,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildFinancialCard(
|
||||
'إيداع هذا الشهر',
|
||||
_money(n(mtd['credits'])),
|
||||
Icons.south_west_rounded,
|
||||
cs.success,
|
||||
cs,
|
||||
subtitle: '${mtd['tx_count'] ?? 0} حركة',
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: _buildFinancialCard(
|
||||
'صرف هذا الشهر',
|
||||
_money(n(mtd['debits'])),
|
||||
Icons.north_east_rounded,
|
||||
cs.warning,
|
||||
cs,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSectionTitle(String title, ColorScheme cs) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
@@ -134,7 +247,7 @@ class FinancialV2Page extends StatelessWidget {
|
||||
|
||||
Widget _buildFinancialCard(
|
||||
String title, String value, IconData icon, Color color, ColorScheme cs,
|
||||
{bool isSmall = false}) {
|
||||
{bool isSmall = false, String? subtitle, Color? subtitleColor}) {
|
||||
return Container(
|
||||
padding: EdgeInsets.all(isSmall ? 16 : 24),
|
||||
decoration: BoxDecoration(
|
||||
@@ -170,6 +283,14 @@ class FinancialV2Page extends StatelessWidget {
|
||||
color: cs.onSurface,
|
||||
fontSize: isSmall ? 18 : 24,
|
||||
fontWeight: FontWeight.bold)),
|
||||
if (subtitle != null) ...[
|
||||
const SizedBox(height: 4),
|
||||
Text(subtitle,
|
||||
style: TextStyle(
|
||||
color: subtitleColor ?? cs.onSurfaceVariant,
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w600)),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user