Offline Support
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import 'package:flutter/foundation.dart' show debugPrint;
|
||||
|
||||
import 'repository.dart';
|
||||
|
||||
/// Returns the locally cached list of [T] from Brick SQLite, or `[]` if Brick
|
||||
/// isn't configured or the read fails. Never throws.
|
||||
///
|
||||
/// Use this as `onOfflineData` for [StreamRecoveryWrapper] so that screens
|
||||
/// render data from the local cache when the device is offline:
|
||||
///
|
||||
/// ```dart
|
||||
/// onOfflineData: () => cachedListFromBrick<Task>(),
|
||||
/// ```
|
||||
Future<List<T>> cachedListFromBrick<T extends OfflineFirstWithSupabaseModel>() async {
|
||||
if (!AppRepository.isConfigured) {
|
||||
debugPrint('[cachedListFromBrick<$T>] BRICK NOT CONFIGURED — returning []');
|
||||
return const [];
|
||||
}
|
||||
try {
|
||||
final rows = await AppRepository.instance.get<T>(
|
||||
policy: OfflineFirstGetPolicy.localOnly,
|
||||
);
|
||||
if (rows.isEmpty) {
|
||||
debugPrint('[cachedListFromBrick<$T>] empty cache (0 rows)');
|
||||
}
|
||||
return rows;
|
||||
} catch (e) {
|
||||
debugPrint('[cachedListFromBrick<$T>] failed: $e');
|
||||
return const [];
|
||||
}
|
||||
}
|
||||
|
||||
/// Mirrors a batch of model rows into Brick's local SQLite cache as a
|
||||
/// fire-and-forget side effect. Errors are caught and logged.
|
||||
///
|
||||
/// Use this as `onCacheMirror` for [StreamRecoveryWrapper] so that every
|
||||
/// realtime emission keeps the local cache fresh — required for the cold-
|
||||
/// launch-offline experience.
|
||||
///
|
||||
/// ```dart
|
||||
/// onCacheMirror: (rows) => mirrorBatchToBrick<Task>(rows, tag: 'tasks'),
|
||||
/// ```
|
||||
void mirrorBatchToBrick<T extends OfflineFirstWithSupabaseModel>(
|
||||
List<T> rows, {
|
||||
String tag = 'mirror',
|
||||
}) {
|
||||
if (!AppRepository.isConfigured) return;
|
||||
// Use sqliteProvider directly (local-only write). AppRepository.upsert is
|
||||
// bidirectional — it re-POSTs rows to Supabase, which triggers RLS
|
||||
// violations for other users' records and deadlocks from concurrent writes.
|
||||
// Sequential processing prevents SQLite lock contention across providers.
|
||||
// ignore: discarded_futures
|
||||
Future(() async {
|
||||
for (final row in rows) {
|
||||
try {
|
||||
await AppRepository.instance.sqliteProvider
|
||||
.upsert<T>(row, repository: AppRepository.instance);
|
||||
} catch (e) {
|
||||
debugPrint('[$tag] mirror upsert<$T> failed: $e');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user