feat(app): responsive asset detail layout, full width chart, reactive hero header, shimmer loaders and enriched fundamentals

This commit is contained in:
2026-08-14 23:57:03 +02:00
parent f94e3b8164
commit 1d244b338a
22 changed files with 1950 additions and 1074 deletions
@@ -1,6 +1,9 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../core/theme/app_theme.dart';
import '../../../core/widgets/glass_container.dart';
import '../../favorites/cubit/favorites_cubit.dart';
import '../../favorites/models/favorite_asset_model.dart';
import '../models/trade_model.dart';
import 'trade_detail_modal.dart';
@@ -26,23 +29,34 @@ class TradeCard extends StatelessWidget {
final isActive = trade.isActive;
final isClosed = trade.isClosed;
final pnlAbs = trade.calculatedPnlAbs;
final pnlPct = trade.calculatedPnlPct;
final isPnlPos = pnlAbs >= 0;
final pnlColor = isPnlPos ? AppTheme.primaryEmerald : AppTheme.accentRed;
return BlocBuilder<FavoritesCubit, FavoritesState>(
builder: (context, favState) {
double livePrice = 0.0;
final keyUpper = (trade.isin.isNotEmpty ? trade.isin : trade.symbol).toUpperCase();
final match = favState.favoriteDetails.firstWhere(
(f) => f.isin.toUpperCase() == keyUpper || f.symbol.toUpperCase() == keyUpper,
orElse: () => const FavoriteAssetModel(isin: '', symbol: '', name: '', currentPrice: 0.0, change24h: 0.0),
);
if (match.currentPrice > 0) {
livePrice = match.currentPrice;
}
final currPrice = trade.effectiveCurrentPrice;
final pnlAbs = livePrice > 0 ? trade.calculateLivePnlAbs(livePrice) : trade.calculatedPnlAbs;
final pnlPct = livePrice > 0 ? trade.calculateLivePnlPct(livePrice) : trade.calculatedPnlPct;
final isPnlPos = pnlAbs >= 0;
final pnlColor = isPnlPos ? AppTheme.primaryEmerald : AppTheme.accentRed;
final currPrice = livePrice > 0 ? livePrice : trade.effectiveCurrentPrice;
return GestureDetector(
onTap: () => TradeDetailModal.show(
context,
trade: trade,
onAccept: onAccept,
onClose: onClose,
),
child: GlassContainer(
margin: const EdgeInsets.only(bottom: 14),
padding: const EdgeInsets.all(16),
return GestureDetector(
onTap: () => TradeDetailModal.show(
context,
trade: trade,
onAccept: onAccept,
onClose: onClose,
),
child: GlassContainer(
margin: const EdgeInsets.only(bottom: 14),
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -187,7 +201,7 @@ class TradeCard extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${trade.instrumentType.isNotEmpty ? trade.instrumentType : "Stock"}${trade.timeframe.isNotEmpty ? trade.timeframe : "1D"}${trade.leverageUsed > 1 ? "${trade.leverageUsed.toStringAsFixed(0)}x Hebel" : ""}',
'${trade.instrumentType.isNotEmpty ? trade.instrumentType : "Stock"}${trade.derivativeIsin.isNotEmpty ? " (${trade.derivativeIsin})" : ""}${trade.timeframe.isNotEmpty ? trade.timeframe : "1D"}${trade.leverageUsed > 1 ? "${trade.leverageUsed.toStringAsFixed(0)}x Hebel" : ""}',
style: TextStyle(color: AppTheme.textMuted, fontSize: 11),
),
@@ -241,14 +255,16 @@ class TradeCard extends StatelessWidget {
),
),
],
],
),
],
),
],
],
),
],
),
],
),
),
),
);
},
);
}
Widget _priceItem(String label, String val, Color valColor) {