yangjia 1 mese fa
parent
commit
3440ad96ce
1 ha cambiato i file con 153 aggiunte e 102 eliminazioni
  1. 153 102
      lib/presentation/screens/asset/asset_staking_tab.dart

+ 153 - 102
lib/presentation/screens/asset/asset_staking_tab.dart

@@ -1,5 +1,4 @@
 import 'package:flutter/material.dart';
-import 'package:go_router/go_router.dart';
 
 import '../../../core/l10n/app_localizations.dart';
 import '../../../core/theme/app_colors.dart';
@@ -10,7 +9,8 @@ import '../../widgets/common/app_refresh_indicator.dart';
 
 /// 锁仓账户 Tab — 对齐 Web AssetsView STAKING Tab
 class AssetStakingTab extends StatelessWidget {
-  const AssetStakingTab({super.key, required this.state, required this.notifier});
+  const AssetStakingTab(
+      {super.key, required this.state, required this.notifier});
   final AssetState state;
   final AssetNotifier notifier;
 
@@ -116,34 +116,6 @@ class AssetStakingTab extends StatelessWidget {
                       ),
                     ],
                   ),
-                  const SizedBox(height: 16),
-                  if (false) //先隐藏划转按钮
-                  Row(
-                    children: [
-                      Expanded(
-                        child: _StakingActionButton(
-                          label: l10n.depositCoin,
-                          primary: true,
-                          onTap: () => context.push('/asset/deposit'),
-                        ),
-                      ),
-                      const SizedBox(width: 8),
-                      Expanded(
-                        child: _StakingActionButton(
-                          label: l10n.withdrawCoin,
-                          onTap: () => context.push('/asset/withdraw'),
-                        ),
-                      ),
-                      const SizedBox(width: 8),
-                      Expanded(
-                        child: _StakingActionButton(
-                          label: l10n.transfer,
-                          onTap: () =>
-                              context.push('/asset/transfer?from=SPOT&to=SWAP'),
-                        ),
-                      ),
-                    ],
-                  ),
                 ],
               ),
             ),
@@ -208,41 +180,6 @@ class AssetStakingTab extends StatelessWidget {
   }
 }
 
-class _StakingActionButton extends StatelessWidget {
-  const _StakingActionButton({
-    required this.label,
-    required this.onTap,
-    this.primary = false,
-  });
-  final String label;
-  final VoidCallback onTap;
-  final bool primary;
-
-  @override
-  Widget build(BuildContext context) {
-    final cs = Theme.of(context).colorScheme;
-    return GestureDetector(
-      onTap: onTap,
-      child: Container(
-        height: 40,
-        alignment: Alignment.center,
-        decoration: BoxDecoration(
-          color: primary ? AppColors.brand : cs.onSurface.withAlpha(20),
-          borderRadius: BorderRadius.circular(20),
-        ),
-        child: Text(
-          label,
-          style: TextStyle(
-            color: primary ? Colors.white : cs.onSurface,
-            fontSize: 13,
-            fontWeight: FontWeight.w600,
-          ),
-        ),
-      ),
-    );
-  }
-}
-
 class _StakingStatusFilter extends StatelessWidget {
   const _StakingStatusFilter({
     required this.value,
@@ -267,7 +204,8 @@ class _StakingStatusFilter extends StatelessWidget {
         child: DropdownButton<StakingOrderStatusFilter>(
           value: value,
           isDense: true,
-          icon: Icon(Icons.expand_more, size: 18, color: cs.onSurface.withAlpha(153)),
+          icon: Icon(Icons.expand_more,
+              size: 18, color: cs.onSurface.withAlpha(153)),
           items: [
             DropdownMenuItem(
               value: StakingOrderStatusFilter.all,
@@ -275,11 +213,13 @@ class _StakingStatusFilter extends StatelessWidget {
             ),
             DropdownMenuItem(
               value: StakingOrderStatusFilter.subscribing,
-              child: Text(l10n.assetsSubscribing, style: const TextStyle(fontSize: 13)),
+              child: Text(l10n.assetsSubscribing,
+                  style: const TextStyle(fontSize: 13)),
             ),
             DropdownMenuItem(
               value: StakingOrderStatusFilter.releasing,
-              child: Text(l10n.assetsReleasing, style: const TextStyle(fontSize: 13)),
+              child: Text(l10n.assetsReleasing,
+                  style: const TextStyle(fontSize: 13)),
             ),
             DropdownMenuItem(
               value: StakingOrderStatusFilter.completed,
@@ -304,11 +244,24 @@ class _StakingOrderCard extends StatelessWidget {
   final StakingOrderItem order;
   final bool obscure;
 
-  String _fmtAmount(double value) {
+  String _fmtAmount(double value, {int decimals = 2}) {
     if (obscure) {
       return '******';
     }
-    return formatPrice(value, decimalPlaces: 2);
+    return formatPrice(value, decimalPlaces: decimals);
+  }
+
+  String _fmtReleasedCompact(double value) {
+    if (obscure) {
+      return '******';
+    }
+    if (value == value.truncateToDouble()) {
+      return value.toInt().toString();
+    }
+    return value
+        .toStringAsFixed(8)
+        .replaceAll(RegExp(r'0+$'), '')
+        .replaceAll(RegExp(r'\.$'), '');
   }
 
   String _statusLabel(AppLocalizations l10n) {
@@ -321,14 +274,71 @@ class _StakingOrderCard extends StatelessWidget {
     return l10n.assetsReleasing;
   }
 
-  Color _statusColor() {
+  Color _statusTextColor() {
     if (order.status == 0) {
       return AppColors.brand;
     }
     if (order.status == 2) {
-      return Colors.grey;
+      return const Color(0xFF8E949F);
     }
-    return Colors.orange;
+    return const Color(0xFF12161C);
+  }
+
+  Color _statusBackgroundColor() {
+    if (order.status == 0) {
+      return const Color(0xFF12161C);
+    }
+    if (order.status == 2) {
+      return const Color(0xFF12161C);
+    }
+    return AppColors.brand;
+  }
+
+  String _displayDate(String? raw) {
+    if (raw == null || raw.isEmpty) {
+      return '-';
+    }
+    final normalized = raw.replaceFirst('T', ' ');
+    return normalized.length >= 10 ? normalized.substring(0, 10) : normalized;
+  }
+
+  String _lockDaysText() {
+    final startRaw = order.stakingTime ?? order.createTime;
+    final endRaw = order.unlockTime;
+    if (startRaw == null ||
+        endRaw == null ||
+        startRaw.isEmpty ||
+        endRaw.isEmpty) {
+      return '--';
+    }
+    final start = DateTime.tryParse(startRaw);
+    final end = DateTime.tryParse(endRaw);
+    if (start == null || end == null) {
+      return '--';
+    }
+    final days = end.difference(start).inDays.abs();
+    return days > 0 ? '$days天' : '--';
+  }
+
+  double _releaseProgress(double amount, double released) {
+    if (!amount.isFinite || amount <= 0) {
+      return 0;
+    }
+    final ratio = released / amount;
+    if (!ratio.isFinite) {
+      return 0;
+    }
+    return ratio.clamp(0.0, 1.0);
+  }
+
+  Color _progressColor() {
+    if (order.status == 2) {
+      return const Color(0xFF62656C);
+    }
+    if (order.status == 1) {
+      return AppColors.brand;
+    }
+    return Colors.transparent;
   }
 
   @override
@@ -336,49 +346,92 @@ class _StakingOrderCard extends StatelessWidget {
     final cs = Theme.of(context).colorScheme;
     final l10n = AppLocalizations.of(context)!;
     final isDark = Theme.of(context).brightness == Brightness.dark;
-    final coin = order.coinUnit.isNotEmpty ? order.coinUnit : l10n.assetsIbitUnit.toUpperCase();
+    final coin = order.coinUnit.isNotEmpty
+        ? order.coinUnit
+        : l10n.assetsIbitUnit.toUpperCase();
     final amount = double.tryParse(order.amount) ?? 0;
     final released = double.tryParse(order.releasedAmount) ?? 0;
+    final progress = _releaseProgress(amount, released);
 
     return Container(
       margin: const EdgeInsets.fromLTRB(16, 0, 16, 10),
-      padding: const EdgeInsets.all(16),
+      padding: const EdgeInsets.fromLTRB(14, 14, 14, 12),
       decoration: BoxDecoration(
         color: isDark ? AppColors.darkBgSecondary : AppColors.lightBgSecondary,
-        borderRadius: BorderRadius.circular(12),
-        border: isDark ? null : Border.all(color: AppColors.lightBorder, width: 0.5),
+        borderRadius: BorderRadius.circular(16),
+        border: isDark
+            ? null
+            : Border.all(color: AppColors.lightBorder, width: 0.5),
       ),
       child: Column(
         crossAxisAlignment: CrossAxisAlignment.start,
         children: [
-          Text(
-            '${l10n.assetsStakingOrderNo}: ORD${order.id}',
-            style: TextStyle(
-              color: cs.onSurface.withAlpha(153),
-              fontSize: 12,
-            ),
+          Row(
+            children: [
+              Expanded(
+                child: Text(
+                  '${l10n.assetsStakingOrderNo}: ORD${order.id}',
+                  style: TextStyle(
+                    color: cs.onSurface,
+                    fontSize: 13,
+                    fontWeight: FontWeight.w600,
+                  ),
+                ),
+              ),
+              Container(
+                padding:
+                    const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
+                decoration: BoxDecoration(
+                  color: _statusBackgroundColor(),
+                  borderRadius: BorderRadius.circular(999),
+                ),
+                child: Text(
+                  _statusLabel(l10n),
+                  style: TextStyle(
+                    color: _statusTextColor(),
+                    fontSize: 12,
+                    fontWeight: FontWeight.w600,
+                    height: 1,
+                  ),
+                ),
+              ),
+            ],
           ),
-          const SizedBox(height: 12),
+          const SizedBox(height: 14),
           _StakingOrderRow(
-            label: l10n.assetsStakingTotal,
-            value: '${_fmtAmount(amount)} $coin',
+            label: l10n.orderTime,
+            value: _displayDate(order.stakingTime ?? order.createTime),
           ),
           _StakingOrderRow(
-            label: l10n.assetsReleased,
-            value: '${_fmtAmount(released)} $coin',
+            label: l10n.assetsStakingTotal,
+            value: '${_fmtAmount(amount, decimals: 0)} $coin',
           ),
           _StakingOrderRow(
-            label: l10n.assetsPendingRelease,
-            value: '${_fmtAmount(order.pendingAmount)} $coin',
+            label: l10n.stakingLockDaysLabel,
+            value: _lockDaysText(),
           ),
           _StakingOrderRow(
-            label: l10n.startTime,
-            value: order.displayStartTime,
+            label: l10n.assetsReleased,
+            value:
+                '${_fmtReleasedCompact(released)}/${_fmtReleasedCompact(amount)}',
           ),
-          _StakingOrderRow(
-            label: l10n.statusLabel,
-            value: _statusLabel(l10n),
-            valueColor: _statusColor(),
+          const SizedBox(height: 8),
+          ClipRRect(
+            borderRadius: BorderRadius.circular(999),
+            child: SizedBox(
+              height: 8,
+              child: Stack(
+                fit: StackFit.expand,
+                children: [
+                  Container(color: const Color(0xFF12161C)),
+                  FractionallySizedBox(
+                    alignment: Alignment.centerLeft,
+                    widthFactor: progress,
+                    child: Container(color: _progressColor()),
+                  ),
+                ],
+              ),
+            ),
           ),
         ],
       ),
@@ -390,30 +443,28 @@ class _StakingOrderRow extends StatelessWidget {
   const _StakingOrderRow({
     required this.label,
     required this.value,
-    this.valueColor,
   });
   final String label;
   final String value;
-  final Color? valueColor;
 
   @override
   Widget build(BuildContext context) {
     final cs = Theme.of(context).colorScheme;
     return Padding(
-      padding: const EdgeInsets.only(bottom: 8),
+      padding: const EdgeInsets.only(bottom: 10),
       child: Row(
         mainAxisAlignment: MainAxisAlignment.spaceBetween,
         children: [
           Text(
             label,
-            style: TextStyle(color: cs.onSurface.withAlpha(153), fontSize: 13),
+            style: TextStyle(color: cs.onSurface.withAlpha(140), fontSize: 13),
           ),
-          Flexible(
+          Expanded(
             child: Text(
               value,
               textAlign: TextAlign.right,
               style: TextStyle(
-                color: valueColor ?? cs.onSurface,
+                color: cs.onSurface,
                 fontSize: 13,
                 fontWeight: FontWeight.w500,
               ),