mirror of
https://github.com/koloideal/Casha.git
synced 2026-06-10 18:35:28 +03:00
stableee
This commit is contained in:
@@ -98,6 +98,8 @@ class AppStrings {
|
|||||||
String get noCategoriesYet => _ru ? 'Нет категорий' : 'No categories yet';
|
String get noCategoriesYet => _ru ? 'Нет категорий' : 'No categories yet';
|
||||||
String get noExpenseData => _ru ? 'Нет данных о расходах' : 'No expense data';
|
String get noExpenseData => _ru ? 'Нет данных о расходах' : 'No expense data';
|
||||||
String get addExpensesToSeeBreakdown => _ru ? 'Добавьте расходы, чтобы увидеть разбивку' : 'Add some expenses to see the breakdown';
|
String get addExpensesToSeeBreakdown => _ru ? 'Добавьте расходы, чтобы увидеть разбивку' : 'Add some expenses to see the breakdown';
|
||||||
|
String get noIncomeData => _ru ? 'Нет данных о доходах' : 'No income data';
|
||||||
|
String get addIncomeToSeeBreakdown => _ru ? 'Добавьте доходы, чтобы увидеть разбивку' : 'Add some income to see the breakdown';
|
||||||
String get total => _ru ? 'Всего' : 'Total';
|
String get total => _ru ? 'Всего' : 'Total';
|
||||||
String get lastSixMonths => _ru ? 'Последние 6 месяцев' : 'Last 6 Months';
|
String get lastSixMonths => _ru ? 'Последние 6 месяцев' : 'Last 6 Months';
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,17 @@ final categoryExpenseProvider = Provider<Map<String, double>>((ref) {
|
|||||||
return map;
|
return map;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final categoryIncomeProvider = Provider<Map<String, double>>((ref) {
|
||||||
|
final txs = ref.watch(transactionsProvider)
|
||||||
|
.where((t) => t.type == TransactionType.income);
|
||||||
|
|
||||||
|
final map = <String, double>{};
|
||||||
|
for (final t in txs) {
|
||||||
|
map[t.category] = (map[t.category] ?? 0) + t.amount;
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
|
||||||
final monthlyBreakdownProvider = Provider<List<MonthlyData>>((ref) {
|
final monthlyBreakdownProvider = Provider<List<MonthlyData>>((ref) {
|
||||||
final txs = ref.watch(transactionsProvider)
|
final txs = ref.watch(transactionsProvider)
|
||||||
.where((t) => t.type == TransactionType.expense);
|
.where((t) => t.type == TransactionType.expense);
|
||||||
|
|||||||
@@ -21,11 +21,14 @@ class CategoriesScreen extends ConsumerStatefulWidget {
|
|||||||
class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
|
class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
|
||||||
int _touchedIndex = -1;
|
int _touchedIndex = -1;
|
||||||
ChartType _chartType = ChartType.pie;
|
ChartType _chartType = ChartType.pie;
|
||||||
|
bool _showIncome = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final s = ref.watch(stringsProvider);
|
final s = ref.watch(stringsProvider);
|
||||||
final data = ref.watch(categoryExpenseProvider);
|
final data = _showIncome
|
||||||
|
? ref.watch(categoryIncomeProvider)
|
||||||
|
: ref.watch(categoryExpenseProvider);
|
||||||
final monthlyData = ref.watch(monthlyBreakdownProvider);
|
final monthlyData = ref.watch(monthlyBreakdownProvider);
|
||||||
final total = data.values.fold(0.0, (a, b) => a + b);
|
final total = data.values.fold(0.0, (a, b) => a + b);
|
||||||
final currencyInfo = ref.watch(currencyProvider);
|
final currencyInfo = ref.watch(currencyProvider);
|
||||||
@@ -57,8 +60,82 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () => setState(() {
|
||||||
|
_showIncome = false;
|
||||||
|
_touchedIndex = -1;
|
||||||
|
}),
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: !_showIncome
|
||||||
|
? AppColors.accent
|
||||||
|
: Colors.transparent,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
border: Border.all(
|
||||||
|
color: !_showIncome
|
||||||
|
? AppColors.accent
|
||||||
|
: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
|
||||||
|
width: 1.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
s.expenses,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: !_showIncome
|
||||||
|
? Colors.white
|
||||||
|
: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () => setState(() {
|
||||||
|
_showIncome = true;
|
||||||
|
_touchedIndex = -1;
|
||||||
|
}),
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: _showIncome
|
||||||
|
? AppColors.accent
|
||||||
|
: Colors.transparent,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
border: Border.all(
|
||||||
|
color: _showIncome
|
||||||
|
? AppColors.accent
|
||||||
|
: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
|
||||||
|
width: 1.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
s.income,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: _showIncome
|
||||||
|
? Colors.white
|
||||||
|
: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
if (data.isEmpty)
|
if (data.isEmpty)
|
||||||
const Expanded(child: _EmptyState())
|
Expanded(child: _EmptyState(isIncome: _showIncome))
|
||||||
else
|
else
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView(
|
child: ListView(
|
||||||
@@ -94,6 +171,7 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
|
|||||||
amount: amount,
|
amount: amount,
|
||||||
total: total,
|
total: total,
|
||||||
currency: currencyInfo.symbol,
|
currency: currencyInfo.symbol,
|
||||||
|
isIncome: _showIncome,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
@@ -390,12 +468,14 @@ class _CategoryRow extends ConsumerWidget {
|
|||||||
final double amount;
|
final double amount;
|
||||||
final double total;
|
final double total;
|
||||||
final String currency;
|
final String currency;
|
||||||
|
final bool isIncome;
|
||||||
const _CategoryRow({
|
const _CategoryRow({
|
||||||
required this.rank,
|
required this.rank,
|
||||||
required this.category,
|
required this.category,
|
||||||
required this.amount,
|
required this.amount,
|
||||||
required this.total,
|
required this.total,
|
||||||
required this.currency,
|
required this.currency,
|
||||||
|
required this.isIncome,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -457,7 +537,7 @@ class _CategoryRow extends ConsumerWidget {
|
|||||||
Text(
|
Text(
|
||||||
formatAmount(currency, amount, fmt),
|
formatAmount(currency, amount, fmt),
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
color: AppColors.expense,
|
color: isIncome ? AppColors.income : AppColors.expense,
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.w700,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -488,7 +568,8 @@ class _CategoryRow extends ConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _EmptyState extends ConsumerWidget {
|
class _EmptyState extends ConsumerWidget {
|
||||||
const _EmptyState();
|
final bool isIncome;
|
||||||
|
const _EmptyState({required this.isIncome});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
@@ -511,7 +592,7 @@ class _EmptyState extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
s.noExpenseData,
|
isIncome ? s.noIncomeData : s.noExpenseData,
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||||
color: Theme.of(context).colorScheme.onSurface,
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@@ -519,7 +600,7 @@ class _EmptyState extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
Text(
|
Text(
|
||||||
s.addExpensesToSeeBreakdown,
|
isIncome ? s.addIncomeToSeeBreakdown : s.addExpensesToSeeBreakdown,
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user