289 lines
10 KiB
Dart
289 lines
10 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.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});
|
|
|
|
@override
|
|
ConsumerState<TransactionsListview> createState() => _TransactionsListviewState();
|
|
}
|
|
|
|
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 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: MediaQuery.of(context).size.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'),
|
|
),
|
|
],
|
|
if (transactions.isNotEmpty)
|
|
Column(
|
|
children: [
|
|
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(),
|
|
itemCount: transactions.length,
|
|
itemBuilder: (BuildContext context, int index) {
|
|
return TransactionListItem(
|
|
index: index,
|
|
);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
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);
|