import 'dart:async'; import 'dart:convert'; import 'package:localstore/localstore.dart'; import 'apiResponse.dart'; abstract class RequestCache { static const int cacheNothing = 0; static const int cacheMinute = 60; static const int cacheHour = 60 * 60; static const int cacheDay = 60 * 60 * 24; static String collection = 'MarianumMobile'; int maxCacheTime; void Function(T)? onUpdate; void Function(Exception) onError; bool? renew; final Completer _ready = Completer(); /// Resolves when [start] has finished, regardless of whether the network /// call succeeded, failed, or was skipped due to a fresh cache. Callers /// can await this to know when both the cache lookup and the network /// attempt have settled. Future get ready => _ready.future; RequestCache(this.maxCacheTime, this.onUpdate, {this.onError = ignore, this.renew = false}); static void ignore(Exception e) {} Future start(String document) async { try { final tableData = await Localstore.instance.collection(collection).doc(document).get(); if (tableData != null) { onUpdate?.call(onLocalData(tableData['json'])); } if (DateTime.now().millisecondsSinceEpoch - (maxCacheTime * 1000) < (tableData?['lastupdate'] ?? 0)) { if (renew == null || !renew!) return; } try { final newValue = await onLoad(); onUpdate?.call(newValue); Localstore.instance.collection(collection).doc(document).set({ 'json': jsonEncode(newValue), 'lastupdate': DateTime.now().millisecondsSinceEpoch, }); } on Exception catch (e) { onError(e); } } finally { if (!_ready.isCompleted) _ready.complete(); } } T onLocalData(String json); Future onLoad(); }