admin user able to create test txs

This commit is contained in:
davmar
2026-09-10 23:18:24 +02:00
parent c4f0ca785e
commit f8e293f823
13 changed files with 507 additions and 111 deletions
@@ -1,4 +1,4 @@
/// Admin-only dialog to create a local test bank transaction.
/// Admin-only dialog to create or edit a local test bank transaction.
library;
import 'package:flutter/material.dart';
@@ -11,16 +11,22 @@ import '../providers/bank_provider.dart';
import '../utils/helpers.dart';
Future<BankTransaction?> showAdminCreateTransactionDialog(
BuildContext context,
) {
BuildContext context, {
BankTransaction? existing,
}) {
return showDialog<BankTransaction>(
context: context,
builder: (context) => const _AdminCreateTransactionDialog(),
builder: (context) => _AdminCreateTransactionDialog(existing: existing),
);
}
String _stripManualStamp(String description) =>
description.replaceFirst(RegExp(r' ·#\d+$'), '');
class _AdminCreateTransactionDialog extends StatefulWidget {
const _AdminCreateTransactionDialog();
const _AdminCreateTransactionDialog({this.existing});
final BankTransaction? existing;
@override
State<_AdminCreateTransactionDialog> createState() =>
@@ -33,19 +39,40 @@ class _AdminCreateTransactionDialogState
late final TextEditingController _description;
late final TextEditingController _amount;
late final TextEditingController _currency;
var _flow = TxFlowFilter.expense;
var _pending = false;
late TxFlowFilter _flow;
late bool _pending;
var _saving = false;
String? _error;
bool get _editing => widget.existing != null;
@override
void initState() {
super.initState();
final now = DateTime.now();
_date = DateTime(now.year, now.month, now.day);
_description = TextEditingController(text: 'Test merchant');
_amount = TextEditingController(text: '12.50');
_currency = TextEditingController(text: 'EUR');
final existing = widget.existing;
if (existing != null) {
final parsed = DateTime.tryParse(existing.date) ?? DateTime.now();
_date = DateTime(parsed.year, parsed.month, parsed.day);
_description = TextEditingController(
text: _stripManualStamp(existing.description),
);
_amount = TextEditingController(
text: existing.amount.abs().toStringAsFixed(2),
);
_currency = TextEditingController(text: existing.currency);
_flow = existing.amount >= 0
? TxFlowFilter.income
: TxFlowFilter.expense;
_pending = existing.pending;
} else {
final now = DateTime.now();
_date = DateTime(now.year, now.month, now.day);
_description = TextEditingController(text: 'Test merchant');
_amount = TextEditingController(text: '12.50');
_currency = TextEditingController(text: 'EUR');
_flow = TxFlowFilter.expense;
_pending = false;
}
}
@override
@@ -81,13 +108,26 @@ class _AdminCreateTransactionDialogState
});
try {
final bank = context.read<BankController>();
final tx = await bank.addManualTransaction(
date: _date,
description: _description.text,
amount: signed,
currency: _currency.text,
pending: _pending,
);
final existing = widget.existing;
final BankTransaction tx;
if (existing != null) {
tx = await bank.updateManualTransaction(
previous: existing,
date: _date,
description: _description.text,
amount: signed,
currency: _currency.text,
pending: _pending,
);
} else {
tx = await bank.addManualTransaction(
date: _date,
description: _description.text,
amount: signed,
currency: _currency.text,
pending: _pending,
);
}
if (!mounted) return;
Navigator.pop(context, tx);
} catch (error) {
@@ -103,14 +143,16 @@ class _AdminCreateTransactionDialogState
Widget build(BuildContext context) {
final theme = Theme.of(context);
return AlertDialog(
title: const Text('Create test transaction'),
title: Text(_editing ? 'Edit test transaction' : 'Create test transaction'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Saved on this device and included in the next PocketBase sync.',
_editing
? 'Updates this device and removes the old row on the next PocketBase sync.'
: 'Saved on this device and included in the next PocketBase sync.',
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
),
@@ -218,7 +260,7 @@ class _AdminCreateTransactionDialogState
height: 18,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Text('Create'),
: Text(_editing ? 'Save' : 'Create'),
),
],
);
+5 -2
View File
@@ -371,8 +371,11 @@ class _BudgetBody extends StatelessWidget {
widget: widgetConfig,
);
final progress = budget.progress.clamp(0.0, 1.0);
final over = budget.overBudget;
final fillColor = over ? colors.error : colors.primary;
final fillColor = budget.overBudget
? AppTheme.expense
: AppTheme.budgetProgressFill(
budget.target <= 0 ? 0 : progress,
);
// Grayish unfilled track (not green-tinted).
final trackColor = Color.alphaBlend(
colors.onSurface.withValues(alpha: 0.14),