@marcos_feitoza/personal-finance-frontend-feature-investments 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [1.1.2](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/compare/v1.1.1...v1.1.2) (2025-12-03)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * refatoração das telas InvestmentAccountScreen, CryptoAccountScreen e RrspSunLifeScreen para o padrão ViewModel com ChangeNotifier ([20419ac](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/commit/20419ac0c38259469c69389496ec7e24c6d95e3b))
7
+
8
+ ## [1.1.1](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/compare/v1.1.0...v1.1.1) (2025-12-02)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * add AppDialogs.showDeleteConfirmationDialog ([29c41f8](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/commit/29c41f80530906111efe5fac1c3c493c78a29a62))
14
+
1
15
  # [1.1.0](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/compare/v1.0.1...v1.1.0) (2025-11-28)
2
16
 
3
17
 
@@ -1,239 +1,123 @@
1
1
  import 'package:flutter/material.dart';
2
2
  import 'package:intl/intl.dart';
3
- import 'package:personal_finance_frontend_core_services/services/crypto_service.dart';
4
- import 'package:personal_finance_frontend_core_services/services/transaction_service.dart';
5
- import 'package:personal_finance_frontend_core_ui/widgets/crypto_trade_form.dart';
6
- import 'package:personal_finance_frontend_core_ui/widgets/app_widgets.dart';
7
3
  import 'package:provider/provider.dart';
8
4
  import 'package:personal_finance_frontend_core_services/providers/auth_provider.dart';
5
+ import 'package:personal_finance_frontend_core_ui/utils/app_dialogs.dart';
6
+ import 'package:personal_finance_frontend_core_ui/widgets/crypto_trade_form.dart';
7
+ import '../viewmodels/crypto_account_viewmodel.dart';
9
8
 
10
- class CryptoAccountScreen extends StatefulWidget {
9
+ class CryptoAccountScreen extends StatelessWidget {
11
10
  final String accountName;
12
11
 
13
- const CryptoAccountScreen({Key? key, required this.accountName}) : super(key: key);
14
-
15
- @override
16
- _CryptoAccountScreenState createState() => _CryptoAccountScreenState();
17
- }
18
-
19
- class _CryptoAccountScreenState extends State<CryptoAccountScreen> {
20
- final TransactionService _transactionService = TransactionService();
21
- final CryptoService _cryptoService = CryptoService();
22
-
23
- List<Map<String, dynamic>> _trades = [];
24
- List<Map<String, dynamic>> _assets = [];
25
- List<Map<String, dynamic>> _portfolioSummary = [];
26
- Map<String, double> _livePrices = {};
27
- double _cashBalance = 0.0;
28
- double _accountTotalValue = 0.0;
29
- double _totalPortfolioBookCost = 0.0;
30
- bool _isLoading = true;
31
- bool _isFetchingPrices = false;
32
- String? _selectedSymbolForFilter;
33
- String? _token;
34
-
35
- @override
36
- void initState() {
37
- super.initState();
38
- WidgetsBinding.instance.addPostFrameCallback((_) {
39
- final authProvider = Provider.of<AuthProvider>(context, listen: false);
40
- setState(() {
41
- _token = authProvider.token;
42
- });
43
- _fetchData();
44
- });
45
- }
46
-
47
- String currencySymbol = r'$';
48
-
49
- String _formatCurrency(double value) {
50
- return '$currencySymbol${value.toStringAsFixed(2)}';
51
- }
52
-
53
- Future<void> _fetchData() async {
54
- if (_token == null) return;
55
- setState(() => _isLoading = true);
56
- try {
57
- final futures = <Future>[
58
- _transactionService.getTrades(investmentAccount: widget.accountName, token: _token),
59
- _transactionService.getAccountBalance(widget.accountName, token: _token),
60
- _transactionService.getAssets(investmentAccount: widget.accountName, token: _token),
61
- _transactionService.getTotalPortfolioBookCost(token: _token), // Fetch total cost
62
- ];
63
- final results = await Future.wait(futures);
64
-
65
- final trades = results[0] as List<Map<String, dynamic>>;
66
- final balance = results[1] as double;
67
- final assets = results[2] as List<Map<String, dynamic>>;
68
- final totalPortfolioBookCost = results[3] as double;
69
-
70
- final summaryData = _calculatePortfolioSummary(trades, totalPortfolioBookCost);
71
-
72
- setState(() {
73
- _trades = trades;
74
- _cashBalance = balance;
75
- _assets = assets;
76
- _portfolioSummary = summaryData['summary'];
77
- _accountTotalValue = summaryData['total_value'] + _cashBalance;
78
- _totalPortfolioBookCost = totalPortfolioBookCost;
79
- });
80
-
81
- if (mounted) await _fetchLivePrices();
82
- } catch (e) {
83
- if (mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Error fetching data: $e')));
84
- } finally {
85
- if (mounted) setState(() => _isLoading = false);
86
- }
87
- }
88
-
89
- Future<void> _fetchLivePrices() async {
90
- if (_portfolioSummary.isEmpty || !mounted) return;
91
- setState(() => _isFetchingPrices = true);
92
-
93
- final idsToFetch = _portfolioSummary.map((p) => p['id_crypto'] as String? ?? p['symbol'] as String).where((s) => s.isNotEmpty).toList();
94
-
95
- if (idsToFetch.isEmpty) {
96
- setState(() => _isFetchingPrices = false);
97
- return;
98
- }
99
-
100
- final livePrices = await _cryptoService.getLiveCryptoPrices(idsToFetch);
101
-
102
- if (!mounted) return;
103
-
104
- double newTotalValue = _cashBalance;
105
- for (final position in _portfolioSummary) {
106
- final shares = double.parse(position['shares'].toString());
107
- final idForLookup = (position['id_crypto'] as String? ?? position['symbol'] as String).toLowerCase();
108
- final livePrice = livePrices[idForLookup];
109
- if (livePrice != null) {
110
- newTotalValue += shares * livePrice;
111
- } else {
112
- newTotalValue += (position['total_cost'] as num?)?.toDouble() ?? 0.0;
113
- }
114
- }
115
-
116
- setState(() {
117
- _livePrices = livePrices;
118
- _accountTotalValue = newTotalValue;
119
- _isFetchingPrices = false;
120
- });
121
- }
122
-
123
- Map<String, dynamic> _calculatePortfolioSummary(List<Map<String, dynamic>> trades, double totalPortfolioBookCost) {
124
- Map<String, dynamic> summary = {};
125
- double accountPortfolioBookCost = 0;
126
-
127
- for (var trade in trades) {
128
- final asset = trade['asset'];
129
- if (asset == null || asset['symbol'] == null) continue;
130
- String symbol = asset['symbol'];
131
- String idCrypto = asset['id_crypto'] ?? symbol;
132
-
133
- double shares = double.parse(trade['shares'].toString());
134
- double price = double.parse(trade['price'].toString());
135
- String tradeType = trade['trade_type'];
136
-
137
- if (!summary.containsKey(symbol)) {
138
- summary[symbol] = {
139
- 'symbol': symbol,
140
- 'id_crypto': idCrypto,
141
- 'name': asset['name'] ?? symbol,
142
- 'shares': 0.0,
143
- 'total_cost': 0.0,
144
- };
145
- }
146
-
147
- if (tradeType == 'buy') {
148
- summary[symbol]['shares'] += shares;
149
- summary[symbol]['total_cost'] += shares * price;
150
- } else if (tradeType == 'sell') {
151
- double originalShares = summary[symbol]['shares'];
152
- if (originalShares > 0) {
153
- double avgPrice = summary[symbol]['total_cost'] / originalShares;
154
- summary[symbol]['total_cost'] -= shares * avgPrice;
155
- }
156
- summary[symbol]['shares'] -= shares;
157
- }
158
- }
159
-
160
- summary.removeWhere((key, value) => value['shares'] < 0.01);
161
- accountPortfolioBookCost = summary.values.fold(0.0, (sum, item) => sum + item['total_cost']);
162
-
163
- List<Map<String, dynamic>> result = [];
164
- summary.forEach((symbol, data) {
165
- double shares = data['shares'];
166
- double totalCost = data['total_cost'];
167
- data['avg_price'] = (shares > 0) ? totalCost / shares : 0.0;
168
- data['account_allocation'] = (accountPortfolioBookCost > 0) ? (totalCost / accountPortfolioBookCost) * 100 : 0.0;
169
- data['stocks_allocation'] = (totalPortfolioBookCost > 0) ? (totalCost / totalPortfolioBookCost) * 100 : 0.0;
170
- result.add(data);
171
- });
172
-
173
- return {'summary': result, 'total_value': accountPortfolioBookCost};
174
- }
175
-
12
+ const CryptoAccountScreen({Key? key, required this.accountName})
13
+ : super(key: key);
176
14
 
177
15
  @override
178
16
  Widget build(BuildContext context) {
179
- return Scaffold(
180
- appBar: AppBar(
181
- title: Text('${widget.accountName} Portfolio'),
182
- actions: [
183
- Center(
184
- child: Padding(
185
- padding: const EdgeInsets.only(right: 16.0),
186
- child: Column(
187
- mainAxisAlignment: MainAxisAlignment.center,
188
- crossAxisAlignment: CrossAxisAlignment.end,
189
- children: [
190
- Text('Total Portfolio: ${_formatCurrency(_accountTotalValue)}', style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
191
- Text('Account Balance: ${_formatCurrency(_cashBalance)}', style: const TextStyle(fontSize: 12)),
192
- ],
193
- ),
194
- ),
195
- ),
196
- IconButton(icon: const Icon(Icons.refresh), onPressed: _fetchData, tooltip: 'Refresh Data'),
197
- ],
17
+ final authProvider = Provider.of<AuthProvider>(context, listen: false);
18
+
19
+ return ChangeNotifierProvider(
20
+ create: (_) => CryptoAccountViewModel(
21
+ accountName: accountName,
22
+ token: authProvider.token,
198
23
  ),
199
- body: _isLoading
200
- ? const Center(child: CircularProgressIndicator())
201
- : RefreshIndicator(
202
- onRefresh: _fetchData,
203
- child: SingleChildScrollView(
204
- physics: const AlwaysScrollableScrollPhysics(),
205
- padding: const EdgeInsets.all(16.0),
206
- child: Column(
207
- crossAxisAlignment: CrossAxisAlignment.stretch,
208
- children: [
209
- Row(
210
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
24
+ child: Consumer<CryptoAccountViewModel>(
25
+ builder: (context, viewModel, child) {
26
+ return Scaffold(
27
+ appBar: AppBar(
28
+ title: Text('$accountName Portfolio'),
29
+ actions: [
30
+ Center(
31
+ child: Padding(
32
+ padding: const EdgeInsets.only(right: 16.0),
33
+ child: Column(
34
+ mainAxisAlignment: MainAxisAlignment.center,
35
+ crossAxisAlignment: CrossAxisAlignment.end,
211
36
  children: [
212
- Text('Portfolio Summary', style: Theme.of(context).textTheme.titleLarge),
213
- if (_isFetchingPrices) const SizedBox(height: 20, width: 20, child: CircularProgressIndicator(strokeWidth: 2.0)),
37
+ Text(
38
+ 'Total Portfolio: ${_formatCurrency(viewModel.accountTotalValue)}',
39
+ style: const TextStyle(
40
+ fontSize: 16, fontWeight: FontWeight.bold),
41
+ ),
42
+ Text(
43
+ 'Account Balance: ${_formatCurrency(viewModel.cashBalance)}',
44
+ style: const TextStyle(fontSize: 12),
45
+ ),
214
46
  ],
215
47
  ),
216
- _buildSinteticoTable(),
217
- const SizedBox(height: 24),
218
- CryptoTradeForm(
219
- accountName: widget.accountName,
220
- portfolioSummary: _portfolioSummary,
221
- onTradeCreated: (_) => _fetchData(),
222
- token: _token),
223
- const SizedBox(height: 24),
224
- Text('Trade History', style: Theme.of(context).textTheme.titleLarge),
225
- const SizedBox(height: 8),
226
- _buildAnaliticoTable(),
227
- ],
48
+ ),
49
+ ),
50
+ IconButton(
51
+ icon: const Icon(Icons.refresh),
52
+ onPressed: viewModel.fetchData,
53
+ tooltip: 'Refresh Data',
228
54
  ),
229
- ),
55
+ ],
230
56
  ),
57
+ body: viewModel.isLoading
58
+ ? const Center(child: CircularProgressIndicator())
59
+ : RefreshIndicator(
60
+ onRefresh: viewModel.fetchData,
61
+ child: SingleChildScrollView(
62
+ physics: const AlwaysScrollableScrollPhysics(),
63
+ padding: const EdgeInsets.all(16.0),
64
+ child: Column(
65
+ crossAxisAlignment: CrossAxisAlignment.stretch,
66
+ children: [
67
+ Row(
68
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
69
+ children: [
70
+ Text('Portfolio Summary',
71
+ style:
72
+ Theme.of(context).textTheme.titleLarge),
73
+ if (viewModel.isFetchingPrices)
74
+ const SizedBox(
75
+ height: 20,
76
+ width: 20,
77
+ child: CircularProgressIndicator(
78
+ strokeWidth: 2.0),
79
+ ),
80
+ ],
81
+ ),
82
+ _buildSinteticoTable(context, viewModel),
83
+ const SizedBox(height: 24),
84
+ CryptoTradeForm(
85
+ accountName: accountName,
86
+ portfolioSummary: viewModel.portfolioSummary,
87
+ onTradeCreated: (_) => viewModel.fetchData(),
88
+ token: viewModel.token,
89
+ ),
90
+ const SizedBox(height: 24),
91
+ Text('Trade History',
92
+ style: Theme.of(context).textTheme.titleLarge),
93
+ const SizedBox(height: 8),
94
+ _buildAnaliticoTable(context, viewModel),
95
+ ],
96
+ ),
97
+ ),
98
+ ),
99
+ );
100
+ },
101
+ ),
231
102
  );
232
103
  }
233
104
 
234
- Widget _buildSinteticoTable() {
235
- if (_portfolioSummary.isEmpty) return const Center(child: Padding(padding: EdgeInsets.all(16.0), child: Text('No positions held.')));
236
-
105
+ String _formatCurrency(double value) {
106
+ String currencySymbol = r'$';
107
+ return '$currencySymbol${value.toStringAsFixed(2)}';
108
+ }
109
+
110
+ Widget _buildSinteticoTable(
111
+ BuildContext context, CryptoAccountViewModel viewModel) {
112
+ if (viewModel.portfolioSummary.isEmpty) {
113
+ return const Center(
114
+ child: Padding(
115
+ padding: EdgeInsets.all(16.0),
116
+ child: Text('No positions held.'),
117
+ ),
118
+ );
119
+ }
120
+
237
121
  return SingleChildScrollView(
238
122
  scrollDirection: Axis.horizontal,
239
123
  child: DataTable(
@@ -250,51 +134,85 @@ class _CryptoAccountScreenState extends State<CryptoAccountScreen> {
250
134
  DataColumn(label: Text('Return')),
251
135
  DataColumn(label: Text('% Return')),
252
136
  ],
253
- rows: _portfolioSummary.map((position) {
137
+ rows: viewModel.portfolioSummary.map((position) {
254
138
  final symbol = position['symbol'] as String;
255
- final idForLookup = (position['id_crypto'] as String? ?? symbol).toLowerCase();
256
- final livePrice = _livePrices[idForLookup];
139
+ final idForLookup =
140
+ (position['id_crypto'] as String? ?? symbol).toLowerCase();
141
+ final livePrice = viewModel.livePrices[idForLookup];
257
142
  final shares = double.parse(position['shares'].toString());
258
143
  final avgPrice = double.parse(position['avg_price'].toString());
259
- final totalPurchased = double.parse(position['total_cost'].toString());
260
- final accountAllocation = (position['account_allocation'] as num?)?.toDouble() ?? 0.0;
261
- final stocksAllocation = (position['stocks_allocation'] as num?)?.toDouble() ?? 0.0;
144
+ final totalPurchased =
145
+ double.parse(position['total_cost'].toString());
146
+ final accountAllocation =
147
+ (position['account_allocation'] as num?)?.toDouble() ?? 0.0;
148
+ final stocksAllocation =
149
+ (position['stocks_allocation'] as num?)?.toDouble() ?? 0.0;
262
150
 
263
151
  double? totalReturnValue, percentageReturn;
264
152
 
265
153
  if (livePrice != null && shares > 0) {
266
154
  final currentMarketValue = livePrice * shares;
267
155
  totalReturnValue = currentMarketValue - totalPurchased;
268
- if (totalPurchased > 0) percentageReturn = (totalReturnValue / totalPurchased) * 100;
156
+ if (totalPurchased > 0) {
157
+ percentageReturn = (totalReturnValue / totalPurchased) * 100;
158
+ }
269
159
  }
270
160
 
271
- final returnColor = (totalReturnValue ?? 0) >= 0 ? Colors.green : Colors.red;
161
+ final returnColor =
162
+ (totalReturnValue ?? 0) >= 0 ? Colors.green : Colors.red;
272
163
 
273
164
  return DataRow(cells: [
274
- DataCell(SizedBox(width: 150, child: Text(position['name'] as String, overflow: TextOverflow.ellipsis))),
165
+ DataCell(SizedBox(
166
+ width: 150,
167
+ child: Text(position['name'] as String,
168
+ overflow: TextOverflow.ellipsis))),
275
169
  DataCell(Text(symbol)),
276
170
  DataCell(Text(shares.toStringAsFixed(6))),
277
171
  DataCell(Text(_formatCurrency(avgPrice))),
278
- DataCell(livePrice != null ? Text(_formatCurrency(livePrice)) : const Text('N/A')),
172
+ DataCell(livePrice != null
173
+ ? Text(_formatCurrency(livePrice))
174
+ : const Text('N/A')),
279
175
  DataCell(Text(_formatCurrency(totalPurchased))),
280
176
  DataCell(Text('${accountAllocation.toStringAsFixed(2)}%')),
281
177
  DataCell(Text('${stocksAllocation.toStringAsFixed(2)}%')),
282
- DataCell(totalReturnValue != null ? Text(_formatCurrency(totalReturnValue), style: TextStyle(color: returnColor)) : const Text('N/A')),
283
- DataCell(percentageReturn != null ? Text('${percentageReturn.toStringAsFixed(2)}%', style: TextStyle(color: returnColor)) : const Text('N/A')),
178
+ DataCell(
179
+ totalReturnValue != null
180
+ ? Text(_formatCurrency(totalReturnValue),
181
+ style: TextStyle(color: returnColor))
182
+ : const Text('N/A'),
183
+ ),
184
+ DataCell(
185
+ percentageReturn != null
186
+ ? Text('${percentageReturn.toStringAsFixed(2)}%',
187
+ style: TextStyle(color: returnColor))
188
+ : const Text('N/A'),
189
+ ),
284
190
  ]);
285
191
  }).toList(),
286
192
  ),
287
193
  );
288
194
  }
289
195
 
290
- Widget _buildAnaliticoTable() {
291
- if (_trades.isEmpty) return const Center(child: Padding(padding: EdgeInsets.all(16.0), child: Text('No trades found.')));
196
+ Widget _buildAnaliticoTable(
197
+ BuildContext context, CryptoAccountViewModel viewModel) {
198
+ if (viewModel.trades.isEmpty) {
199
+ return const Center(
200
+ child: Padding(
201
+ padding: EdgeInsets.all(16.0),
202
+ child: Text('No trades found.'),
203
+ ),
204
+ );
205
+ }
292
206
 
293
- final sortedTrades = List<Map<String, dynamic>>.from(_trades)..sort((a, b) {
294
- try {
295
- return DateTime.parse(b['date'] as String).compareTo(DateTime.parse(a['date'] as String));
296
- } catch (e) { return 0; }
297
- });
207
+ final sortedTrades = List<Map<String, dynamic>>.from(viewModel.trades)
208
+ ..sort((a, b) {
209
+ try {
210
+ return DateTime.parse(b['date'] as String)
211
+ .compareTo(DateTime.parse(a['date'] as String));
212
+ } catch (e) {
213
+ return 0;
214
+ }
215
+ });
298
216
 
299
217
  return DataTable(
300
218
  columns: const [
@@ -304,14 +222,14 @@ class _CryptoAccountScreenState extends State<CryptoAccountScreen> {
304
222
  DataColumn(label: Text('Quantity')),
305
223
  DataColumn(label: Text('Price')),
306
224
  DataColumn(label: Text('Total')),
307
- DataColumn(label: Text('Actions')), // New column
225
+ DataColumn(label: Text('Actions')),
308
226
  ],
309
227
  rows: sortedTrades.map((trade) {
310
228
  final double shares = double.parse(trade['shares'].toString());
311
229
  final double price = double.parse(trade['price'].toString());
312
230
  final double total = shares * price;
313
231
  final tradeDate = DateTime.parse(trade['date'] as String);
314
- final int tradeId = trade['id'] as int; // Get trade ID
232
+ final int tradeId = trade['id'] as int;
315
233
 
316
234
  return DataRow(cells: [
317
235
  DataCell(Text(DateFormat('yyyy-MM-dd').format(tradeDate))),
@@ -320,10 +238,11 @@ class _CryptoAccountScreenState extends State<CryptoAccountScreen> {
320
238
  DataCell(Text(shares.toStringAsFixed(6))),
321
239
  DataCell(Text(_formatCurrency(price))),
322
240
  DataCell(Text(_formatCurrency(total))),
323
- DataCell( // New cell for the delete button
241
+ DataCell(
324
242
  IconButton(
325
243
  icon: const Icon(Icons.delete, color: Colors.red),
326
- onPressed: () => _confirmAndDeleteTrade(tradeId),
244
+ onPressed: () =>
245
+ _confirmAndDeleteTrade(context, viewModel, tradeId),
327
246
  tooltip: 'Delete Trade',
328
247
  ),
329
248
  ),
@@ -332,51 +251,22 @@ class _CryptoAccountScreenState extends State<CryptoAccountScreen> {
332
251
  );
333
252
  }
334
253
 
335
- Future<void> _confirmAndDeleteTrade(int tradeId) async {
336
- final bool? confirm = await showDialog<bool>(
337
- context: context,
338
- builder: (BuildContext context) {
339
- return AlertDialog(
340
- title: const Text('Confirm Deletion'),
341
- content: const Text('Are you sure you want to delete this trade? This action cannot be undone.'),
342
- actions: <Widget>[
343
- TextButton(
344
- onPressed: () => Navigator.of(context).pop(false),
345
- child: const Text('Cancel'),
346
- ),
347
- TextButton(
348
- onPressed: () => Navigator.of(context).pop(true),
349
- child: const Text('Delete'),
350
- ),
351
- ],
352
- );
353
- }
354
- );
254
+ Future<void> _confirmAndDeleteTrade(BuildContext context,
255
+ CryptoAccountViewModel viewModel, int tradeId) async {
256
+ final bool? confirm =
257
+ await AppDialogs.showDeleteConfirmationDialog(context, 'this trade');
355
258
 
356
259
  if (confirm == true) {
357
- if (_token == null) {
358
- ScaffoldMessenger.of(context).showSnackBar(
359
- const SnackBar(content: Text('Authentication token not available.')),
360
- );
361
- return;
362
- }
363
- try {
364
- final success = await _transactionService.deleteTrade(tradeId, token: _token);
365
- if (success) {
366
- ScaffoldMessenger.of(context).showSnackBar(
367
- const SnackBar(content: Text('Trade deleted successfully.')),
368
- );
369
- _fetchData(); // Refresh data after deletion
370
- } else {
371
- ScaffoldMessenger.of(context).showSnackBar(
372
- const SnackBar(content: Text('Failed to delete trade.')),
373
- );
374
- }
375
- } catch (e) {
260
+ final success = await viewModel.deleteTrade(tradeId);
261
+ if (ScaffoldMessenger.of(context).mounted) {
376
262
  ScaffoldMessenger.of(context).showSnackBar(
377
- SnackBar(content: Text('Error deleting trade: $e')),
263
+ SnackBar(
264
+ content: Text(success
265
+ ? 'Trade deleted successfully.'
266
+ : 'Failed to delete trade.'),
267
+ ),
378
268
  );
379
269
  }
380
270
  }
381
271
  }
382
- }
272
+ }