|
|
|
|
@ -19,14 +19,37 @@ import '../../repo/tokens_repo.dart';
|
|
|
|
|
import '../../utils/error_handler.dart';
|
|
|
|
|
import '../../utils/overlay.dart';
|
|
|
|
|
|
|
|
|
|
class _SpanDetailsCacheItem {
|
|
|
|
|
SpanDetailsRepoReqAndRes data;
|
|
|
|
|
|
|
|
|
|
_SpanDetailsCacheItem({required this.data});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class IgcController {
|
|
|
|
|
Choreographer choreographer;
|
|
|
|
|
IGCTextData? igcTextData;
|
|
|
|
|
Object? igcError;
|
|
|
|
|
|
|
|
|
|
Completer<IGCTextData> igcCompleter = Completer();
|
|
|
|
|
final Map<int, _SpanDetailsCacheItem> _cache = {};
|
|
|
|
|
Timer? _cacheClearTimer;
|
|
|
|
|
|
|
|
|
|
IgcController(this.choreographer) {
|
|
|
|
|
_initializeCacheClearing();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _initializeCacheClearing() {
|
|
|
|
|
const duration = Duration(minutes: 2);
|
|
|
|
|
_cacheClearTimer = Timer.periodic(duration, (Timer t) => _clearCache());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _clearCache() {
|
|
|
|
|
_cache.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IgcController(this.choreographer);
|
|
|
|
|
void dispose() {
|
|
|
|
|
_cacheClearTimer?.cancel();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> getIGCTextData({required bool tokensOnly}) async {
|
|
|
|
|
try {
|
|
|
|
|
@ -80,6 +103,14 @@ class IgcController {
|
|
|
|
|
|
|
|
|
|
igcTextData = igcTextDataResponse;
|
|
|
|
|
|
|
|
|
|
// After fetching igc data, pre-call span details for each match optimistically.
|
|
|
|
|
// This will make the loading of span details faster for the user
|
|
|
|
|
if (igcTextData?.matches.isNotEmpty ?? false) {
|
|
|
|
|
for (int i = 0; i < igcTextData!.matches.length; i++) {
|
|
|
|
|
getSpanDetails(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
debugPrint("igc text ${igcTextData.toString()}");
|
|
|
|
|
} catch (err, stack) {
|
|
|
|
|
debugger(when: kDebugMode);
|
|
|
|
|
@ -99,18 +130,38 @@ class IgcController {
|
|
|
|
|
debugger(when: kDebugMode);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
final SpanData span = igcTextData!.matches[matchIndex].match;
|
|
|
|
|
|
|
|
|
|
final SpanDetailsRepoReqAndRes response = await SpanDataRepo.getSpanDetails(
|
|
|
|
|
await choreographer.accessToken,
|
|
|
|
|
request: SpanDetailsRepoReqAndRes(
|
|
|
|
|
userL1: choreographer.l1LangCode!,
|
|
|
|
|
userL2: choreographer.l2LangCode!,
|
|
|
|
|
enableIGC: choreographer.igcEnabled,
|
|
|
|
|
enableIT: choreographer.itEnabled,
|
|
|
|
|
span: span,
|
|
|
|
|
),
|
|
|
|
|
/// Retrieves the span data from the `igcTextData` matches at the specified `matchIndex`.
|
|
|
|
|
/// Creates a `SpanDetailsRepoReqAndRes` object with the retrieved span data and other parameters.
|
|
|
|
|
/// Generates a cache key based on the created `SpanDetailsRepoReqAndRes` object.
|
|
|
|
|
final SpanData span = igcTextData!.matches[matchIndex].match;
|
|
|
|
|
final req = SpanDetailsRepoReqAndRes(
|
|
|
|
|
userL1: choreographer.l1LangCode!,
|
|
|
|
|
userL2: choreographer.l2LangCode!,
|
|
|
|
|
enableIGC: choreographer.igcEnabled,
|
|
|
|
|
enableIT: choreographer.itEnabled,
|
|
|
|
|
span: span,
|
|
|
|
|
);
|
|
|
|
|
final int cacheKey = req.hashCode;
|
|
|
|
|
|
|
|
|
|
/// Retrieves the [SpanDetailsRepoReqAndRes] response from the cache if it exists,
|
|
|
|
|
/// otherwise makes an API call to get the response and stores it in the cache.
|
|
|
|
|
SpanDetailsRepoReqAndRes response;
|
|
|
|
|
if (_cache.containsKey(cacheKey)) {
|
|
|
|
|
response = _cache[cacheKey]!.data;
|
|
|
|
|
} else {
|
|
|
|
|
response = await SpanDataRepo.getSpanDetails(
|
|
|
|
|
await choreographer.accessToken,
|
|
|
|
|
request: SpanDetailsRepoReqAndRes(
|
|
|
|
|
userL1: choreographer.l1LangCode!,
|
|
|
|
|
userL2: choreographer.l2LangCode!,
|
|
|
|
|
enableIGC: choreographer.igcEnabled,
|
|
|
|
|
enableIT: choreographer.itEnabled,
|
|
|
|
|
span: span,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
_cache[cacheKey] = _SpanDetailsCacheItem(data: response);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
igcTextData!.matches[matchIndex].match = response.span;
|
|
|
|
|
|