Skip to content

Commit

Permalink
Add conditional modal sheet popping feature (#41)
Browse files Browse the repository at this point in the history
Closes #18.

# New Feature
- Add `SheetDismissible`, which enables the enclosed sheet to be
dismissed by a drag-down gesture. It accepts an `onDismiss` callback,
which will be invoked when the user tries to dismiss the sheet by
dragging it down, providing an opportunity to determine if the sheet
should be dismissed.

# Changes
- Add tutorial code for `SheetDismissible`.
- Update the Safari and the AI playlist generator example to use
`SheetDismissible` to show a confirmation dialog to discard changes.

# Breaking Changes
- Remove `ModalSheetRouteMixin.enablePullToDismiss`.
  • Loading branch information
fujidaiti authored Feb 24, 2024
1 parent 2055919 commit 90c8f10
Show file tree
Hide file tree
Showing 9 changed files with 213 additions and 114 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/code_check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,17 @@ jobs:
name: Test Report
path: ${{ env.FLUTTER_TEST_REPORT }}
reporter: flutter-json

# Final results (Used for status checks)
code-check:
if: ${{ always() }}
runs-on: ubuntu-latest
needs: [analysis, testing]
steps:
# Fails if any of the previous jobs failed.
- run: exit 1
if: >-
${{
contains(needs.*.result, 'failure')
|| contains(needs.*.result, 'cancelled')
}}
63 changes: 51 additions & 12 deletions cookbook/lib/showcase/ai_playlist_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,9 @@ final _sheetShellRoute = ShellRoute(
pageBuilder: (context, state, navigator) {
// Use ModalSheetPage to show a modal sheet.
return ModalSheetPage(
child: SafeArea(
bottom: false,
child: NavigationSheet(
transitionObserver: sheetTransitionObserver,
child: _SheetShell(navigator: navigator),
),
child: _SheetShell(
navigator: navigator,
transitionObserver: sheetTransitionObserver,
),
);
},
Expand Down Expand Up @@ -143,19 +140,61 @@ class _Root extends StatelessWidget {

class _SheetShell extends StatelessWidget {
const _SheetShell({
required this.transitionObserver,
required this.navigator,
});

final NavigationSheetTransitionObserver transitionObserver;
final Widget navigator;

@override
Widget build(BuildContext context) {
return Material(
// Add circular corners to the sheet.
borderRadius: BorderRadius.circular(16),
clipBehavior: Clip.antiAlias,
color: Theme.of(context).colorScheme.surface,
child: navigator,
void showCancelDialog() {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Are you sure?'),
content:
const Text('Do you want to cancel the playlist generation?'),
actions: [
TextButton(
onPressed: () => context.go('/'),
child: const Text('Yes'),
),
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('No'),
),
],
);
},
);
}

return SafeArea(
bottom: false,
// Wrap the sheet in a SheetDismissible to enable pull-to-dismiss action.
child: SheetDismissible(
// This callback is invoked when the user tries
// to dismiss the sheet by dragging it down.
onDismiss: () {
// Prompt the user to confirm if they want to dismiss the sheet.
showCancelDialog();
// Returns false to disable automatic modal sheet popping.
return false;
},
child: NavigationSheet(
transitionObserver: sheetTransitionObserver,
child: Material(
// Add circular corners to the sheet.
borderRadius: BorderRadius.circular(16),
clipBehavior: Clip.antiAlias,
color: Theme.of(context).colorScheme.surface,
child: navigator,
),
),
),
);
}
}
Expand Down
6 changes: 5 additions & 1 deletion cookbook/lib/showcase/safari/actions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ void showEditActionsSheet(BuildContext context) {
Navigator.push(
context,
CupertinoModalSheetRoute(
builder: (context) => const EditActionsSheet(),
builder: (context) {
return const SheetDismissible(
child: EditActionsSheet(),
);
},
),
);
}
Expand Down
6 changes: 5 additions & 1 deletion cookbook/lib/showcase/safari/menu.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ void showMenuSheet(BuildContext context) {
Navigator.push(
context,
CupertinoModalSheetRoute(
builder: (context) => const MenuSheet(),
builder: (context) {
return const SheetDismissible(
child: MenuSheet(),
);
},
),
);
}
Expand Down
54 changes: 44 additions & 10 deletions cookbook/lib/showcase/todo_list/todo_editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,36 @@ class _TodoEditorState extends State<TodoEditor> {
super.dispose();
}

bool onDismiss() {
if (!controller.canCompose.value) {
// Dismiss immediately if there are no unsaved changes.
return true;
}

// Show a confirmation dialog.
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Discard changes?'),
actions: [
TextButton(
onPressed: () =>
Navigator.popUntil(context, (route) => route.isFirst),
child: const Text('Discard'),
),
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Cancel'),
),
],
);
},
);

return false;
}

@override
Widget build(BuildContext context) {
final titleInput = _MultiLineInput(
Expand Down Expand Up @@ -103,16 +133,20 @@ class _TodoEditorState extends State<TodoEditor> {

return SafeArea(
bottom: false,
child: ScrollableSheet(
keyboardDismissBehavior: const SheetKeyboardDismissBehavior.onDragDown(
isContentScrollAware: true,
),
child: Container(
clipBehavior: Clip.antiAlias,
decoration: sheetShape,
child: SheetContentScaffold(
body: body,
bottomBar: bottomBar,
child: SheetDismissible(
onDismiss: onDismiss,
child: ScrollableSheet(
keyboardDismissBehavior:
const SheetKeyboardDismissBehavior.onDragDown(
isContentScrollAware: true,
),
child: Container(
clipBehavior: Clip.antiAlias,
decoration: sheetShape,
child: SheetContentScaffold(
body: body,
bottomBar: bottomBar,
),
),
),
),
Expand Down
6 changes: 5 additions & 1 deletion cookbook/lib/tutorial/declarative_modal_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ final _router = GoRouter(
// It works with any *Sheet provided by this package!
return ModalSheetPage(
key: state.pageKey,
child: const _ExampleSheet(),
// Wrap your sheet with a SheetDismissible to make it
// dismissible by dragging it down.
child: const SheetDismissible(
child: _ExampleSheet(),
),
);
},
),
Expand Down
54 changes: 44 additions & 10 deletions cookbook/lib/tutorial/imperative_modal_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,52 @@ class _ExampleSheet extends StatelessWidget {

@override
Widget build(BuildContext context) {
return DraggableSheet(
child: Card(
color: Theme.of(context).colorScheme.secondaryContainer,
margin: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: const SizedBox(
height: 500,
width: double.infinity,
// Wrap your sheet with a SheetDismissible to make it
// dismissible by dragging it down.
return SheetDismissible(
// This callback is called when the user tries to dismiss the sheet
// by dragging it down. Return true to dismiss the sheet immediately,
// or false otherwise. This is useful when, for example, you want to
// show a confirmation dialog before dismissing the sheet.
onDismiss: () {
showConfirmDialog(context);
return false;
},
child: DraggableSheet(
child: Card(
color: Theme.of(context).colorScheme.secondaryContainer,
margin: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: const SizedBox(
height: 500,
width: double.infinity,
),
),
),
);
}

void showConfirmDialog(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Are you sure?'),
actions: [
TextButton(
onPressed: () =>
Navigator.popUntil(context, (route) => route.isFirst),
child: const Text('Yes'),
),
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('No'),
),
],
);
},
);
}
}
7 changes: 0 additions & 7 deletions package/lib/src/modal/cupertino.dart
Original file line number Diff line number Diff line change
Expand Up @@ -469,9 +469,6 @@ class _PageBasedCupertinoModalSheetRoute<T>
@override
bool get barrierDismissible => _page.barrierDismissible;

@override
bool get enablePullToDismiss => _page.enablePullToDismiss;

@override
Curve get transitionCurve => _page.transitionCurve;

Expand All @@ -490,7 +487,6 @@ class CupertinoModalSheetRoute<T> extends _BaseCupertinoModalSheetRoute<T> {
super.settings,
super.fullscreenDialog,
required this.builder,
this.enablePullToDismiss = true,
this.maintainState = true,
this.barrierDismissible = true,
this.barrierLabel,
Expand All @@ -510,9 +506,6 @@ class CupertinoModalSheetRoute<T> extends _BaseCupertinoModalSheetRoute<T> {
@override
final String? barrierLabel;

@override
final bool enablePullToDismiss;

@override
final bool maintainState;

Expand Down
Loading

0 comments on commit 90c8f10

Please sign in to comment.