feat(app): add evaluation history, bot control panel, simulation visualizer, and vendored signalr_core
This commit is contained in:
@@ -35,7 +35,7 @@ class DashboardScreen extends StatelessWidget {
|
||||
const SizedBox(height: 24),
|
||||
TradesStreamWidget(apiClient: apiClient),
|
||||
const SizedBox(height: 24),
|
||||
DailyNewsSnapshot(apiClient: apiClient),
|
||||
DailyNewsSnapshot(apiClient: apiClient, signalRService: signalRService),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../../core/network/api_client.dart';
|
||||
import '../../../core/network/signalr_service.dart';
|
||||
import '../../../core/theme/app_theme.dart';
|
||||
import '../../../core/utils/time_utils.dart';
|
||||
import '../../../core/widgets/glass_container.dart';
|
||||
@@ -14,11 +15,13 @@ import '../../news/widgets/article_sentiment_dialog.dart';
|
||||
|
||||
class DailyNewsSnapshot extends StatelessWidget {
|
||||
final ApiClient apiClient;
|
||||
final SignalRService? signalRService;
|
||||
final String? backendUrl;
|
||||
|
||||
const DailyNewsSnapshot({
|
||||
super.key,
|
||||
required this.apiClient,
|
||||
this.signalRService,
|
||||
this.backendUrl,
|
||||
});
|
||||
|
||||
@@ -26,7 +29,11 @@ class DailyNewsSnapshot extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => NewsBloc(
|
||||
repository: NewsRepository(apiClient: apiClient, backendUrl: backendUrl ?? ApiClient.baseUrl),
|
||||
repository: NewsRepository(
|
||||
apiClient: apiClient,
|
||||
backendUrl: backendUrl ?? ApiClient.baseUrl,
|
||||
signalRService: signalRService,
|
||||
),
|
||||
)..add(FetchNews(date: DateTime.now().toIso8601String().substring(0, 10))),
|
||||
child: const _DailyNewsSnapshotContent(),
|
||||
);
|
||||
|
||||
@@ -75,7 +75,7 @@ class FavoritesCarousel extends StatelessWidget {
|
||||
children: [
|
||||
AssetLogoWidget(
|
||||
symbolOrName: isin,
|
||||
imageUrl: fav.image.isNotEmpty ? fav.image : null,
|
||||
imageUrl: isin.isNotEmpty ? '/api/v1/logo/$isin' : (fav.image.isNotEmpty ? fav.image : null),
|
||||
size: 24,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
|
||||
@@ -101,7 +101,7 @@ class _TradesStreamWidgetContent extends StatelessWidget {
|
||||
itemCount: proposals.length,
|
||||
itemBuilder: (context, index) {
|
||||
final p = proposals[index];
|
||||
final isBuy = p.signalType.toUpperCase() == 'BUY' || p.signalType.toUpperCase() == 'LONG';
|
||||
final isBuy = p.direction.isLong;
|
||||
final signalColor = isBuy ? AppTheme.primaryEmerald : AppTheme.accentRed;
|
||||
|
||||
return GestureDetector(
|
||||
@@ -110,8 +110,8 @@ class _TradesStreamWidgetContent extends StatelessWidget {
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (ctx) => AssetDetailScreen(
|
||||
isin: p.isin,
|
||||
name: p.companyName,
|
||||
isin: p.underlyingIsin,
|
||||
name: p.symbol,
|
||||
symbol: p.symbol.isNotEmpty ? p.symbol : null,
|
||||
apiClient: context.read<TradeBloc>().repository.apiClient,
|
||||
),
|
||||
@@ -158,35 +158,24 @@ class _TradesStreamWidgetContent extends StatelessWidget {
|
||||
border: Border.all(color: signalColor.withValues(alpha: 0.3)),
|
||||
),
|
||||
child: Text(
|
||||
p.signalType,
|
||||
p.direction.label,
|
||||
style: TextStyle(color: signalColor, fontWeight: FontWeight.bold, fontSize: 11),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (p.companyName.isNotEmpty) ...[
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
p.companyName,
|
||||
style: TextStyle(color: AppTheme.textMuted, fontSize: 12),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
p.underlyingIsin,
|
||||
style: TextStyle(color: AppTheme.textMuted, fontSize: 12),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const Spacer(),
|
||||
if (p.reasoning.isNotEmpty) ...[
|
||||
Text(
|
||||
p.reasoning,
|
||||
style: const TextStyle(color: Colors.white70, fontSize: 11, fontStyle: FontStyle.italic),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
],
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
'KI Score: ${(p.winRate).toStringAsFixed(0)}%',
|
||||
p.instrumentType.label,
|
||||
style: TextStyle(color: AppTheme.accentCyan, fontWeight: FontWeight.w600, fontSize: 13),
|
||||
),
|
||||
const Spacer(),
|
||||
|
||||
Reference in New Issue
Block a user