fix tx listing
This commit is contained in:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user