@marcos_feitoza/personal-finance-frontend-feature-investments 1.2.0 → 1.2.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.2.2](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/compare/v1.2.1...v1.2.2) (2026-01-30)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* Web responsivo (mobile/tablet/resize) ([f3aa7b2](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/commit/f3aa7b2edd456ca2fe1d32ea3a7f8798dc053fe9))
|
|
7
|
+
|
|
8
|
+
## [1.2.1](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/compare/v1.2.0...v1.2.1) (2026-01-29)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* update SnackBar ([a8f6587](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/commit/a8f6587eb10895eedd77eaa8bf9e15c5efa53463))
|
|
14
|
+
|
|
1
15
|
# [1.2.0](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/compare/v1.1.2...v1.2.0) (2025-12-06)
|
|
2
16
|
|
|
3
17
|
|
|
@@ -3,6 +3,8 @@ import 'package:intl/intl.dart';
|
|
|
3
3
|
import 'package:provider/provider.dart';
|
|
4
4
|
import 'package:personal_finance_frontend_core_services/providers/auth_provider.dart';
|
|
5
5
|
import 'package:personal_finance_frontend_core_ui/utils/app_dialogs.dart';
|
|
6
|
+
import 'package:personal_finance_frontend_core_ui/utils/app_responsive.dart';
|
|
7
|
+
import 'package:personal_finance_frontend_core_ui/utils/app_snackbars.dart';
|
|
6
8
|
import 'package:personal_finance_frontend_core_ui/widgets/crypto_trade_form.dart';
|
|
7
9
|
import '../viewmodels/crypto_account_viewmodel.dart';
|
|
8
10
|
|
|
@@ -118,8 +120,7 @@ class CryptoAccountScreen extends StatelessWidget {
|
|
|
118
120
|
);
|
|
119
121
|
}
|
|
120
122
|
|
|
121
|
-
return
|
|
122
|
-
scrollDirection: Axis.horizontal,
|
|
123
|
+
return ResponsiveHorizontalScroll(
|
|
123
124
|
child: DataTable(
|
|
124
125
|
columnSpacing: 24.0,
|
|
125
126
|
columns: const [
|
|
@@ -204,7 +205,8 @@ class CryptoAccountScreen extends StatelessWidget {
|
|
|
204
205
|
}
|
|
205
206
|
});
|
|
206
207
|
|
|
207
|
-
return
|
|
208
|
+
return ResponsiveHorizontalScroll(
|
|
209
|
+
child: DataTable(
|
|
208
210
|
columns: const [
|
|
209
211
|
DataColumn(label: Text('Date')),
|
|
210
212
|
DataColumn(label: Text('Symbol')),
|
|
@@ -238,6 +240,7 @@ class CryptoAccountScreen extends StatelessWidget {
|
|
|
238
240
|
),
|
|
239
241
|
]);
|
|
240
242
|
}).toList(),
|
|
243
|
+
),
|
|
241
244
|
);
|
|
242
245
|
}
|
|
243
246
|
|
|
@@ -249,13 +252,11 @@ class CryptoAccountScreen extends StatelessWidget {
|
|
|
249
252
|
if (confirm == true) {
|
|
250
253
|
final success = await viewModel.deleteTrade(tradeId);
|
|
251
254
|
if (ScaffoldMessenger.of(context).mounted) {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
),
|
|
258
|
-
);
|
|
255
|
+
if (success) {
|
|
256
|
+
showSuccessSnackBar(context, 'Trade deleted successfully.');
|
|
257
|
+
} else {
|
|
258
|
+
showErrorSnackBar(context, 'Failed to delete trade.');
|
|
259
|
+
}
|
|
259
260
|
}
|
|
260
261
|
}
|
|
261
262
|
}
|
|
@@ -3,6 +3,8 @@ import 'package:intl/intl.dart';
|
|
|
3
3
|
import 'package:provider/provider.dart';
|
|
4
4
|
import 'package:personal_finance_frontend_core_services/providers/auth_provider.dart';
|
|
5
5
|
import 'package:personal_finance_frontend_core_ui/utils/app_dialogs.dart';
|
|
6
|
+
import 'package:personal_finance_frontend_core_ui/utils/app_snackbars.dart';
|
|
7
|
+
import 'package:personal_finance_frontend_core_ui/utils/app_responsive.dart';
|
|
6
8
|
import 'package:personal_finance_frontend_core_ui/widgets/trade_form.dart';
|
|
7
9
|
import 'package:personal_finance_frontend_core_ui/widgets/dividend_log_form.dart';
|
|
8
10
|
import 'package:personal_finance_frontend_core_ui/widgets/app_widgets.dart';
|
|
@@ -182,8 +184,7 @@ class InvestmentAccountScreen extends StatelessWidget {
|
|
|
182
184
|
);
|
|
183
185
|
}
|
|
184
186
|
|
|
185
|
-
return
|
|
186
|
-
scrollDirection: Axis.horizontal,
|
|
187
|
+
return ResponsiveHorizontalScroll(
|
|
187
188
|
child: DataTable(
|
|
188
189
|
columnSpacing: 24.0,
|
|
189
190
|
columns: [
|
|
@@ -263,48 +264,57 @@ class InvestmentAccountScreen extends StatelessWidget {
|
|
|
263
264
|
);
|
|
264
265
|
}
|
|
265
266
|
|
|
266
|
-
return
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
267
|
+
return ResponsiveHorizontalScroll(
|
|
268
|
+
child: DataTable(
|
|
269
|
+
columns: const [
|
|
270
|
+
DataColumn(label: Text('Date')),
|
|
271
|
+
DataColumn(label: Text('Trade Age')),
|
|
272
|
+
DataColumn(label: Text('Symbol')),
|
|
273
|
+
DataColumn(label: Text('Type')),
|
|
274
|
+
DataColumn(label: Text('Shares')),
|
|
275
|
+
DataColumn(label: Text('Price')),
|
|
276
|
+
DataColumn(label: Text('Total')),
|
|
277
|
+
DataColumn(label: Text('Actions')),
|
|
278
|
+
],
|
|
279
|
+
rows: filteredHistory.map((item) {
|
|
280
|
+
final isTrade = item['history_type'] == 'trade';
|
|
281
|
+
// final isDividend = item['history_type'] == 'dividend'; // Reserved for future use.
|
|
280
282
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
283
|
+
final tradeDate = DateTime.parse(item['date'] as String);
|
|
284
|
+
final tradeAge = DateTime.now().difference(tradeDate);
|
|
285
|
+
final symbol = item['symbol'] as String? ?? 'N/A';
|
|
286
|
+
final type = item['type'] as String? ?? 'N/A';
|
|
287
|
+
final int id = item['id'] as int;
|
|
286
288
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
289
|
+
final double shares = isTrade
|
|
290
|
+
? (double.tryParse(item['shares']?.toString() ?? '0.0') ?? 0.0)
|
|
291
|
+
: 0.0;
|
|
292
|
+
final double price = isTrade
|
|
293
|
+
? (double.tryParse(item['price']?.toString() ?? '0.0') ?? 0.0)
|
|
294
|
+
: 0.0;
|
|
295
|
+
final double total = isTrade
|
|
296
|
+
? (shares * price)
|
|
297
|
+
: (double.tryParse(item['total']?.toString() ?? '0.0') ?? 0.0);
|
|
290
298
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
299
|
+
return DataRow(cells: [
|
|
300
|
+
DataCell(Text(DateFormat('yyyy-MM-dd').format(tradeDate))),
|
|
301
|
+
DataCell(Text(_formatDuration(tradeAge))),
|
|
302
|
+
DataCell(Text(symbol)),
|
|
303
|
+
DataCell(Text(type)),
|
|
304
|
+
DataCell(isTrade ? Text(shares.toStringAsFixed(4)) : const Text('-')),
|
|
305
|
+
DataCell(isTrade ? Text(_formatCurrency(price)) : const Text('-')),
|
|
306
|
+
DataCell(Text(_formatCurrency(total))),
|
|
307
|
+
DataCell(
|
|
308
|
+
IconButton(
|
|
309
|
+
icon: const Icon(Icons.delete, color: Colors.red),
|
|
310
|
+
onPressed: () =>
|
|
311
|
+
_confirmAndDeleteItem(context, viewModel, id, isTrade),
|
|
312
|
+
tooltip: 'Delete Item',
|
|
313
|
+
),
|
|
304
314
|
),
|
|
305
|
-
)
|
|
306
|
-
|
|
307
|
-
|
|
315
|
+
]);
|
|
316
|
+
}).toList(),
|
|
317
|
+
),
|
|
308
318
|
);
|
|
309
319
|
}
|
|
310
320
|
|
|
@@ -320,13 +330,11 @@ class InvestmentAccountScreen extends StatelessWidget {
|
|
|
320
330
|
: await viewModel.deleteDividend(itemId);
|
|
321
331
|
|
|
322
332
|
if (ScaffoldMessenger.of(context).mounted) {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
),
|
|
329
|
-
);
|
|
333
|
+
if (success) {
|
|
334
|
+
showSuccessSnackBar(context, 'The $itemType was deleted successfully.');
|
|
335
|
+
} else {
|
|
336
|
+
showErrorSnackBar(context, 'Failed to delete the $itemType.');
|
|
337
|
+
}
|
|
330
338
|
}
|
|
331
339
|
}
|
|
332
340
|
}
|
|
@@ -3,6 +3,8 @@ import 'package:intl/intl.dart';
|
|
|
3
3
|
import 'package:provider/provider.dart';
|
|
4
4
|
import 'package:personal_finance_frontend_core_services/providers/auth_provider.dart';
|
|
5
5
|
import 'package:personal_finance_frontend_core_ui/utils/app_dialogs.dart';
|
|
6
|
+
import 'package:personal_finance_frontend_core_ui/utils/app_responsive.dart';
|
|
7
|
+
import 'package:personal_finance_frontend_core_ui/utils/app_snackbars.dart';
|
|
6
8
|
import 'package:personal_finance_frontend_core_ui/widgets/rrsp_contribution_form.dart';
|
|
7
9
|
import '../viewmodels/rrsp_sun_life_viewmodel.dart';
|
|
8
10
|
|
|
@@ -99,8 +101,9 @@ class RrspSunLifeScreen extends StatelessWidget {
|
|
|
99
101
|
final double unrealizedPL = double.tryParse(summary['unrealized_pl']?.toString() ?? '0.0') ?? 0.0;
|
|
100
102
|
final plColor = (unrealizedPL >= 0) ? Colors.green : Colors.red;
|
|
101
103
|
|
|
102
|
-
return
|
|
103
|
-
|
|
104
|
+
return ResponsiveHorizontalScroll(
|
|
105
|
+
child: DataTable(
|
|
106
|
+
columns: const [
|
|
104
107
|
DataColumn(label: Text('User Contr.')),
|
|
105
108
|
DataColumn(label: Text('Company Contr.')),
|
|
106
109
|
DataColumn(label: Text('Total Contributed')),
|
|
@@ -109,7 +112,7 @@ class RrspSunLifeScreen extends StatelessWidget {
|
|
|
109
112
|
DataColumn(label: Text('Market Value')),
|
|
110
113
|
DataColumn(label: Text('Portfolio %')),
|
|
111
114
|
],
|
|
112
|
-
|
|
115
|
+
rows: [
|
|
113
116
|
DataRow(
|
|
114
117
|
cells: [
|
|
115
118
|
DataCell(
|
|
@@ -132,7 +135,8 @@ class RrspSunLifeScreen extends StatelessWidget {
|
|
|
132
135
|
),
|
|
133
136
|
],
|
|
134
137
|
),
|
|
135
|
-
|
|
138
|
+
],
|
|
139
|
+
),
|
|
136
140
|
);
|
|
137
141
|
}
|
|
138
142
|
|
|
@@ -147,8 +151,9 @@ class RrspSunLifeScreen extends StatelessWidget {
|
|
|
147
151
|
);
|
|
148
152
|
}
|
|
149
153
|
|
|
150
|
-
return
|
|
151
|
-
|
|
154
|
+
return ResponsiveHorizontalScroll(
|
|
155
|
+
child: DataTable(
|
|
156
|
+
columns: const [
|
|
152
157
|
DataColumn(label: Text('Date')),
|
|
153
158
|
DataColumn(label: Text('User Contr.')),
|
|
154
159
|
DataColumn(label: Text('Company Contr.')),
|
|
@@ -159,7 +164,7 @@ class RrspSunLifeScreen extends StatelessWidget {
|
|
|
159
164
|
DataColumn(label: Text('Portfolio %')),
|
|
160
165
|
DataColumn(label: Text('Actions')),
|
|
161
166
|
],
|
|
162
|
-
|
|
167
|
+
rows: viewModel.contributions.map((c) {
|
|
163
168
|
final contributionId = c['id'] as int;
|
|
164
169
|
final rrspAmount = double.tryParse(c['rrsp_amount']?.toString() ?? '0.0') ?? 0.0;
|
|
165
170
|
final dpspAmount = double.tryParse(c['dpsp_amount']?.toString() ?? '0.0') ?? 0.0;
|
|
@@ -206,7 +211,8 @@ class RrspSunLifeScreen extends StatelessWidget {
|
|
|
206
211
|
),
|
|
207
212
|
],
|
|
208
213
|
);
|
|
209
|
-
|
|
214
|
+
}).toList(),
|
|
215
|
+
),
|
|
210
216
|
);
|
|
211
217
|
}
|
|
212
218
|
|
|
@@ -220,14 +226,12 @@ class RrspSunLifeScreen extends StatelessWidget {
|
|
|
220
226
|
if (confirm == true) {
|
|
221
227
|
final success = await viewModel.deleteContribution(contributionId);
|
|
222
228
|
if (ScaffoldMessenger.of(context).mounted) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
),
|
|
229
|
-
);
|
|
229
|
+
if (success) {
|
|
230
|
+
showSuccessSnackBar(context, 'Contribution deleted successfully.');
|
|
231
|
+
} else {
|
|
232
|
+
showErrorSnackBar(context, 'Failed to delete contribution.');
|
|
233
|
+
}
|
|
230
234
|
}
|
|
231
235
|
}
|
|
232
236
|
}
|
|
233
|
-
}
|
|
237
|
+
}
|