fix tx listing

This commit is contained in:
davmar
2026-09-09 11:40:05 +02:00
parent 2a741c7f2a
commit 903a2980de
8 changed files with 1638 additions and 281 deletions
+73
View File
@@ -3,6 +3,8 @@ library;
import 'package:flutter/material.dart';
import 'bank.dart';
/// A spend/income label shown on transactions.
class TxLabel {
const TxLabel({
@@ -380,6 +382,77 @@ String merchantKeyFromDescription(String description) {
String defaultSimilarPattern(String description) =>
merchantKeyFromDescription(description);
/// Income / expense / any — used by list filters and similar matching.
enum TxFlowFilter { all, income, expense }
/// Absolute-amount filter for transaction lists (exact and/or range).
class TxAmountRange {
const TxAmountRange({this.exact, this.min, this.max});
/// Exact absolute amount; when set, takes precedence over [min]/[max].
final double? exact;
/// Inclusive lower bound on absolute amount; null = no lower bound.
final double? min;
/// Inclusive upper bound on absolute amount; null = no upper bound.
final double? max;
bool get isActive => exact != null || min != null || max != null;
}
bool txMatchesAmountRange(BankTransaction tx, TxAmountRange range) {
if (!range.isActive) return true;
final abs = tx.amount.abs();
if (range.exact != null) {
// Match to the nearest cent.
return (abs - range.exact!).abs() < 0.005;
}
if (range.min != null && abs < range.min!) return false;
if (range.max != null && abs > range.max!) return false;
return true;
}
/// Criteria for finding similar transactions (apply-to-similar).
class SimilarMatchCriteria {
const SimilarMatchCriteria({
required this.pattern,
this.flow = TxFlowFilter.all,
});
/// Plain contains needle, or `/regex/`.
final String pattern;
/// Limit matches to income, expense, or either.
final TxFlowFilter flow;
SimilarMatchCriteria copyWith({
String? pattern,
TxFlowFilter? flow,
}) {
return SimilarMatchCriteria(
pattern: pattern ?? this.pattern,
flow: flow ?? this.flow,
);
}
}
bool txMatchesFlow(BankTransaction tx, TxFlowFilter flow) {
switch (flow) {
case TxFlowFilter.all:
return true;
case TxFlowFilter.income:
return tx.amount > 0;
case TxFlowFilter.expense:
return tx.amount < 0;
}
}
bool txMatchesSimilarCriteria(BankTransaction tx, SimilarMatchCriteria criteria) {
if (!txMatchesFlow(tx, criteria.flow)) return false;
return descriptionMatchesPattern(tx.description, criteria.pattern);
}
/// Match [description] against a simple contains needle or `/regex/`.
bool descriptionMatchesPattern(String description, String pattern) {
final raw = pattern.trim();