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
@@ -2,6 +2,7 @@ import 'dart:math';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import '../../../../core/theme/app_theme.dart';
import '../../utils/pattern_explanations.dart';
class CandleModel {
final DateTime time;
@@ -518,16 +519,16 @@ class _CandlePainter extends CustomPainter {
}
if (showEma && !firstEma20) {
canvas.drawPath(ema20Path, Paint()..color = theme.primaryColor..style = PaintingStyle.stroke..strokeWidth = 1.5);
canvas.drawPath(ema20Path, Paint()..color = Colors.blueAccent..style = PaintingStyle.stroke..strokeWidth = 1.5);
}
if (showSma50 && !firstSma50) {
canvas.drawPath(sma50Path, Paint()..color = Colors.orangeAccent..style = PaintingStyle.stroke..strokeWidth = 1.5);
}
if (showSma200 && !firstSma200) {
canvas.drawPath(sma200Path, Paint()..color = Colors.purpleAccent..style = PaintingStyle.stroke..strokeWidth = 2.0);
canvas.drawPath(sma200Path, Paint()..color = Colors.redAccent..style = PaintingStyle.stroke..strokeWidth = 2.0);
}
if (showSupertrend && !firstSupertrend) {
canvas.drawPath(supertrendPath, Paint()..color = Colors.lightBlueAccent..style = PaintingStyle.stroke..strokeWidth = 2.0);
canvas.drawPath(supertrendPath, Paint()..color = AppTheme.primaryEmerald..style = PaintingStyle.stroke..strokeWidth = 2.0);
}
if (showPatterns) {
@@ -702,12 +703,13 @@ class _CandlePainter extends CustomPainter {
}
void _drawPatterns(Canvas canvas, double Function(DateTime) getX, double Function(double) getY) {
final paint = Paint()
..color = Colors.orangeAccent
..style = PaintingStyle.stroke
..strokeWidth = 2.0;
for (var pattern in patterns) {
final color = PatternExplanations.getColorForPattern(pattern.type);
final paint = Paint()
..color = color
..style = PaintingStyle.stroke
..strokeWidth = 2.0;
void drawLine(List<PatternPoint> points) {
if (points.length < 2) return;
final path = Path();
@@ -6,19 +6,19 @@ import '../../../../shared/widgets/favorite_star_button.dart';
import '../../bloc/header/asset_header_bloc.dart';
import '../../bloc/header/asset_header_state.dart';
import '../../models/asset_model.dart';
import 'package:url_launcher/url_launcher.dart';
class AssetHeroHeader extends StatelessWidget {
final String symbol;
final String isin;
final String name;
final String? symbol;
final void Function(String exchange, String ticker)? onExchangeChanged;
final VoidCallback? onForceRefresh;
final String? selectedExchange;
const AssetHeroHeader({
super.key,
required this.symbol,
this.onExchangeChanged,
this.onForceRefresh,
this.selectedExchange,
this.onForceRefresh, required this.isin, required this.name, this.symbol,
});
@override
@@ -27,10 +27,8 @@ class AssetHeroHeader extends StatelessWidget {
return BlocBuilder<AssetHeaderBloc, AssetHeaderState>(
builder: (context, state) {
String name = symbol;
double? price;
String currency = 'EUR';
String currentExchange = selectedExchange ?? 'XETRA';
List<AssetTickerOption> tickerOptions = [
AssetTickerOption(ticker: 'Loading', exchange: 'Loading', tradingCurrency: '', currentPrice: 0.0)
];
@@ -43,10 +41,9 @@ class AssetHeroHeader extends StatelessWidget {
}
if (asset != null) {
name = asset.name.isNotEmpty ? asset.name : symbol;
//name = asset.name.isNotEmpty ? asset.name : symbol;
currency = asset.currency.isNotEmpty ? asset.currency : 'EUR';
price = asset.currentPrice;
currentExchange = selectedExchange ?? asset.exchange;
if (asset.tickers.isNotEmpty) {
tickerOptions = asset.tickers;
@@ -54,7 +51,7 @@ class AssetHeroHeader extends StatelessWidget {
}
final selectedOption = tickerOptions.firstWhere(
(t) => t.exchange == currentExchange,
(t) => t.ticker == symbol || t.exchange == symbol,
orElse: () => tickerOptions.first,
);
@@ -89,7 +86,7 @@ class AssetHeroHeader extends StatelessWidget {
),
const SizedBox(width: 8),
],
AssetLogoWidget(symbolOrName: symbol, size: 48),
AssetLogoWidget(symbolOrName: isin, imageUrl: asset?.image, size: 48),
const SizedBox(width: 16),
Expanded(
child: Column(
@@ -106,7 +103,7 @@ class AssetHeroHeader extends StatelessWidget {
),
const SizedBox(height: 2),
SelectableText(
symbol,
isin,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
@@ -122,13 +119,24 @@ class AssetHeroHeader extends StatelessWidget {
),
Row(
children: [
IconButton(
tooltip: 'Open in Yahoo Finance',
icon: Icon(Icons.open_in_new, color: theme.textSecondary),
onPressed: () async {
final url = Uri.parse('https://finance.yahoo.com/quote/${selectedOption.ticker}');
if (await canLaunchUrl(url)) {
await launchUrl(url, mode: LaunchMode.externalApplication);
}
},
),
const SizedBox(width: 8),
IconButton(
tooltip: 'Force Refresh Data',
icon: Icon(Icons.refresh, color: theme.primaryColor),
onPressed: onForceRefresh,
),
const SizedBox(width: 8),
FavoriteStarButton(symbol: symbol, identifier: symbol, name: name),
FavoriteStarButton(symbol: symbol, identifier: isin, name: name),
],
),
],
@@ -142,7 +150,7 @@ class AssetHeroHeader extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'LIVE PRICE',
'AKTUELLER PREIS',
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.bold,
@@ -180,15 +188,15 @@ class AssetHeroHeader extends StatelessWidget {
),
// Interactive Ticker & Exchange Selector Dropdown
PopupMenuButton<String>(
initialValue: selectedOption.exchange,
initialValue: selectedOption.ticker,
tooltip: 'Select Exchange & Ticker',
onSelected: (newExchange) {
onSelected: (newTicker) {
if (onExchangeChanged != null) {
final opt = tickerOptions.firstWhere(
(t) => t.exchange == newExchange,
(t) => t.ticker == newTicker,
orElse: () => tickerOptions.first,
);
onExchangeChanged!(newExchange, opt.ticker);
onExchangeChanged!(opt.exchange, opt.ticker);
}
},
itemBuilder: (context) {
@@ -196,10 +204,10 @@ class AssetHeroHeader extends StatelessWidget {
final ex = opt.exchange;
final tick = opt.ticker;
final label = '$tick ($ex)';
final isSelected = ex == currentExchange;
final isSelected = tick == symbol || ex == symbol;
return PopupMenuItem<String>(
value: ex,
value: tick,
child: Row(
children: [
Icon(