custom login implementation, period-based timetable layout with overlap handling, enhanced error dialogs, and unified bottom sheets

This commit is contained in:
2026-05-06 20:42:09 +02:00
parent 50d2941e52
commit 86d12884fc
32 changed files with 1038 additions and 377 deletions
@@ -1,51 +1,32 @@
import 'package:flutter/material.dart';
/// Shows a modal bottom sheet for an appointment, matching the design of the
/// other sheets in the app (file details, file actions, overflow lessons):
/// drag handle on top, default theme background, ListTile-style header
/// followed by a divider, scrollable body below.
void showAppointmentBottomSheet(
BuildContext context, {
required Widget Function(BuildContext context) header,
required SliverChildListDelegate Function(BuildContext context) body,
required Widget header,
required List<Widget> Function(BuildContext sheetContext) children,
}) {
showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
showDragHandle: true,
useSafeArea: true,
backgroundColor: Theme.of(context).colorScheme.surface,
builder: (sheetContext) => DraggableScrollableSheet(
expand: false,
initialChildSize: 0.4,
minChildSize: 0.2,
maxChildSize: 0.7,
snap: true,
snapSizes: const [0.4],
builder: (_, scrollController) => CustomScrollView(
controller: scrollController,
slivers: [
SliverPersistentHeader(
pinned: true,
delegate: _StickyHeader(child: header(sheetContext)),
),
SliverList(delegate: body(sheetContext)),
],
builder: (sheetContext) => SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.only(bottom: 16),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
header,
const Divider(height: 1),
...children(sheetContext),
],
),
),
),
);
}
class _StickyHeader extends SliverPersistentHeaderDelegate {
_StickyHeader({required this.child});
final Widget child;
@override
double get minExtent => 100;
@override
double get maxExtent => 100;
@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) => Material(
color: Theme.of(context).colorScheme.surface,
child: SizedBox.expand(child: child),
);
@override
bool shouldRebuild(covariant _StickyHeader oldDelegate) => oldDelegate.child != child;
}