feat(proj): init
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:please_pay_me/core/state/async_value.dart';
|
||||
import 'package:please_pay_me/data/api/api_client.dart';
|
||||
import 'package:please_pay_me/data/models/budget.dart';
|
||||
import 'package:please_pay_me/data/repositories/repositories.dart';
|
||||
|
||||
/// Source of truth for budgets: the overview, the budget list and the expense
|
||||
/// form all read the selected envelope from here.
|
||||
class BudgetsController extends ChangeNotifier {
|
||||
BudgetsController({
|
||||
required BudgetRepository budgets,
|
||||
required ExpenseRepository expenses,
|
||||
}) : _budgets = budgets,
|
||||
_expenses = expenses;
|
||||
|
||||
final BudgetRepository _budgets;
|
||||
final ExpenseRepository _expenses;
|
||||
|
||||
AsyncValue<List<BudgetStatus>> _state = const AsyncValue.loading();
|
||||
bool _mutating = false;
|
||||
|
||||
AsyncValue<List<BudgetStatus>> get state => _state;
|
||||
|
||||
/// True while a write is in flight — used to disable buttons.
|
||||
bool get isMutating => _mutating;
|
||||
|
||||
List<BudgetStatus> get items => _state.valueOrNull ?? const [];
|
||||
|
||||
/// Currently selected envelope; `null` when the user has no budgets at all.
|
||||
BudgetStatus? get selected {
|
||||
final all = items;
|
||||
if (all.isEmpty) return null;
|
||||
for (final status in all) {
|
||||
if (status.selected) return status;
|
||||
}
|
||||
return all.first;
|
||||
}
|
||||
|
||||
bool get hasBudgets => items.isNotEmpty;
|
||||
|
||||
Future<void> load({bool silent = false}) async {
|
||||
if (!silent) {
|
||||
_state = const AsyncValue.loading();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
try {
|
||||
_state = AsyncValue.data(await _budgets.list());
|
||||
} on ApiException catch (error) {
|
||||
_state = AsyncValue.error(error.message);
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<String?> select(int budgetId) {
|
||||
return _mutate(() => _budgets.select(budgetId));
|
||||
}
|
||||
|
||||
Future<String?> setActive(int budgetId, {required bool isActive}) {
|
||||
return _mutate(() => _budgets.setActive(budgetId, isActive: isActive));
|
||||
}
|
||||
|
||||
Future<String?> create({
|
||||
required String name,
|
||||
required double totalAmount,
|
||||
required DateTime endDate,
|
||||
DateTime? startDate,
|
||||
}) {
|
||||
return _mutate(
|
||||
() => _budgets.create(
|
||||
name: name,
|
||||
totalAmount: totalAmount,
|
||||
endDate: endDate,
|
||||
startDate: startDate,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<String?> update({
|
||||
required int budgetId,
|
||||
String? name,
|
||||
double? totalAmount,
|
||||
DateTime? endDate,
|
||||
DateTime? startDate,
|
||||
bool resetExpenses = false,
|
||||
}) {
|
||||
return _mutate(
|
||||
() => _budgets.update(
|
||||
budgetId: budgetId,
|
||||
name: name,
|
||||
totalAmount: totalAmount,
|
||||
endDate: endDate,
|
||||
startDate: startDate,
|
||||
resetExpenses: resetExpenses,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<String?> delete(int budgetId) => _mutate(() => _budgets.delete(budgetId));
|
||||
|
||||
Future<String?> addExpense({
|
||||
required double amount,
|
||||
String? note,
|
||||
DateTime? spentAt,
|
||||
int? budgetId,
|
||||
}) {
|
||||
return _mutate(
|
||||
() => _expenses.create(
|
||||
amount: amount,
|
||||
note: note,
|
||||
spentAt: spentAt,
|
||||
budgetId: budgetId ?? selected?.budget.id,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<String?> undoLastExpense() {
|
||||
return _mutate(() => _expenses.undoLast(budgetId: selected?.budget.id));
|
||||
}
|
||||
|
||||
/// Runs a write, reloads the list and returns an error message or `null`.
|
||||
Future<String?> _mutate(Future<void> Function() action) async {
|
||||
_mutating = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
await action();
|
||||
await load(silent: true);
|
||||
return null;
|
||||
} on ApiException catch (error) {
|
||||
return error.message;
|
||||
} finally {
|
||||
_mutating = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user