added guardian login with views for their assigned childs
This commit is contained in:
@@ -4,12 +4,17 @@ import '../../../../../api/marianumconnect/queries/timetable_custom_events/custo
|
||||
import '../../../../../api/marianumconnect/queries/timetable_get_week/timetable_get_week_response.dart';
|
||||
import '../../../../../api/mhsl/custom_timetable_event/custom_timetable_event.dart';
|
||||
import '../../../../../extensions/date_time.dart';
|
||||
import '../../../infrastructure/loadable_state/loadable_state.dart';
|
||||
import '../../../infrastructure/utility_widgets/loadable_hydrated_bloc/loadable_hydrated_bloc.dart';
|
||||
import '../../../infrastructure/utility_widgets/loadable_hydrated_bloc/loadable_hydrated_bloc_event.dart';
|
||||
import '../repository/timetable_repository.dart';
|
||||
import '../subject/timetable_subject.dart';
|
||||
import 'timetable_event.dart';
|
||||
import 'timetable_state.dart';
|
||||
|
||||
/// Drives one [TimetableSubject]'s plan. The same class serves the own plan
|
||||
/// and foreign element plans; everything subject-specific (endpoint,
|
||||
/// persistence, custom events) is derived from [subject].
|
||||
class TimetableBloc
|
||||
extends
|
||||
LoadableHydratedBloc<
|
||||
@@ -17,6 +22,13 @@ class TimetableBloc
|
||||
TimetableState,
|
||||
TimetableRepository
|
||||
> {
|
||||
final TimetableSubject subject;
|
||||
|
||||
TimetableBloc({required this.subject});
|
||||
|
||||
@override
|
||||
String get id => subject.storageId;
|
||||
|
||||
DateTime _lastWeekRequestStart = DateTime.fromMillisecondsSinceEpoch(0);
|
||||
|
||||
/// Set by [retry] to force the next [gatherData] to bypass cache freshness
|
||||
@@ -59,8 +71,25 @@ class TimetableBloc
|
||||
@override
|
||||
Map<String, dynamic>? toStorage(TimetableState state) => state.toJson();
|
||||
|
||||
@override
|
||||
Map<String, dynamic>? toJson(LoadableState<TimetableState> state) =>
|
||||
subject.persistent ? super.toJson(state) : null;
|
||||
|
||||
@override
|
||||
LoadableState<TimetableState> fromJson(Map<String, dynamic> json) =>
|
||||
subject.persistent
|
||||
? super.fromJson(json)
|
||||
: const LoadableState(
|
||||
isLoading: true,
|
||||
data: null,
|
||||
lastFetch: null,
|
||||
reFetch: null,
|
||||
error: null,
|
||||
);
|
||||
|
||||
@override
|
||||
Future<void> gatherData() async {
|
||||
if (subject is NoTimetable) return;
|
||||
final initial = innerState ?? fromNothing();
|
||||
final renew = _forceRenew;
|
||||
_forceRenew = false;
|
||||
@@ -75,10 +104,10 @@ class TimetableBloc
|
||||
initial.startDate,
|
||||
initial.endDate,
|
||||
onError: recordError,
|
||||
renew: renew,
|
||||
),
|
||||
_loadStaticReferenceData(onError: recordError, renew: renew),
|
||||
_loadCustomEvents(onError: recordError, renew: renew),
|
||||
if (subject.supportsCustomEvents)
|
||||
_loadCustomEvents(onError: recordError, renew: renew),
|
||||
]);
|
||||
|
||||
if (firstError != null) throw firstError!;
|
||||
@@ -102,17 +131,28 @@ class TimetableBloc
|
||||
|
||||
void refresh() => fetch();
|
||||
|
||||
/// Custom events belong to the signed-in user's own plan only — never to a
|
||||
/// foreign plan or a guardian's view of a child.
|
||||
void _requireCustomEvents() {
|
||||
if (!subject.supportsCustomEvents) {
|
||||
throw StateError('Custom events are not available for $subject');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> addCustomEvent(CustomTimetableEvent event) async {
|
||||
_requireCustomEvents();
|
||||
await repo.data.addCustomEvent(event);
|
||||
await _refreshCustomEvents();
|
||||
}
|
||||
|
||||
Future<void> updateCustomEvent(String id, CustomTimetableEvent event) async {
|
||||
_requireCustomEvents();
|
||||
await repo.data.updateCustomEvent(id, event);
|
||||
await _refreshCustomEvents();
|
||||
}
|
||||
|
||||
Future<void> removeCustomEvent(String id) async {
|
||||
_requireCustomEvents();
|
||||
await repo.data.removeCustomEvent(id);
|
||||
await _refreshCustomEvents();
|
||||
}
|
||||
@@ -142,16 +182,15 @@ class TimetableBloc
|
||||
DateTime startDate,
|
||||
DateTime endDate, {
|
||||
void Function(Object)? onError,
|
||||
bool renew = false,
|
||||
}) async {
|
||||
final requestStart = DateTime.now();
|
||||
_lastWeekRequestStart = requestStart;
|
||||
try {
|
||||
final week = await repo.data.getWeek(
|
||||
subject,
|
||||
startDate,
|
||||
endDate,
|
||||
onError: onError,
|
||||
renew: renew,
|
||||
);
|
||||
if (_lastWeekRequestStart.isAfter(requestStart)) return;
|
||||
_writeWeekToCache(startDate, week);
|
||||
@@ -237,7 +276,7 @@ class TimetableBloc
|
||||
|
||||
void _prefetchWeek(DateTime start, DateTime end) {
|
||||
repo.data
|
||||
.getWeek(start, end)
|
||||
.getWeek(subject, start, end)
|
||||
.then((week) => _writeWeekToCache(start, week))
|
||||
.catchError((_) {});
|
||||
}
|
||||
@@ -265,3 +304,11 @@ class TimetableBloc
|
||||
return DateTime(friday.year, friday.month, friday.day);
|
||||
}
|
||||
}
|
||||
|
||||
/// Type token for a page-scoped plan (e.g. a foreign element). Carries no
|
||||
/// logic of its own; the distinct type keeps a page-local provider from
|
||||
/// shadowing the app-wide [TimetableBloc] that sheets and root-navigator pages
|
||||
/// (subject colours, custom events) read.
|
||||
final class ScopedTimetableBloc extends TimetableBloc {
|
||||
ScopedTimetableBloc({required super.subject});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user