refactor: save current workspace state including FinlyticAnalyzer fixes, FinlyticApp trade route alignment, and DTO audit documentation
This commit is contained in:
@@ -1,23 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:finlytic_app/features/favorites/repositories/favorites_repository.dart';
|
||||
import 'favorites_event.dart';
|
||||
import 'favorites_state.dart';
|
||||
|
||||
class FavoritesBloc extends Bloc<FavoritesEvent, FavoritesState> {
|
||||
final FavoritesRepository repository;
|
||||
|
||||
FavoritesBloc({required this.repository}) : super(FavoritesInitial()) {
|
||||
on<LoadFavorites>(_onLoadFavorites);
|
||||
}
|
||||
|
||||
Future<void> _onLoadFavorites(LoadFavorites event, Emitter<FavoritesState> emit) async {
|
||||
emit(FavoritesLoading());
|
||||
try {
|
||||
final favorites = await repository.fetchFavoritesDetails(event.symbols);
|
||||
emit(FavoritesLoaded(favorites));
|
||||
} catch (e) {
|
||||
emit(const FavoritesError("Fehler beim Laden der Favoriten."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
abstract class FavoritesEvent extends Equatable {
|
||||
const FavoritesEvent();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class LoadFavorites extends FavoritesEvent {
|
||||
final List<String> symbols;
|
||||
|
||||
const LoadFavorites(this.symbols);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [symbols];
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:finlytic_app/features/favorites/models/favorite_asset_model.dart';
|
||||
|
||||
abstract class FavoritesState extends Equatable {
|
||||
const FavoritesState();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class FavoritesInitial extends FavoritesState {}
|
||||
|
||||
class FavoritesLoading extends FavoritesState {}
|
||||
|
||||
class FavoritesLoaded extends FavoritesState {
|
||||
final List<FavoriteAssetModel> favorites;
|
||||
|
||||
const FavoritesLoaded(this.favorites);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [favorites];
|
||||
}
|
||||
|
||||
class FavoritesError extends FavoritesState {
|
||||
final String message;
|
||||
|
||||
const FavoritesError(this.message);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [message];
|
||||
}
|
||||
@@ -3,7 +3,6 @@ import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../../core/network/api_client.dart';
|
||||
import '../../../core/network/signalr_service.dart';
|
||||
import '../../../core/utils/asset_utils.dart';
|
||||
import '../models/favorite_asset_model.dart';
|
||||
|
||||
class FavoritesState extends Equatable {
|
||||
@@ -63,7 +62,8 @@ class FavoritesCubit extends Cubit<FavoritesState> {
|
||||
Future<void> loadFavorites() async {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
try {
|
||||
final res = await apiClient.get('/api/v1/user/favorites');
|
||||
final ts = DateTime.now().millisecondsSinceEpoch;
|
||||
final res = await apiClient.get('/api/v1/user/favorites?_t=$ts');
|
||||
if (res.statusCode == 200 && res.data is List) {
|
||||
final rawList = res.data as List;
|
||||
final set = <String>{};
|
||||
@@ -71,7 +71,6 @@ class FavoritesCubit extends Cubit<FavoritesState> {
|
||||
|
||||
for (var item in rawList) {
|
||||
final model = FavoriteAssetModel.fromJson(Map<String, dynamic>.from(item));
|
||||
AssetUtils.registerAsset(model.isin, model.name, model.image);
|
||||
final key = (model.isin.isNotEmpty ? model.isin : (model.symbol.isNotEmpty ? model.symbol : model.name)).toUpperCase();
|
||||
if (!dedupMap.containsKey(key)) {
|
||||
dedupMap[key] = model;
|
||||
@@ -150,10 +149,21 @@ class FavoritesCubit extends Cubit<FavoritesState> {
|
||||
|
||||
Future<void> updateFavoriteTicker(String symbol, String ticker) async {
|
||||
try {
|
||||
// Optimistic UI update
|
||||
final target = symbol.toUpperCase();
|
||||
final updatedDetails = state.favoriteDetails.map((model) {
|
||||
if (model.isin.toUpperCase() == target || model.symbol.toUpperCase() == target) {
|
||||
return model.copyWith(symbol: ticker);
|
||||
}
|
||||
return model;
|
||||
}).toList();
|
||||
emit(state.copyWith(favoriteDetails: updatedDetails));
|
||||
|
||||
await apiClient.post('/api/v1/user/favorites/$symbol/ticker?ticker=$ticker');
|
||||
await loadFavorites();
|
||||
} catch (_) {
|
||||
// Ignore gracefully
|
||||
// Revert/refresh on error
|
||||
await loadFavorites();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import 'package:finlytic_app/core/network/api_client.dart';
|
||||
import 'package:finlytic_app/features/favorites/models/favorite_asset_model.dart';
|
||||
import 'package:finlytic_app/core/utils/asset_utils.dart';
|
||||
|
||||
class FavoritesRepository {
|
||||
final ApiClient apiClient;
|
||||
|
||||
FavoritesRepository({required this.apiClient});
|
||||
|
||||
Future<List<FavoriteAssetModel>> fetchFavoritesDetails(List<String> symbols) async {
|
||||
if (symbols.isEmpty) return [];
|
||||
|
||||
try {
|
||||
final res = await apiClient.post('/api/v1/assets/batch', data: {'symbols': symbols});
|
||||
if (res.statusCode == 200 && res.data != null) {
|
||||
final List<dynamic> data = res.data;
|
||||
return data.map((json) => FavoriteAssetModel.fromJson(json)).toList();
|
||||
}
|
||||
return symbols.map((s) => FavoriteAssetModel(
|
||||
symbol: s,
|
||||
name: AssetUtils.getAssetName(s),
|
||||
currentPrice: 0.0,
|
||||
change24h: 0.0,
|
||||
)).toList();
|
||||
} catch (e) {
|
||||
print('Error fetching favorites details: $e');
|
||||
return symbols.map((s) => FavoriteAssetModel(
|
||||
symbol: s,
|
||||
name: AssetUtils.getAssetName(s),
|
||||
currentPrice: 0.0,
|
||||
change24h: 0.0,
|
||||
)).toList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../core/network/api_client.dart';
|
||||
import '../../../core/theme/app_theme.dart';
|
||||
import '../../../core/utils/asset_utils.dart';
|
||||
import '../../../core/widgets/asset_logo_widget.dart';
|
||||
import '../../../core/widgets/glass_container.dart';
|
||||
import '../../../shared/widgets/favorite_star_button.dart';
|
||||
@@ -23,7 +22,7 @@ class WatchlistCard extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final activeTheme = AppTheme.activePreset;
|
||||
final symbol = asset.symbol;
|
||||
final displayName = asset.name.isNotEmpty ? asset.name : AssetUtils.getAssetName(symbol);
|
||||
final displayName = asset.name;
|
||||
final isPositive = asset.change24h >= 0;
|
||||
|
||||
return GlassContainer(
|
||||
@@ -32,7 +31,9 @@ class WatchlistCard extends StatelessWidget {
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => AssetDetailScreen(
|
||||
symbol: displayName,
|
||||
isin: asset.isin,
|
||||
name: displayName,
|
||||
symbol: asset.symbol,
|
||||
apiClient: apiClient,
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user