Updates from idk when...
This commit is contained in:
@@ -9,6 +9,7 @@ import 'package:rluv/global/styles.dart';
|
||||
import 'package:rluv/global/utils.dart';
|
||||
|
||||
import '../../../global/store.dart';
|
||||
import '../../../global/widgets/ui_button.dart';
|
||||
import '../../../models/transaction_model.dart';
|
||||
import '../widgets/add_budget_category_dialog.dart';
|
||||
|
||||
@@ -26,11 +27,13 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
|
||||
final budgetListScrollController = ScrollController();
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final budget = ref.watch(budgetProvider);
|
||||
final budgetCategories = ref.watch(budgetCategoriesProvider);
|
||||
final transactions = ref.watch(transactionsProvider);
|
||||
final screen = BuildMedia(context).size;
|
||||
double netExpense = 0.0;
|
||||
double netIncome = 0.0;
|
||||
double expectedExpenses = 0.0;
|
||||
Map<int, double> budgetCategoryNetMap = {};
|
||||
netExpense = transactions
|
||||
.where((t) => t.type == TransactionType.expense)
|
||||
@@ -40,6 +43,7 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
|
||||
.fold(netIncome, (net, t) => net + t.amount);
|
||||
for (final bud in budgetCategories) {
|
||||
double net = 0.0;
|
||||
expectedExpenses += bud.amount;
|
||||
net = transactions
|
||||
.where((t) => t.budgetCategoryId == bud.id)
|
||||
.fold(net, (net, t) => net + t.amount);
|
||||
@@ -68,9 +72,15 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
|
||||
style:
|
||||
TextStyle(fontSize: 42, color: Styles.electricBlue)),
|
||||
const Spacer(flex: 2),
|
||||
BudgetNetBar(isPositive: true, net: netIncome),
|
||||
BudgetNetBar(
|
||||
isPositive: true,
|
||||
net: netIncome,
|
||||
expected: budget?.expectedIncome ?? 0.0),
|
||||
const Spacer(),
|
||||
BudgetNetBar(isPositive: false, net: netExpense),
|
||||
BudgetNetBar(
|
||||
isPositive: false,
|
||||
net: netExpense,
|
||||
expected: expectedExpenses),
|
||||
const Spacer(),
|
||||
],
|
||||
),
|
||||
@@ -113,7 +123,7 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
|
||||
child: Text(
|
||||
'No budget categories created yet, add some!'),
|
||||
),
|
||||
ElevatedButton(
|
||||
UiButton(
|
||||
onPressed:
|
||||
ref.watch(budgetProvider) ==
|
||||
null
|
||||
@@ -127,9 +137,9 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
|
||||
Styles
|
||||
.dialogColor,
|
||||
child:
|
||||
const AddBudgetCategoryDialog()),
|
||||
const BudgetCategoryDialog()),
|
||||
),
|
||||
child: const Text('Add Category'),
|
||||
text: 'Add Category',
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -181,7 +191,7 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
|
||||
Styles
|
||||
.dialogColor,
|
||||
child:
|
||||
const AddBudgetCategoryDialog()),
|
||||
const BudgetCategoryDialog()),
|
||||
),
|
||||
child: const Text(
|
||||
'Add Category'),
|
||||
@@ -259,7 +269,7 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
|
||||
return Dialog(
|
||||
backgroundColor: Styles.dialogColor,
|
||||
shape: Styles.dialogShape,
|
||||
child: const AddTransactionDialog());
|
||||
child: const TransactionDialog());
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:helpers/helpers/misc_build/build_media.dart';
|
||||
import 'package:rluv/features/budget/widgets/transaction_list_item.dart';
|
||||
import 'package:rluv/global/styles.dart';
|
||||
import 'package:rluv/models/transaction_model.dart';
|
||||
|
||||
import '../../../global/store.dart';
|
||||
import '../../../models/budget_category_model.dart';
|
||||
|
||||
class TransactionsListview extends ConsumerStatefulWidget {
|
||||
const TransactionsListview({super.key});
|
||||
@@ -14,18 +17,180 @@ class TransactionsListview extends ConsumerStatefulWidget {
|
||||
}
|
||||
|
||||
class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
|
||||
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
// TODO: implement initState
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref.read(selectedTransactionSortProvider.notifier).state =
|
||||
TransactionSort.all;
|
||||
ref.read(selectedSortDateProvider.notifier).state = SortDate.decending;
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final transactions = ref.watch(transactionsProvider);
|
||||
transactions.sort(
|
||||
(a, b) => b.date.compareTo(a.date),
|
||||
);
|
||||
final budgetCategories = ref.watch(budgetCategoriesProvider);
|
||||
if (ref.read(selectedCategory) == null && budgetCategories.isNotEmpty) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) =>
|
||||
ref.read(selectedCategory.notifier).state = budgetCategories.first);
|
||||
}
|
||||
final sortType = ref.watch(selectedTransactionSortProvider);
|
||||
final sortDate = ref.watch(selectedSortDateProvider);
|
||||
List<Transaction> transactions = [...ref.watch(transactionsProvider)];
|
||||
// Removes transactions by category
|
||||
switch (sortType) {
|
||||
case TransactionSort.income:
|
||||
transactions = transactions
|
||||
.where(
|
||||
(element) => element.type == TransactionType.income,
|
||||
)
|
||||
.toList();
|
||||
break;
|
||||
case TransactionSort.expense:
|
||||
transactions = transactions
|
||||
.where(
|
||||
(element) => element.type == TransactionType.expense,
|
||||
)
|
||||
.toList();
|
||||
break;
|
||||
case TransactionSort.category:
|
||||
if (ref.read(selectedCategory) != null) {
|
||||
transactions = transactions
|
||||
.where(
|
||||
(element) =>
|
||||
element.budgetCategoryId == ref.read(selectedCategory)!.id,
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
break;
|
||||
case TransactionSort.all:
|
||||
break;
|
||||
}
|
||||
// Sorts transactions by date
|
||||
switch (sortDate) {
|
||||
case SortDate.ascending:
|
||||
transactions.sort((a, b) => a.date.compareTo(b.date));
|
||||
break;
|
||||
case SortDate.decending:
|
||||
transactions.sort((a, b) => b.date.compareTo(a.date));
|
||||
break;
|
||||
}
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) =>
|
||||
ref.read(transactionHistoryListProvider.notifier).state = transactions);
|
||||
return Scaffold(
|
||||
endDrawer: Drawer(
|
||||
backgroundColor: Styles.purpleNurple,
|
||||
child: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(height: BuildMedia(context).height * 0.15),
|
||||
DropdownButton<TransactionSort>(
|
||||
dropdownColor: Styles.lavender,
|
||||
value: ref.watch(selectedTransactionSortProvider),
|
||||
items: TransactionSort.values
|
||||
.map(
|
||||
(e) => DropdownMenuItem(
|
||||
value: e,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
sortTypeToIcon(e),
|
||||
const SizedBox(width: 12),
|
||||
Text(e.name),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onChanged: (TransactionSort? value) {
|
||||
if (value != null) {
|
||||
ref.read(selectedTransactionSortProvider.notifier).state =
|
||||
value;
|
||||
}
|
||||
}),
|
||||
const SizedBox(height: 20),
|
||||
DropdownButton<SortDate>(
|
||||
dropdownColor: Styles.lavender,
|
||||
value: ref.watch(selectedSortDateProvider),
|
||||
items: SortDate.values
|
||||
.map(
|
||||
(e) => DropdownMenuItem(
|
||||
value: e,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
sortDateToIcon(e),
|
||||
const SizedBox(width: 12),
|
||||
Text(e.name),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onChanged: (SortDate? value) {
|
||||
if (value != null) {
|
||||
ref.read(selectedSortDateProvider.notifier).state = value;
|
||||
}
|
||||
}),
|
||||
const SizedBox(height: 20),
|
||||
if (ref.read(selectedTransactionSortProvider) ==
|
||||
TransactionSort.category)
|
||||
DropdownButton<BudgetCategory>(
|
||||
dropdownColor: Styles.lavender,
|
||||
value: ref.watch(selectedCategory),
|
||||
items: budgetCategories
|
||||
.map(
|
||||
(e) => DropdownMenuItem(
|
||||
value: e,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
height: 18,
|
||||
width: 18,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: Colors.black, width: 1.5),
|
||||
color: e.color,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Text(e.name),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onChanged: (BudgetCategory? value) {
|
||||
if (value != null) {
|
||||
ref.read(selectedCategory.notifier).state = value;
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
key: scaffoldKey,
|
||||
backgroundColor: Styles.purpleNurple,
|
||||
body: SafeArea(
|
||||
child: Stack(
|
||||
children: [
|
||||
if (transactions.isEmpty) ...[
|
||||
Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 8.0, top: 16.0),
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.chevron_left),
|
||||
onPressed: () => Navigator.pop(context)),
|
||||
),
|
||||
),
|
||||
const Center(
|
||||
child: Text('No transactions'),
|
||||
),
|
||||
@@ -33,12 +198,33 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
|
||||
if (transactions.isNotEmpty)
|
||||
Column(
|
||||
children: [
|
||||
const SizedBox(height: 28),
|
||||
const Text(
|
||||
'Transaction History',
|
||||
style: TextStyle(fontSize: 28),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 8.0, top: 16.0),
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.chevron_left),
|
||||
onPressed: () => Navigator.pop(context)),
|
||||
),
|
||||
const Spacer(),
|
||||
const Padding(
|
||||
padding:
|
||||
EdgeInsets.symmetric(vertical: 18.0, horizontal: 0.0),
|
||||
child: Text(
|
||||
'Transaction History',
|
||||
style: TextStyle(fontSize: 28),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 8.0, top: 16.0),
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.sort),
|
||||
onPressed: () {
|
||||
toggleDrawer();
|
||||
}),
|
||||
),
|
||||
]),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
@@ -52,12 +238,65 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
|
||||
),
|
||||
],
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.chevron_left),
|
||||
onPressed: () => Navigator.pop(context)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void toggleDrawer() {
|
||||
if (scaffoldKey.currentState != null &&
|
||||
scaffoldKey.currentState!.isDrawerOpen) {
|
||||
scaffoldKey.currentState!.openDrawer();
|
||||
} else if (scaffoldKey.currentState != null) {
|
||||
scaffoldKey.currentState!.openEndDrawer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum TransactionSort {
|
||||
all,
|
||||
income,
|
||||
expense,
|
||||
category,
|
||||
}
|
||||
|
||||
enum SortDate {
|
||||
decending,
|
||||
ascending,
|
||||
}
|
||||
|
||||
Icon sortTypeToIcon(TransactionSort s) {
|
||||
switch (s) {
|
||||
case TransactionSort.all:
|
||||
return const Icon(Icons.donut_large);
|
||||
case TransactionSort.income:
|
||||
return const Icon(Icons.attach_money);
|
||||
case TransactionSort.expense:
|
||||
return const Icon(Icons.shopping_bag);
|
||||
case TransactionSort.category:
|
||||
return const Icon(Icons.sort);
|
||||
}
|
||||
}
|
||||
|
||||
Icon sortDateToIcon(SortDate s) {
|
||||
switch (s) {
|
||||
case SortDate.ascending:
|
||||
return const Icon(Icons.arrow_circle_up);
|
||||
case SortDate.decending:
|
||||
return const Icon(Icons.arrow_circle_down);
|
||||
}
|
||||
}
|
||||
|
||||
final selectedTransactionSortProvider = StateProvider<TransactionSort>(
|
||||
(ref) => TransactionSort.all,
|
||||
);
|
||||
|
||||
final selectedSortDateProvider =
|
||||
StateProvider<SortDate>((ref) => SortDate.decending);
|
||||
|
||||
final transactionHistoryListProvider = StateProvider<List<Transaction>>(
|
||||
(ref) => [],
|
||||
);
|
||||
|
||||
final selectedCategory = StateProvider<BudgetCategory?>((ref) => null);
|
||||
|
||||
Reference in New Issue
Block a user