1
+ import 'package:collection/collection.dart' ;
1
2
import 'package:ensemble/framework/action.dart' ;
2
3
import 'package:ensemble/framework/data_context.dart' ;
3
4
import 'package:ensemble/framework/error_handling.dart' ;
@@ -21,6 +22,8 @@ class ShowBottomSheetAction extends EnsembleAction {
21
22
});
22
23
23
24
static const defaultTopBorderRadius = Radius .circular (16 );
25
+ static const dragHandleHeight = 3.0 ;
26
+ static const dragHandleVerticalMargin = 10.0 ;
24
27
25
28
final Map payload;
26
29
final dynamic body;
@@ -85,6 +88,14 @@ class ShowBottomSheetAction extends EnsembleAction {
85
88
min: 0 ,
86
89
max: 1 );
87
90
91
+ bool isSnap (scopeManager) =>
92
+ Utils .optionalBool (
93
+ eval (payload["scrollOptions" ]? ["snap" ], scopeManager)) ??
94
+ false ;
95
+
96
+ List <double >? additionalSnaps (scopeManager) => Utils .getList <double >(
97
+ eval (payload["scrollOptions" ]? ["additionalViewportSnaps" ], scopeManager));
98
+
88
99
@override
89
100
Future <dynamic > execute (BuildContext context, ScopeManager scopeManager) {
90
101
if (body != null ) {
@@ -123,7 +134,21 @@ class ShowBottomSheetAction extends EnsembleAction {
123
134
}
124
135
125
136
Widget getBodyWidget (ScopeManager scopeManager, BuildContext context) {
126
- var widget = scopeManager.buildWidgetFromDefinition (body);
137
+ // We have to handle the BottomSheet's padding directly around the widget,
138
+ // such that it is inside the Scrollable area to be able to move up and down.
139
+ var sheetPadding = padding (scopeManager) ?? EdgeInsets .zero;
140
+
141
+ // account for the drag handle
142
+ if (showDragHandle (scopeManager)) {
143
+ var additionalPaddingTop =
144
+ dragHandleVerticalMargin * 2 + dragHandleHeight;
145
+ sheetPadding =
146
+ sheetPadding.copyWith (top: sheetPadding.top + additionalPaddingTop);
147
+ }
148
+
149
+ var widget = Padding (
150
+ padding: sheetPadding,
151
+ child: scopeManager.buildWidgetFromDefinition (body));
127
152
128
153
if (isScrollable (scopeManager) == true ) {
129
154
// fix the viewport numbers if used incorrectly
@@ -140,14 +165,22 @@ class ShowBottomSheetAction extends EnsembleAction {
140
165
initialViewport = (minViewport + maxViewport) / 2.0 ;
141
166
}
142
167
168
+ bool useSnap = isSnap (scopeManager);
169
+ List <double >? snaps = additionalSnaps (scopeManager)
170
+ ? .where ((item) => item > minViewport && item < maxViewport)
171
+ .toList ();
172
+ snaps? .sort ();
173
+
143
174
// On platforms with a mouse (Web/desktop), there is no min/maxViewport due to platform consistency,
144
175
// so the height will be fixed to initialViewport, and content will just scroll within it.
145
176
// https://docs.flutter.dev/release/breaking-changes/default-scroll-behavior-drag
146
177
return DraggableScrollableSheet (
147
- expand: false ,
178
+ expand: true ,
148
179
minChildSize: minViewport,
149
180
maxChildSize: maxViewport,
150
181
initialChildSize: initialViewport,
182
+ snap: useSnap,
183
+ snapSizes: useSnap ? snaps : null ,
151
184
builder: (context, scrollController) =>
152
185
buildRootContainer (scopeManager, context,
153
186
child: SingleChildScrollView (
@@ -164,8 +197,6 @@ class ShowBottomSheetAction extends EnsembleAction {
164
197
Widget buildRootContainer (ScopeManager scopeManager, BuildContext context,
165
198
{required Widget child, required bool isScrollable}) {
166
199
Widget rootWidget = Container (
167
- margin: margin (scopeManager),
168
- padding: padding (scopeManager),
169
200
decoration: BoxDecoration (
170
201
color: getBackgroundColor (scopeManager) ??
171
202
Theme .of (context).dialogBackgroundColor,
@@ -185,14 +216,17 @@ class ShowBottomSheetAction extends EnsembleAction {
185
216
children: [rootWidget, _buildDragHandle (scopeManager)],
186
217
);
187
218
}
188
- return rootWidget;
219
+ // This is the Margin of the bottom sheet.
220
+ // Padding will be handled separately inside the scrollable area
221
+ return Padding (
222
+ padding: margin (scopeManager) ?? EdgeInsets .zero, child: rootWidget);
189
223
}
190
224
191
225
Widget _buildDragHandle (ScopeManager scopeManager) {
192
226
return Container (
193
- margin: const EdgeInsets .only (top: 10 ),
227
+ margin: const EdgeInsets .only (top: dragHandleVerticalMargin ),
194
228
width: 32 ,
195
- height: 3 ,
229
+ height: dragHandleHeight ,
196
230
decoration: BoxDecoration (
197
231
color: dragHandleColor (scopeManager) ?? Colors .grey[500 ],
198
232
borderRadius: BorderRadius .circular (12 ),
0 commit comments