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,8 +1,10 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../models/asset_model.dart';
import '../../models/fundamental_data_model.dart';
import '../../models/technical_analysis_model.dart';
import '../../repositories/asset_repository.dart';
import 'asset_header_event.dart';
import 'asset_header_state.dart';
import '../../repositories/asset_repository.dart';
import '../../models/asset_model.dart';
class AssetHeaderBloc extends Bloc<AssetHeaderEvent, AssetHeaderState> {
final AssetRepository repository;
@@ -11,21 +13,41 @@ class AssetHeaderBloc extends Bloc<AssetHeaderEvent, AssetHeaderState> {
final prevData = state is AssetHeaderLoaded ? (state as AssetHeaderLoaded).data : (state is AssetHeaderLoading ? (state as AssetHeaderLoading).previousData : null);
emit(AssetHeaderLoading(previousData: prevData));
try {
final fundamentals = await repository.getAssetFundamentals(event.isin, event.forceRefresh, ticker: event.ticker);
final results = await Future.wait([
repository.getAssetFundamentals(event.isin, event.forceRefresh, ticker: event.ticker),
repository.getAssetTechnical(event.isin, event.forceRefresh, ticker: event.ticker),
]);
final fundamentals = results[0] as FundamentalDataModel?;
final technical = results[1] as TechnicalAnalysisModel?;
if (fundamentals != null) {
double initialPrice = fundamentals.currentPrice;
String initialCurrency = fundamentals.tradingCurrency ?? 'EUR';
if (technical != null && technical.candles.isNotEmpty) {
final lastClose = technical.candles.last.close;
if (lastClose > 0) {
initialPrice = lastClose;
}
if (technical.currency.isNotEmpty) {
initialCurrency = technical.currency;
}
}
final assetModel = AssetModel(
isin: fundamentals.isin,
symbol: fundamentals.primaryTicker.isNotEmpty ? fundamentals.primaryTicker : fundamentals.isin,
name: fundamentals.companyName,
currentPrice: fundamentals.currentPrice,
currency: fundamentals.tradingCurrency ?? 'EUR',
currentPrice: initialPrice,
currency: initialCurrency,
exchange: fundamentals.exchange ?? 'XETRA',
exchanges: [], // Can be populated if needed
exchanges: [],
tickers: fundamentals.availableTickers.map((t) => AssetTickerOption(
ticker: t.ticker,
exchange: t.exchange ?? 'Unknown',
tradingCurrency: t.tradingCurrency ?? fundamentals.tradingCurrency ?? 'EUR',
currentPrice: t.currentPrice,
tradingCurrency: t.tradingCurrency ?? initialCurrency,
currentPrice: t.currentPrice ?? initialPrice,
)).toList(),
image: '/api/v1/logo/${fundamentals.isin}',
);