mirror of
https://github.com/koloideal/Casha.git
synced 2026-06-10 10:25:28 +03:00
update
This commit is contained in:
@@ -53,9 +53,13 @@ final searchQueryProvider = StateProvider<String>((ref) => '');
|
|||||||
|
|
||||||
enum TransactionFilter { all, income, expense }
|
enum TransactionFilter { all, income, expense }
|
||||||
|
|
||||||
|
enum TimeFilter { allTime, lastMonth }
|
||||||
|
|
||||||
final transactionFilterProvider =
|
final transactionFilterProvider =
|
||||||
StateProvider<TransactionFilter>((ref) => TransactionFilter.all);
|
StateProvider<TransactionFilter>((ref) => TransactionFilter.all);
|
||||||
|
|
||||||
|
final timeFilterProvider = StateProvider<TimeFilter>((ref) => TimeFilter.lastMonth);
|
||||||
|
|
||||||
final totalBalanceProvider = Provider<double>((ref) {
|
final totalBalanceProvider = Provider<double>((ref) {
|
||||||
final txs = ref.watch(transactionsProvider);
|
final txs = ref.watch(transactionsProvider);
|
||||||
final exchangeService = ref.watch(exchangeRateServiceProvider);
|
final exchangeService = ref.watch(exchangeRateServiceProvider);
|
||||||
@@ -104,16 +108,30 @@ final currentMonthExpenseProvider = Provider<double>((ref) {
|
|||||||
final filteredTransactionsProvider = Provider<List<Transaction>>((ref) {
|
final filteredTransactionsProvider = Provider<List<Transaction>>((ref) {
|
||||||
final txs = ref.watch(transactionsProvider);
|
final txs = ref.watch(transactionsProvider);
|
||||||
final query = ref.watch(searchQueryProvider).toLowerCase();
|
final query = ref.watch(searchQueryProvider).toLowerCase();
|
||||||
final filter = ref.watch(transactionFilterProvider);
|
final typeFilter = ref.watch(transactionFilterProvider);
|
||||||
|
final timeFilter = ref.watch(timeFilterProvider);
|
||||||
|
|
||||||
var filtered = txs;
|
var filtered = txs;
|
||||||
|
|
||||||
if (filter == TransactionFilter.income) {
|
// Apply time filter first
|
||||||
|
if (timeFilter == TimeFilter.lastMonth) {
|
||||||
|
final now = DateTime.now();
|
||||||
|
final start = DateTime(now.year, now.month, 1);
|
||||||
|
final end = DateTime(now.year, now.month + 1, 1);
|
||||||
|
filtered = filtered.where((t) =>
|
||||||
|
t.date.isAfter(start.subtract(const Duration(seconds: 1))) &&
|
||||||
|
t.date.isBefore(end)
|
||||||
|
).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply type filter
|
||||||
|
if (typeFilter == TransactionFilter.income) {
|
||||||
filtered = filtered.where((t) => t.type == TransactionType.income).toList();
|
filtered = filtered.where((t) => t.type == TransactionType.income).toList();
|
||||||
} else if (filter == TransactionFilter.expense) {
|
} else if (typeFilter == TransactionFilter.expense) {
|
||||||
filtered = filtered.where((t) => t.type == TransactionType.expense).toList();
|
filtered = filtered.where((t) => t.type == TransactionType.expense).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply search query
|
||||||
if (query.isNotEmpty) {
|
if (query.isNotEmpty) {
|
||||||
filtered = filtered.where((t) {
|
filtered = filtered.where((t) {
|
||||||
final matchesCategory = t.category.toLowerCase().contains(query);
|
final matchesCategory = t.category.toLowerCase().contains(query);
|
||||||
|
|||||||
@@ -76,7 +76,6 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
|
|||||||
final monthExpense = ref.watch(currentMonthExpenseProvider);
|
final monthExpense = ref.watch(currentMonthExpenseProvider);
|
||||||
final budget = ref.watch(budgetProvider);
|
final budget = ref.watch(budgetProvider);
|
||||||
final recent = ref.watch(recentTransactionsProvider);
|
final recent = ref.watch(recentTransactionsProvider);
|
||||||
final filter = ref.watch(transactionFilterProvider);
|
|
||||||
final currencyInfo = ref.watch(currencyProvider);
|
final currencyInfo = ref.watch(currencyProvider);
|
||||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||||
|
|
||||||
@@ -152,7 +151,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
|
|||||||
ref: ref,
|
ref: ref,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
_FilterChips(selected: filter, ref: ref),
|
const FilterChips(),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Text(
|
Text(
|
||||||
'Transactions',
|
'Transactions',
|
||||||
@@ -254,36 +253,61 @@ class _SearchBar extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _FilterChips extends StatelessWidget {
|
class FilterChips extends ConsumerWidget {
|
||||||
final TransactionFilter selected;
|
const FilterChips({super.key});
|
||||||
final WidgetRef ref;
|
|
||||||
const _FilterChips({required this.selected, required this.ref});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final typeFilter = ref.watch(transactionFilterProvider);
|
||||||
|
final timeFilter = ref.watch(timeFilterProvider);
|
||||||
|
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
|
// TIME GROUP
|
||||||
|
_FilterChip(
|
||||||
|
label: 'All Time',
|
||||||
|
isSelected: timeFilter == TimeFilter.allTime,
|
||||||
|
onTap: () => ref.read(timeFilterProvider.notifier).state = TimeFilter.allTime,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
_FilterChip(
|
||||||
|
label: 'Month',
|
||||||
|
isSelected: timeFilter == TimeFilter.lastMonth,
|
||||||
|
onTap: () => ref.read(timeFilterProvider.notifier).state = TimeFilter.lastMonth,
|
||||||
|
),
|
||||||
|
|
||||||
|
// VISUAL DIVIDER
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: Container(
|
||||||
|
width: 1,
|
||||||
|
height: 20,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(
|
||||||
|
isDark ? 0.15 : 0.2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// TYPE GROUP
|
||||||
_FilterChip(
|
_FilterChip(
|
||||||
label: 'All',
|
label: 'All',
|
||||||
isSelected: selected == TransactionFilter.all,
|
isSelected: typeFilter == TransactionFilter.all,
|
||||||
onTap: () => ref.read(transactionFilterProvider.notifier).state =
|
onTap: () => ref.read(transactionFilterProvider.notifier).state = TransactionFilter.all,
|
||||||
TransactionFilter.all,
|
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 6),
|
||||||
_FilterChip(
|
_FilterChip(
|
||||||
label: 'Income',
|
label: 'Income',
|
||||||
isSelected: selected == TransactionFilter.income,
|
isSelected: typeFilter == TransactionFilter.income,
|
||||||
color: AppColors.income,
|
color: AppColors.income,
|
||||||
onTap: () => ref.read(transactionFilterProvider.notifier).state =
|
onTap: () => ref.read(transactionFilterProvider.notifier).state = TransactionFilter.income,
|
||||||
TransactionFilter.income,
|
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 6),
|
||||||
_FilterChip(
|
_FilterChip(
|
||||||
label: 'Expense',
|
label: 'Expense',
|
||||||
isSelected: selected == TransactionFilter.expense,
|
isSelected: typeFilter == TransactionFilter.expense,
|
||||||
color: AppColors.expense,
|
color: AppColors.expense,
|
||||||
onTap: () => ref.read(transactionFilterProvider.notifier).state =
|
onTap: () => ref.read(transactionFilterProvider.notifier).state = TransactionFilter.expense,
|
||||||
TransactionFilter.expense,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -295,22 +319,24 @@ class _FilterChip extends StatelessWidget {
|
|||||||
final bool isSelected;
|
final bool isSelected;
|
||||||
final Color? color;
|
final Color? color;
|
||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
|
|
||||||
const _FilterChip({
|
const _FilterChip({
|
||||||
required this.label,
|
required this.label,
|
||||||
required this.isSelected,
|
required this.isSelected,
|
||||||
this.color,
|
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
|
this.color,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final chipColor = color ?? AppColors.accent;
|
final chipColor = color ?? AppColors.accent;
|
||||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
child: AnimatedContainer(
|
child: AnimatedContainer(
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: const Duration(milliseconds: 200),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: isSelected
|
color: isSelected
|
||||||
? chipColor.withOpacity(0.2)
|
? chipColor.withOpacity(0.2)
|
||||||
@@ -318,13 +344,14 @@ class _FilterChip extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
border: isSelected
|
border: isSelected
|
||||||
? Border.all(color: chipColor, width: 1.5)
|
? Border.all(color: chipColor, width: 1.5)
|
||||||
: (isDark
|
: isDark
|
||||||
? null
|
? null
|
||||||
: Border.all(color: const Color(0xFFDDDDEE), width: 1)),
|
: Border.all(color: const Color(0xFFDDDDEE), width: 1),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
label,
|
label,
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
style: const TextStyle(fontSize: 12).merge(
|
||||||
|
Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||||
color: isSelected
|
color: isSelected
|
||||||
? chipColor
|
? chipColor
|
||||||
: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||||
@@ -332,6 +359,7 @@ class _FilterChip extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user