refactored timetable
This commit is contained in:
@@ -8,7 +8,17 @@ import 'getCustomTimetableEventResponse.dart';
|
||||
class GetCustomTimetableEventCache extends RequestCache<GetCustomTimetableEventResponse> {
|
||||
GetCustomTimetableEventParams params;
|
||||
|
||||
GetCustomTimetableEventCache(this.params, {onUpdate, renew}) : super(RequestCache.cacheMinute, onUpdate, renew: renew) {
|
||||
GetCustomTimetableEventCache(
|
||||
this.params, {
|
||||
void Function(GetCustomTimetableEventResponse)? onUpdate,
|
||||
void Function(Exception)? onError,
|
||||
bool? renew,
|
||||
}) : super(
|
||||
RequestCache.cacheMinute,
|
||||
onUpdate,
|
||||
onError: onError ?? RequestCache.ignore,
|
||||
renew: renew,
|
||||
) {
|
||||
start('customTimetableEvents');
|
||||
}
|
||||
|
||||
|
||||
+30
-17
@@ -1,3 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:localstore/localstore.dart';
|
||||
@@ -17,29 +18,41 @@ abstract class RequestCache<T extends ApiResponse?> {
|
||||
void Function(Exception) onError;
|
||||
bool? renew;
|
||||
|
||||
final Completer<void> _ready = Completer<void>();
|
||||
|
||||
/// 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<void> get ready => _ready.future;
|
||||
|
||||
RequestCache(this.maxCacheTime, this.onUpdate, {this.onError = ignore, this.renew = false});
|
||||
|
||||
static void ignore(Exception e) {}
|
||||
|
||||
Future<void> start(String document) async {
|
||||
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);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,11 +14,23 @@ class Authenticate extends WebuntisApi {
|
||||
@override
|
||||
Future<AuthenticateResponse> run() async {
|
||||
awaitingResponse = true;
|
||||
var rawAnswer = await query(this);
|
||||
AuthenticateResponse response = finalize(AuthenticateResponse.fromJson(jsonDecode(rawAnswer)['result']));
|
||||
_lastResponse = response;
|
||||
if(!awaitedResponse.isCompleted) awaitedResponse.complete();
|
||||
return response;
|
||||
try {
|
||||
var rawAnswer = await query(this);
|
||||
AuthenticateResponse response = finalize(AuthenticateResponse.fromJson(jsonDecode(rawAnswer)['result']));
|
||||
_lastResponse = response;
|
||||
if(!awaitedResponse.isCompleted) awaitedResponse.complete();
|
||||
return response;
|
||||
} catch (e) {
|
||||
// Surface the error to anyone waiting on the current completer, then
|
||||
// install a fresh one so a future attempt can succeed. Without this,
|
||||
// any later call to getSession() would hang forever on a completer
|
||||
// that is already settled with no listeners (or never settles at all).
|
||||
if(!awaitedResponse.isCompleted) awaitedResponse.completeError(e);
|
||||
awaitedResponse = Completer();
|
||||
rethrow;
|
||||
} finally {
|
||||
awaitingResponse = false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool awaitingResponse = false;
|
||||
|
||||
@@ -5,7 +5,16 @@ import 'getHolidays.dart';
|
||||
import 'getHolidaysResponse.dart';
|
||||
|
||||
class GetHolidaysCache extends RequestCache<GetHolidaysResponse> {
|
||||
GetHolidaysCache({void Function(GetHolidaysResponse)? onUpdate}) : super(RequestCache.cacheDay, onUpdate) {
|
||||
GetHolidaysCache({
|
||||
void Function(GetHolidaysResponse)? onUpdate,
|
||||
void Function(Exception)? onError,
|
||||
bool? renew,
|
||||
}) : super(
|
||||
RequestCache.cacheDay,
|
||||
onUpdate,
|
||||
onError: onError ?? RequestCache.ignore,
|
||||
renew: renew,
|
||||
) {
|
||||
start('wu-holidays');
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,16 @@ import 'getRooms.dart';
|
||||
import 'getRoomsResponse.dart';
|
||||
|
||||
class GetRoomsCache extends RequestCache<GetRoomsResponse> {
|
||||
GetRoomsCache({void Function(GetRoomsResponse)? onUpdate}) : super(RequestCache.cacheHour, onUpdate) {
|
||||
GetRoomsCache({
|
||||
void Function(GetRoomsResponse)? onUpdate,
|
||||
void Function(Exception)? onError,
|
||||
bool? renew,
|
||||
}) : super(
|
||||
RequestCache.cacheHour,
|
||||
onUpdate,
|
||||
onError: onError ?? RequestCache.ignore,
|
||||
renew: renew,
|
||||
) {
|
||||
start('wu-rooms');
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,16 @@ import 'getSubjects.dart';
|
||||
import 'getSubjectsResponse.dart';
|
||||
|
||||
class GetSubjectsCache extends RequestCache<GetSubjectsResponse> {
|
||||
GetSubjectsCache({void Function(GetSubjectsResponse)? onUpdate}) : super(RequestCache.cacheHour, onUpdate) {
|
||||
GetSubjectsCache({
|
||||
void Function(GetSubjectsResponse)? onUpdate,
|
||||
void Function(Exception)? onError,
|
||||
bool? renew,
|
||||
}) : super(
|
||||
RequestCache.cacheHour,
|
||||
onUpdate,
|
||||
onError: onError ?? RequestCache.ignore,
|
||||
renew: renew,
|
||||
) {
|
||||
start('wu-subjects');
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import '../../webuntisApi.dart';
|
||||
import 'getTimegridUnitsResponse.dart';
|
||||
|
||||
class GetTimegridUnits extends WebuntisApi {
|
||||
GetTimegridUnits() : super('getTimegridUnits', null);
|
||||
|
||||
@override
|
||||
Future<GetTimegridUnitsResponse> run() async {
|
||||
var rawAnswer = await query(this);
|
||||
try {
|
||||
return finalize(GetTimegridUnitsResponse.fromJson(jsonDecode(rawAnswer)));
|
||||
} catch (e, trace) {
|
||||
log(trace.toString());
|
||||
log('Failed to parse getTimegridUnits data with server response: $rawAnswer');
|
||||
}
|
||||
|
||||
throw Exception('Failed to parse getTimegridUnits server response: $rawAnswer');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import '../../../requestCache.dart';
|
||||
import 'getTimegridUnits.dart';
|
||||
import 'getTimegridUnitsResponse.dart';
|
||||
|
||||
class GetTimegridUnitsCache extends RequestCache<GetTimegridUnitsResponse> {
|
||||
GetTimegridUnitsCache({
|
||||
void Function(GetTimegridUnitsResponse)? onUpdate,
|
||||
bool? renew,
|
||||
}) : super(RequestCache.cacheDay, onUpdate, renew: renew) {
|
||||
start('wu-timegrid');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GetTimegridUnitsResponse> onLoad() => GetTimegridUnits().run();
|
||||
|
||||
@override
|
||||
GetTimegridUnitsResponse onLocalData(String json) => GetTimegridUnitsResponse.fromJson(jsonDecode(json));
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import '../../../apiResponse.dart';
|
||||
|
||||
part 'getTimegridUnitsResponse.g.dart';
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class GetTimegridUnitsResponse extends ApiResponse {
|
||||
List<GetTimegridUnitsResponseDay> result;
|
||||
|
||||
GetTimegridUnitsResponse(this.result);
|
||||
|
||||
factory GetTimegridUnitsResponse.fromJson(Map<String, dynamic> json) => _$GetTimegridUnitsResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetTimegridUnitsResponseToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class GetTimegridUnitsResponseDay {
|
||||
int day;
|
||||
List<GetTimegridUnitsResponseUnit> timeUnits;
|
||||
|
||||
GetTimegridUnitsResponseDay(this.day, this.timeUnits);
|
||||
|
||||
factory GetTimegridUnitsResponseDay.fromJson(Map<String, dynamic> json) => _$GetTimegridUnitsResponseDayFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetTimegridUnitsResponseDayToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class GetTimegridUnitsResponseUnit {
|
||||
String name;
|
||||
int startTime;
|
||||
int endTime;
|
||||
|
||||
GetTimegridUnitsResponseUnit(this.name, this.startTime, this.endTime);
|
||||
|
||||
factory GetTimegridUnitsResponseUnit.fromJson(Map<String, dynamic> json) => _$GetTimegridUnitsResponseUnitFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetTimegridUnitsResponseUnitToJson(this);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'getTimegridUnitsResponse.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
GetTimegridUnitsResponse _$GetTimegridUnitsResponseFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) =>
|
||||
GetTimegridUnitsResponse(
|
||||
(json['result'] as List<dynamic>)
|
||||
.map(
|
||||
(e) => GetTimegridUnitsResponseDay.fromJson(
|
||||
e as Map<String, dynamic>,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
)
|
||||
..headers = (json['headers'] as Map<String, dynamic>?)?.map(
|
||||
(k, e) => MapEntry(k, e as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$GetTimegridUnitsResponseToJson(
|
||||
GetTimegridUnitsResponse instance,
|
||||
) => <String, dynamic>{
|
||||
'headers': ?instance.headers,
|
||||
'result': instance.result.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
|
||||
GetTimegridUnitsResponseDay _$GetTimegridUnitsResponseDayFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => GetTimegridUnitsResponseDay(
|
||||
(json['day'] as num).toInt(),
|
||||
(json['timeUnits'] as List<dynamic>)
|
||||
.map(
|
||||
(e) => GetTimegridUnitsResponseUnit.fromJson(e as Map<String, dynamic>),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$GetTimegridUnitsResponseDayToJson(
|
||||
GetTimegridUnitsResponseDay instance,
|
||||
) => <String, dynamic>{
|
||||
'day': instance.day,
|
||||
'timeUnits': instance.timeUnits.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
|
||||
GetTimegridUnitsResponseUnit _$GetTimegridUnitsResponseUnitFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => GetTimegridUnitsResponseUnit(
|
||||
json['name'] as String,
|
||||
(json['startTime'] as num).toInt(),
|
||||
(json['endTime'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$GetTimegridUnitsResponseUnitToJson(
|
||||
GetTimegridUnitsResponseUnit instance,
|
||||
) => <String, dynamic>{
|
||||
'name': instance.name,
|
||||
'startTime': instance.startTime,
|
||||
'endTime': instance.endTime,
|
||||
};
|
||||
@@ -15,7 +15,13 @@ class GetTimetableCache extends RequestCache<GetTimetableResponse> {
|
||||
void Function(Exception)? onError,
|
||||
required this.startdate,
|
||||
required this.enddate,
|
||||
}) : super(RequestCache.cacheMinute, onUpdate, onError: onError ?? RequestCache.ignore) {
|
||||
bool? renew,
|
||||
}) : super(
|
||||
RequestCache.cacheMinute,
|
||||
onUpdate,
|
||||
onError: onError ?? RequestCache.ignore,
|
||||
renew: renew,
|
||||
) {
|
||||
start('wu-timetable-$startdate-$enddate');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user