added guardian login with views for their assigned childs
This commit is contained in:
+57
-34
@@ -15,7 +15,9 @@ import 'notification/notification_tasks.dart';
|
||||
import 'push/push_registration.dart';
|
||||
import 'push/push_tap_router.dart';
|
||||
import 'routing/app_routes.dart';
|
||||
import 'session/session_manager.dart';
|
||||
import 'share_intent/share_intent_listener.dart';
|
||||
import 'state/app/infrastructure/loadable_state/loadable_state.dart';
|
||||
import 'state/app/modules/app_modules.dart';
|
||||
import 'state/app/modules/breaker/bloc/breaker_bloc.dart';
|
||||
import 'state/app/modules/capabilities/bloc/capabilities_cubit.dart';
|
||||
@@ -23,13 +25,16 @@ import 'state/app/modules/chat_list/bloc/chat_list_bloc.dart';
|
||||
import 'state/app/modules/settings/bloc/settings_cubit.dart';
|
||||
import 'state/app/modules/timetable/bloc/timetable_bloc.dart';
|
||||
import 'state/app/modules/timetable/bloc/timetable_state.dart';
|
||||
import 'state/app/modules/timetable/policy/timetable_policy.dart';
|
||||
import 'storage/settings.dart' as model;
|
||||
import 'utils/debouncer.dart';
|
||||
import 'utils/haptics.dart';
|
||||
import 'view/pages/overhang.dart';
|
||||
import 'widget/breaker/breaker.dart';
|
||||
import 'widget/info_dialog.dart';
|
||||
import 'widget_data/widget_navigation.dart';
|
||||
import 'widget_data/widget_publisher.dart';
|
||||
import 'widget_data/widget_sync.dart';
|
||||
|
||||
class App extends StatefulWidget {
|
||||
const App({super.key});
|
||||
@@ -40,7 +45,6 @@ class App extends StatefulWidget {
|
||||
|
||||
class _AppState extends State<App> with WidgetsBindingObserver {
|
||||
late Timer _updateTimings;
|
||||
StreamSubscription<dynamic>? _timetableWidgetSync;
|
||||
StreamSubscription<RemoteMessage>? _onMessageSub;
|
||||
StreamSubscription<RemoteMessage>? _onMessageOpenedAppSub;
|
||||
StreamSubscription<String>? _fcmTokenRefreshSub;
|
||||
@@ -142,12 +146,43 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||
AppRoutes.goToTab(context, Modules.timetable);
|
||||
}
|
||||
|
||||
/// Mirrors the primary plan into the home-screen widget without waiting
|
||||
/// for the periodic background refresh.
|
||||
void _publishWidget(TimetableBloc bloc) {
|
||||
final data = bloc.state.data;
|
||||
if (!mounted || data is! TimetableState) return;
|
||||
if (WidgetSync.encodeSubject(bloc.subject) == null) return;
|
||||
unawaited(
|
||||
WidgetPublisher.publishFromBlocState(
|
||||
data,
|
||||
subject: bloc.subject,
|
||||
settings: context.read<SettingsCubit>().val(),
|
||||
showClassInsteadOfTeacher: TimetablePolicy.resolve(
|
||||
subject: bloc.subject,
|
||||
capabilities: context.read<CapabilitiesCubit>().state,
|
||||
).showClassInsteadOfTeacher,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _handlePendingShare() {
|
||||
if (!mounted) return;
|
||||
final share = ShareIntentListener.pending.value;
|
||||
if (share == null) return;
|
||||
// A second share would otherwise leave the previous share-flow page
|
||||
// on top with stale (already-cleared) file paths.
|
||||
// Sharing targets Talk chats and Files folders only.
|
||||
final session = SessionManager().current;
|
||||
if (!AppModule.isAvailableFor(Modules.talk, session) &&
|
||||
!AppModule.isAvailableFor(Modules.files, session)) {
|
||||
ShareIntentListener.instance.clear();
|
||||
InfoDialog.show(
|
||||
context,
|
||||
'Mit diesem Konto können keine Inhalte in die App geteilt werden.',
|
||||
title: 'Teilen nicht möglich',
|
||||
);
|
||||
return;
|
||||
}
|
||||
final navigator = Navigator.of(context);
|
||||
if (navigator.canPop()) {
|
||||
navigator.popUntil((route) => route.isFirst || route is PopupRoute);
|
||||
@@ -168,37 +203,9 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||
if (!mounted) return;
|
||||
context.read<BreakerBloc>().refresh();
|
||||
context.read<ChatListBloc>().refresh();
|
||||
// Re-mounts on every login, so this also covers post-logout state reset.
|
||||
final timetable = context.read<TimetableBloc>();
|
||||
timetable.refresh();
|
||||
// Mirror BLoC updates into the home-screen widget without waiting
|
||||
// for the periodic background refresh.
|
||||
final settingsCubit = context.read<SettingsCubit>();
|
||||
final capabilitiesCubit = context.read<CapabilitiesCubit>();
|
||||
_timetableWidgetSync?.cancel();
|
||||
_timetableWidgetSync = timetable.stream.listen((state) {
|
||||
final data = state.data;
|
||||
if (data is TimetableState && !state.isLoading) {
|
||||
unawaited(
|
||||
WidgetPublisher.publishFromBlocState(
|
||||
data,
|
||||
settings: settingsCubit.val(),
|
||||
isTeacher: capabilitiesCubit.isTeacher,
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
// Initial publish in case hydrated storage already has data.
|
||||
final initialData = timetable.state.data;
|
||||
if (initialData is TimetableState) {
|
||||
unawaited(
|
||||
WidgetPublisher.publishFromBlocState(
|
||||
initialData,
|
||||
settings: settingsCubit.val(),
|
||||
isTeacher: capabilitiesCubit.isTeacher,
|
||||
),
|
||||
);
|
||||
}
|
||||
// Initial publish in case hydrated storage already has data. No refresh
|
||||
// needed: PrimaryTimetableScope hands out a freshly loading bloc.
|
||||
_publishWidget(context.read<TimetableBloc>());
|
||||
unawaited(_handlePendingWidgetNavigation());
|
||||
ShareIntentListener.instance.attach();
|
||||
ShareIntentListener.pending.addListener(_handlePendingShare);
|
||||
@@ -254,7 +261,6 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||
@override
|
||||
void dispose() {
|
||||
_updateTimings.cancel();
|
||||
_timetableWidgetSync?.cancel();
|
||||
_onMessageSub?.cancel();
|
||||
_onMessageOpenedAppSub?.cancel();
|
||||
_fcmTokenRefreshSub?.cancel();
|
||||
@@ -268,7 +274,24 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(
|
||||
Widget build(BuildContext context) =>
|
||||
BlocListener<TimetableBloc, LoadableState<TimetableState>>(
|
||||
// Also follows a swapped instance (child switch), unlike a manual
|
||||
// stream subscription.
|
||||
listenWhen: (_, state) => !state.isLoading,
|
||||
// A week change emits several times (week, prefetched neighbours);
|
||||
// one widget reload for the burst is enough.
|
||||
listener: (_, _) => Debouncer.debounce(
|
||||
'widgetPublish',
|
||||
const Duration(milliseconds: 500),
|
||||
() {
|
||||
if (mounted) _publishWidget(context.read<TimetableBloc>());
|
||||
},
|
||||
),
|
||||
child: _buildShell(context),
|
||||
);
|
||||
|
||||
Widget _buildShell(
|
||||
BuildContext context,
|
||||
) => BlocBuilder<SettingsCubit, model.Settings>(
|
||||
builder: (context, _) {
|
||||
|
||||
Reference in New Issue
Block a user