ok lets ship for now

This commit is contained in:
davmar
2026-09-10 20:44:54 +02:00
parent 4dde907f52
commit 3187499385
3 changed files with 186 additions and 9 deletions
+84
View File
@@ -7,7 +7,9 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:pocketbase/pocketbase.dart';
import '../models/app_cloud_prefs.dart';
import '../models/bank.dart';
import '../models/home_built_in_sections.dart';
import '../models/home_filter_widget.dart';
import '../models/overview_favourite.dart';
import '../models/transaction_meta.dart';
@@ -558,6 +560,43 @@ class PbSyncService {
await _syncHomeFilterWidgets(userId, filter, widgets);
}
/// Pull per-user app prefs (Home sections + Look ahead). Soft-fail if missing.
Future<AppCloudPrefs?> pullAppPrefs({
void Function(String message)? onStatus,
}) async {
final userId = _userId;
final filter = 'user="$userId"';
onStatus?.call('Pulling app prefs…');
final records = await _fullList('app_prefs', filter);
if (records.isEmpty) {
debugPrint('PbSyncService pull: app_prefs=0');
return null;
}
final r = records.first;
final prefs = AppCloudPrefs(
homeBuiltInSections: HomeBuiltInSections(
showTransactions: r.getBoolValue('home_show_transactions', true),
showCategorized: r.getBoolValue('home_show_categorized', true),
showRecent: r.getBoolValue('home_show_recent', true),
),
lookAheadMaxYears:
r.getIntValue('look_ahead_max_years', 5).clamp(1, 30),
);
debugPrint('PbSyncService pull: app_prefs=1');
return prefs;
}
/// Upsert the single app_prefs row for this user.
Future<void> pushAppPrefs(
AppCloudPrefs prefs, {
void Function(String message)? onStatus,
}) async {
final userId = _userId;
final filter = 'user="$userId"';
onStatus?.call('Syncing app prefs…');
await _syncAppPrefs(userId, filter, prefs);
}
/// Upserts local bank txs to PocketBase. Does **not** delete remote rows
/// (partial local caches must not wipe another device).
Future<String> pushTransactions(
@@ -832,6 +871,10 @@ class PbSyncService {
filter =
'user="$userId" && client_id="${key.replaceAll('"', '\\"')}"';
}
case 'app_prefs':
if (userId != null) {
filter = 'user="$userId"';
}
case 'transactions':
final key = body['tx_id'];
if (userId != null && key is String) {
@@ -1249,6 +1292,36 @@ class PbSyncService {
await _runWriteOps('home_filter_widgets', ops);
}
Future<void> _syncAppPrefs(
String userId,
String filter,
AppCloudPrefs prefs,
) async {
final existing = await _fullList('app_prefs', filter);
final body = <String, dynamic>{
'user': userId,
'home_show_transactions': prefs.homeBuiltInSections.showTransactions,
'home_show_categorized': prefs.homeBuiltInSections.showCategorized,
'home_show_recent': prefs.homeBuiltInSections.showRecent,
'look_ahead_max_years': prefs.lookAheadMaxYears.clamp(1, 30),
};
final ops = <_BatchOp>[];
if (existing.isEmpty) {
ops.add(_BatchOp.create(body));
} else {
final remote = existing.first;
if (!_appPrefsUnchanged(remote, prefs)) {
ops.add(_BatchOp.update(remote.id, body));
}
// Enforce singleton: drop extras if any.
for (var i = 1; i < existing.length; i++) {
ops.add(_BatchOp.delete(existing[i].id));
}
}
debugPrint('PbSyncService app_prefs: remote=${existing.length} ops=${ops.length}');
await _runWriteOps('app_prefs', ops);
}
bool _labelUnchanged(RecordModel remote, Map<String, dynamic> body) {
return remote.getStringValue('name') == body['name'] &&
remote.getIntValue('color') == body['color'] &&
@@ -1339,6 +1412,17 @@ class PbSyncService {
remote.getBoolValue('show_amount_out', true) == w.showAmountOut &&
remote.getBoolValue('show_count', true) == w.showCount;
}
bool _appPrefsUnchanged(RecordModel remote, AppCloudPrefs prefs) {
final s = prefs.homeBuiltInSections;
return remote.getBoolValue('home_show_transactions', true) ==
s.showTransactions &&
remote.getBoolValue('home_show_categorized', true) ==
s.showCategorized &&
remote.getBoolValue('home_show_recent', true) == s.showRecent &&
remote.getIntValue('look_ahead_max_years', 5) ==
prefs.lookAheadMaxYears.clamp(1, 30);
}
}
RecurringTemplateSource _parseTemplateSource(String raw) {