sync transactions with pocketbase

This commit is contained in:
davmar
2026-09-09 22:24:16 +02:00
parent c6d1fdb19e
commit 96627a830e
9 changed files with 1104 additions and 324 deletions
+60 -1
View File
@@ -25,6 +25,9 @@ class TxMetaController extends ChangeNotifier {
final StorageService _storage;
/// Invoked after a successful local persist (used by [SyncController]).
VoidCallback? onPersisted;
Map<String, TxMeta> _byId = {};
Map<String, List<String>> _labelsByMerchant = {};
Map<String, String> _notesByMerchant = {};
@@ -32,6 +35,61 @@ class TxMetaController extends ChangeNotifier {
List<TxLabel> _customLabels = [];
Map<String, String> _labelParents = {};
/// Snapshot of the in-memory annotation store.
TxMetaStoreData exportStore() {
return TxMetaStoreData(
byId: Map.of(_byId),
labelsByMerchant: {
for (final e in _labelsByMerchant.entries)
e.key: List<String>.of(e.value),
},
notesByMerchant: Map.of(_notesByMerchant),
exactTemplates: Map.of(_exactTemplates),
customLabels: List.of(_customLabels),
labelParents: Map.of(_labelParents),
);
}
/// Rows in the local annotation map (may include empty stubs).
int get storedAnnotationCount => _byId.length;
/// Annotations that are pushed to PocketBase (label/notes/flags).
int get syncableAnnotationCount {
var n = 0;
for (final meta in _byId.values) {
if (meta.hasLabel ||
meta.hasNotes ||
meta.recurring ||
meta.internalTransfer) {
n++;
}
}
return n;
}
int get merchantRuleCount => {
..._labelsByMerchant.keys,
..._notesByMerchant.keys,
}.length;
int get customLabelCount => _customLabels.length;
/// Replace local store (e.g. after merge) and persist without re-triggering push.
Future<void> replaceStore(TxMetaStoreData store) async {
_byId = Map.of(store.byId);
_labelsByMerchant = {
for (final e in store.labelsByMerchant.entries)
e.key: List<String>.of(e.value),
};
_notesByMerchant = Map.of(store.notesByMerchant);
_exactTemplates = Map.of(store.exactTemplates);
_customLabels = List.of(store.customLabels);
_labelParents = Map.of(store.labelParents);
_invalidateLabelCache();
notifyListeners();
await _writeStore(notifySync: false);
}
/// Built-in + custom labels available for picking.
List<TxLabel> get allLabels => [...kBuiltinLabels, ..._customLabels];
@@ -759,7 +817,7 @@ class TxMetaController extends ChangeNotifier {
unawaited(_writeStore());
}
Future<void> _writeStore() async {
Future<void> _writeStore({bool notifySync = true}) async {
// Let the busy indicator / label checkbox paint before JSON work.
await Future<void>.delayed(Duration.zero);
final snapshot = TxMetaStoreData(
@@ -778,6 +836,7 @@ class TxMetaController extends ChangeNotifier {
);
try {
await _storage.saveTxMetaStore(snapshot);
if (notifySync) onPersisted?.call();
} catch (error, stackTrace) {
debugPrint('TxMetaController persist failed: $error\n$stackTrace');
}