Files

238 lines
9.1 KiB
Dart

import 'package:flutter/material.dart';
import '../../../../core/theme/app_theme.dart';
import '../models/trade_acceptance_dto.dart';
import '../models/trade_model.dart';
class TradeAcceptanceDialog extends StatefulWidget {
final TradeModel trade;
final ThemePreset theme;
final String userId;
const TradeAcceptanceDialog({
super.key,
required this.trade,
required this.theme,
required this.userId,
});
@override
State<TradeAcceptanceDialog> createState() => _TradeAcceptanceDialogState();
}
class _TradeAcceptanceDialogState extends State<TradeAcceptanceDialog> {
late TextEditingController _entryPriceCtrl;
late TextEditingController _positionSizeCtrl;
late TextEditingController _leverageCtrl;
late TextEditingController _entryFeeCtrl;
late TextEditingController _exitFeeCtrl;
late TextEditingController _quantityCtrl;
late TextEditingController _stopLossCtrl;
late TextEditingController _takeProfitCtrl;
late TextEditingController _notesCtrl;
bool _isRecurring = false;
@override
void initState() {
super.initState();
_entryPriceCtrl = TextEditingController(text: widget.trade.averageBuyIn.toStringAsFixed(2));
_positionSizeCtrl = TextEditingController(text: '1000');
_leverageCtrl = TextEditingController(text: '1');
_stopLossCtrl = TextEditingController(text: widget.trade.currentStopLoss.toStringAsFixed(2));
_takeProfitCtrl = TextEditingController(text: (widget.trade.primaryTakeProfit ?? 0.0).toStringAsFixed(2));
_notesCtrl = TextEditingController();
_entryFeeCtrl = TextEditingController(text: '0.00');
_exitFeeCtrl = TextEditingController(text: '0.00');
double price = widget.trade.averageBuyIn;
_quantityCtrl = TextEditingController(text: (1000 / (price > 0 ? price : 1)).toStringAsFixed(4));
}
@override
void dispose() {
_entryPriceCtrl.dispose();
_positionSizeCtrl.dispose();
_leverageCtrl.dispose();
_stopLossCtrl.dispose();
_takeProfitCtrl.dispose();
_notesCtrl.dispose();
_entryFeeCtrl.dispose();
_exitFeeCtrl.dispose();
_quantityCtrl.dispose();
super.dispose();
}
double? _parseNum(String text) {
final cleaned = text.replaceAll(',', '.').trim();
return double.tryParse(cleaned);
}
void _recalcQuantity() {
double posSize = _parseNum(_positionSizeCtrl.text) ?? 0;
double price = _parseNum(_entryPriceCtrl.text) ?? 0;
if (price > 0) {
_quantityCtrl.text = (posSize / price).toStringAsFixed(4);
}
}
@override
Widget build(BuildContext context) {
return Dialog(
backgroundColor: Colors.transparent,
insetPadding: const EdgeInsets.all(16),
child: Container(
width: 450,
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: widget.theme.cardSurface,
borderRadius: BorderRadius.circular(20),
border: Border.all(color: widget.theme.glassBorder, width: 1),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.5),
blurRadius: 20,
offset: const Offset(0, 10),
)
],
),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.add_shopping_cart, color: widget.theme.primaryColor, size: 28),
const SizedBox(width: 12),
Expanded(
child: Text(
'Trade Akzeptieren - ${widget.trade.symbol}',
style: TextStyle(
color: widget.theme.textPrimary,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
IconButton(
onPressed: () => Navigator.of(context).pop(),
icon: Icon(Icons.close, color: widget.theme.textMuted),
)
],
),
const SizedBox(height: 24),
_buildInputField('Kaufkurs / Entry Price', _entryPriceCtrl, Icons.attach_money, onChanged: (_) => _recalcQuantity()),
const SizedBox(height: 16),
Row(
children: [
Expanded(child: _buildInputField('Kapital (Position Size)', _positionSizeCtrl, Icons.account_balance_wallet, onChanged: (_) => _recalcQuantity())),
const SizedBox(width: 16),
Expanded(child: _buildInputField('Stückzahl (Quantity)', _quantityCtrl, Icons.format_list_numbered)),
],
),
const SizedBox(height: 16),
Row(
children: [
Expanded(child: _buildInputField('Stop Loss', _stopLossCtrl, Icons.block)),
const SizedBox(width: 16),
Expanded(child: _buildInputField('Take Profit', _takeProfitCtrl, Icons.trending_up)),
],
),
const SizedBox(height: 16),
Row(
children: [
Expanded(child: _buildInputField('Hebel (Leverage)', _leverageCtrl, Icons.speed)),
const SizedBox(width: 16),
Expanded(
child: CheckboxListTile(
title: Text('Sparplan', style: TextStyle(color: widget.theme.textPrimary, fontSize: 14)),
value: _isRecurring,
activeColor: widget.theme.primaryColor,
checkColor: Colors.white,
onChanged: (val) {
setState(() {
_isRecurring = val ?? false;
});
},
contentPadding: EdgeInsets.zero,
controlAffinity: ListTileControlAffinity.leading,
),
),
],
),
const SizedBox(height: 16),
_buildInputField('Notizen', _notesCtrl, Icons.edit),
const SizedBox(height: 32),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
final dto = TradeAcceptanceDto(
userId: widget.userId,
tradeId: widget.trade.id,
isin: widget.trade.underlyingIsin,
symbol: widget.trade.symbol,
actualEntryPrice: _parseNum(_entryPriceCtrl.text),
positionSize: _parseNum(_positionSizeCtrl.text),
leverageUsed: _parseNum(_leverageCtrl.text) ?? 1.0,
entryFee: _parseNum(_entryFeeCtrl.text) ?? 0.0,
exitFee: _parseNum(_exitFeeCtrl.text) ?? 0.0,
quantity: _parseNum(_quantityCtrl.text),
isRecurring: _isRecurring,
executionTimestamp: DateTime.now().toUtc(),
signalType: widget.trade.direction.label,
entryPrice: widget.trade.averageBuyIn,
stopLoss: widget.trade.currentStopLoss,
takeProfit: widget.trade.primaryTakeProfit,
instrumentType: widget.trade.instrumentType.label,
);
Navigator.of(context).pop(dto);
},
style: ElevatedButton.styleFrom(
backgroundColor: widget.theme.primaryColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
child: const Text('Jetzt Ausführen', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
),
),
],
),
),
),
);
}
Widget _buildInputField(String label, TextEditingController controller, IconData icon, {Function(String)? onChanged}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: TextStyle(color: widget.theme.textSecondary, fontSize: 12)),
const SizedBox(height: 6),
TextField(
controller: controller,
style: TextStyle(color: widget.theme.textPrimary),
keyboardType: const TextInputType.numberWithOptions(decimal: true),
onChanged: onChanged,
decoration: InputDecoration(
prefixIcon: Icon(icon, color: widget.theme.textMuted, size: 18),
filled: true,
fillColor: widget.theme.darkBackground.withValues(alpha: 0.5),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none,
),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
),
),
],
);
}
}