refactor: save current workspace state including FinlyticAnalyzer fixes, FinlyticApp trade route alignment, and DTO audit documentation

This commit is contained in:
2026-08-12 18:30:42 +02:00
parent a9553e9fbf
commit 3d8af3940b
163 changed files with 3421 additions and 1751 deletions
@@ -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,
),
),