showSnapSheet<T> function
Future<T?>
showSnapSheet<T>(
- BuildContext context, {
- required SnapSheetBuilder builder,
- double initialScrollOffset = 0,
Opens a sheet the reader can drag between snapSheetDetents, starting at
the shortest. Where a sheet cannot have detents the
content keeps its own scroll controller and initialScrollOffset is the
caller's own business.
The sheet follows the view across the mobile breakpoint: it reopens in the other form, and the result is whichever form the reader closes.
Implementation
Future<T?> showSnapSheet<T>(
BuildContext context, {
required SnapSheetBuilder builder,
double initialScrollOffset = 0,
}) {
final completer = Completer<T?>();
void open({required bool isMobile}) {
var crossed = false;
var popped = false;
// The mobile layout drops a desktop page's navigator, sheet and all.
void reopenIfDropped() {
if (crossed || popped) {
return;
}
crossed = true;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (context.mounted) {
open(isMobile: context.isMobileView);
} else {
completer.complete();
}
});
}
Widget home(BuildContext sheetContext, ScrollController? controller) {
return _SnapSheetHome(
isMobile: isMobile,
onCross: () {
if (crossed || !sheetContext.mounted || !context.mounted) {
return;
}
if (ModalRoute.of(sheetContext)?.isCurrent != true) {
return;
}
crossed = true;
Navigator.of(sheetContext).pop();
open(isMobile: !isMobile);
},
onDispose: reopenIfDropped,
child: builder(sheetContext, controller),
);
}
final barrierColor = context.colorScheme.modalScrim;
final Future<T?> closed;
if (isMobile) {
final navigator = sheetNavigatorOf(context);
closed = navigator.push(
SnapSheetRoute<T>(
builder: home,
initialScrollOffset: initialScrollOffset,
sheetBarrierColor: barrierColor,
barrierLabel: UiLocalizations.of(context).close,
),
);
} else {
closed = _showSideSheet<T>(
context,
builder: (sheetContext) => home(sheetContext, null),
);
}
unawaited(
closed.then((value) {
popped = true;
if (!crossed) {
completer.complete(value);
}
}),
);
}
open(isMobile: context.isMobileView);
return completer.future;
}