added guardian login with views for their assigned childs

This commit is contained in:
2026-09-20 11:11:58 +02:00
parent e4e2b1a4fb
commit 67c935c05b
117 changed files with 4784 additions and 1514 deletions
+85
View File
@@ -0,0 +1,85 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../api/marianumconnect/queries/get_capabilities/guardian_child.dart';
import '../state/app/modules/capabilities/bloc/capabilities_cubit.dart';
import '../state/app/modules/children/child_selection_cubit.dart';
import '../utils/haptics.dart';
import 'centered_leading.dart';
import 'details_bottom_sheet.dart';
import 'placeholder_view.dart';
/// AppBar action that shows the selected child and lets a guardian switch to
/// another one. Invisible unless there is a choice to make.
class ChildSwitcher extends StatelessWidget {
const ChildSwitcher({super.key});
@override
Widget build(BuildContext context) {
final children = context.watch<CapabilitiesCubit>().state.children;
if (children.length < 2) return const SizedBox.shrink();
final selected = effectiveChild(
children,
context.watch<ChildSelectionCubit>().state,
)!;
return TextButton.icon(
icon: const Icon(Icons.face_outlined),
label: Text(selected.firstName),
onPressed: () => _pick(context, selected.id),
);
}
void _pick(BuildContext context, String selectedId) {
final selection = context.read<ChildSelectionCubit>();
final children = context.read<CapabilitiesCubit>().state.children;
showDetailsBottomSheet(
context,
header: const ListTile(title: Text('Kind auswählen')),
children: (sheetContext) => [
for (final child in children)
ChildTile(
child: child,
trailing: child.id == selectedId ? const Icon(Icons.check) : null,
onTap: () {
Haptics.selection();
selection.select(child.id);
Navigator.pop(sheetContext);
},
),
],
);
}
}
/// One linked child: name and class.
class ChildTile extends StatelessWidget {
final GuardianChild child;
final Widget? trailing;
final VoidCallback? onTap;
const ChildTile({required this.child, this.trailing, this.onTap, super.key});
@override
Widget build(BuildContext context) => ListTile(
leading: const CenteredLeading(Icon(Icons.face_outlined)),
title: Text(child.displayName),
subtitle: child.className.isEmpty
? null
: Text('Klasse ${child.className}'),
trailing: trailing,
onTap: onTap,
);
}
/// Shown by per-child modules while a guardian has no linked child.
class NoChildrenPlaceholder extends StatelessWidget {
const NoChildrenPlaceholder({super.key});
@override
Widget build(BuildContext context) => const PlaceholderView(
icon: Icons.family_restroom_outlined,
text:
'Deinem Konto ist noch kein Kind zugeordnet. Bitte wende dich an '
'das Sekretariat.',
);
}
@@ -1,8 +1,8 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import '../../model/account_data.dart';
import '../../model/endpoint_data.dart';
import '../../session/session_manager.dart';
import '../../share_intent/remote_file_ref.dart';
import '../app_progress_indicator.dart';
@@ -67,7 +67,7 @@ class _UnknownPreviewBlockState extends State<UnknownPreviewBlock> {
width: _previewSize,
height: _previewSize,
child: CachedNetworkImage(
httpHeaders: AccountData().authHeaders(),
httpHeaders: SessionManager().requireNextcloud().authHeaders,
imageUrl: _ncPreviewUrl(remote, width: 360),
fadeInDuration: Duration.zero,
fadeOutDuration: Duration.zero,
+2 -3
View File
@@ -8,9 +8,9 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:http/http.dart' as http;
import '../api/http_errors.dart';
import '../model/account_data.dart';
import '../model/endpoint_data.dart';
import '../push/push_avatar.dart';
import '../session/session_manager.dart';
import 'a11y/a11y_labels.dart';
import 'avatar_disk_cache.dart';
@@ -162,7 +162,7 @@ Future<AvatarPayload?> _fetchAvatarPayload(String url) async {
() => http.get(
Uri.parse(url),
headers: {
...AccountData().authHeaders(),
...SessionManager().requireNextcloud().authHeaders,
'Accept': 'image/png,image/jpeg,image/webp,image/svg+xml',
},
),
@@ -368,7 +368,6 @@ class _UserAvatarState extends State<UserAvatar> {
return listEquals(a.bytes, b.bytes);
}
@override
Widget build(BuildContext context) {
final radius = widget.size.toDouble();