Skip to content

Commit 1e8829c

Browse files
authored
Merge pull request #1405 from EnsembleUI/bottom_sheet
Add snaps to Bottom Sheet
2 parents 724e5db + d4549ab commit 1e8829c

File tree

5 files changed

+49
-11
lines changed

5 files changed

+49
-11
lines changed

integration_test/local/dialog_test.dart renamed to integration_test/local/dialogsAndToast_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import '../framework/test_helper.dart';
88
void main() {
99
late EnsembleConfig config;
1010
setUpAll(() async {
11-
config = await TestHelper.setupApp(appName: 'dialog');
11+
config = await TestHelper.setupApp(appName: 'dialogsAndToast');
1212
});
1313

1414
group('Testing Toast', () {

lib/action/bottom_sheet_actions.dart

+41-7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:collection/collection.dart';
12
import 'package:ensemble/framework/action.dart';
23
import 'package:ensemble/framework/data_context.dart';
34
import 'package:ensemble/framework/error_handling.dart';
@@ -21,6 +22,8 @@ class ShowBottomSheetAction extends EnsembleAction {
2122
});
2223

2324
static const defaultTopBorderRadius = Radius.circular(16);
25+
static const dragHandleHeight = 3.0;
26+
static const dragHandleVerticalMargin = 10.0;
2427

2528
final Map payload;
2629
final dynamic body;
@@ -85,6 +88,14 @@ class ShowBottomSheetAction extends EnsembleAction {
8588
min: 0,
8689
max: 1);
8790

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+
8899
@override
89100
Future<dynamic> execute(BuildContext context, ScopeManager scopeManager) {
90101
if (body != null) {
@@ -123,7 +134,21 @@ class ShowBottomSheetAction extends EnsembleAction {
123134
}
124135

125136
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));
127152

128153
if (isScrollable(scopeManager) == true) {
129154
// fix the viewport numbers if used incorrectly
@@ -140,14 +165,22 @@ class ShowBottomSheetAction extends EnsembleAction {
140165
initialViewport = (minViewport + maxViewport) / 2.0;
141166
}
142167

168+
bool useSnap = isSnap(scopeManager);
169+
List<double>? snaps = additionalSnaps(scopeManager)
170+
?.where((item) => item > minViewport && item < maxViewport)
171+
.toList();
172+
snaps?.sort();
173+
143174
// On platforms with a mouse (Web/desktop), there is no min/maxViewport due to platform consistency,
144175
// so the height will be fixed to initialViewport, and content will just scroll within it.
145176
// https://docs.flutter.dev/release/breaking-changes/default-scroll-behavior-drag
146177
return DraggableScrollableSheet(
147-
expand: false,
178+
expand: true,
148179
minChildSize: minViewport,
149180
maxChildSize: maxViewport,
150181
initialChildSize: initialViewport,
182+
snap: useSnap,
183+
snapSizes: useSnap ? snaps : null,
151184
builder: (context, scrollController) =>
152185
buildRootContainer(scopeManager, context,
153186
child: SingleChildScrollView(
@@ -164,8 +197,6 @@ class ShowBottomSheetAction extends EnsembleAction {
164197
Widget buildRootContainer(ScopeManager scopeManager, BuildContext context,
165198
{required Widget child, required bool isScrollable}) {
166199
Widget rootWidget = Container(
167-
margin: margin(scopeManager),
168-
padding: padding(scopeManager),
169200
decoration: BoxDecoration(
170201
color: getBackgroundColor(scopeManager) ??
171202
Theme.of(context).dialogBackgroundColor,
@@ -185,14 +216,17 @@ class ShowBottomSheetAction extends EnsembleAction {
185216
children: [rootWidget, _buildDragHandle(scopeManager)],
186217
);
187218
}
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);
189223
}
190224

191225
Widget _buildDragHandle(ScopeManager scopeManager) {
192226
return Container(
193-
margin: const EdgeInsets.only(top: 10),
227+
margin: const EdgeInsets.only(top: dragHandleVerticalMargin),
194228
width: 32,
195-
height: 3,
229+
height: dragHandleHeight,
196230
decoration: BoxDecoration(
197231
color: dragHandleColor(scopeManager) ?? Colors.grey[500],
198232
borderRadius: BorderRadius.circular(12),

lib/util/utils.dart

+6-2
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,12 @@ class Utils {
261261
}
262262

263263
static List<T>? getList<T>(dynamic value) {
264-
if (value is YamlList) {
264+
if (value is List) {
265265
List<T> results = [];
266266
for (var item in value) {
267-
results.add(item);
267+
if (item is T) {
268+
results.add(item);
269+
}
268270
}
269271
return results;
270272
}
@@ -693,6 +695,8 @@ class Utils {
693695
} else if (values.length == 2) {
694696
left = right = (parseIntFromString(values[1]) ?? 0).toDouble();
695697
bottom = top;
698+
} else {
699+
left = right = bottom = top;
696700
}
697701
return EdgeInsets.only(
698702
top: top, right: right, bottom: bottom, left: left);

pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ flutter:
152152
# integration tests (TODO - exclude from build)
153153
- integration_test/local/defaultApp/
154154
- integration_test/local/themedApp/
155-
- integration_test/local/dialog/
155+
- integration_test/local/dialogsAndToast/
156156

157157
fonts:
158158
# icon fonts

0 commit comments

Comments
 (0)