Skip to content

Commit eb5c29c

Browse files
Dismissible Control (#2124)
* initial commit * add `dismissible.dart` * remove `key` – add docstring * remove `key` – add docstring * update key * move from `Control` to `ConstrainedControl` --------- Co-authored-by: Feodor Fitsner <feodor@appveyor.com>
1 parent 514abdb commit eb5c29c

File tree

5 files changed

+398
-1
lines changed

5 files changed

+398
-1
lines changed

package/lib/src/controls/create_control.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import 'column.dart';
2929
import 'container.dart';
3030
import 'datatable.dart';
3131
import 'date_picker.dart';
32-
import 'time_picker.dart';
32+
import 'dismissible.dart';
3333
import 'divider.dart';
3434
import 'drag_target.dart';
3535
import 'draggable.dart';
@@ -74,6 +74,7 @@ import 'tabs.dart';
7474
import 'text.dart';
7575
import 'text_button.dart';
7676
import 'textfield.dart';
77+
import 'time_picker.dart';
7778
import 'tooltip.dart';
7879
import 'transparent_pointer.dart';
7980
import 'vertical_divider.dart';
@@ -501,6 +502,12 @@ Widget createWidget(Key? key, ControlViewModel controlView, Control? parent,
501502
children: controlView.children,
502503
parentDisabled: parentDisabled,
503504
nextChild: nextChild);
505+
case "dismissible":
506+
return DismissibleControl(
507+
parent: parent,
508+
control: controlView.control,
509+
children: controlView.children,
510+
parentDisabled: parentDisabled);
504511
case "alertdialog":
505512
return AlertDialogControl(
506513
parent: parent,
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import 'package:collection/collection.dart';
2+
import 'package:flet/src/utils/dismissible.dart';
3+
import 'package:flutter/material.dart';
4+
5+
import '../flet_app_services.dart';
6+
import '../models/control.dart';
7+
import 'create_control.dart';
8+
import 'error.dart';
9+
10+
class DismissibleControl extends StatelessWidget {
11+
final Control? parent;
12+
final Control control;
13+
final List<Control> children;
14+
final bool parentDisabled;
15+
16+
const DismissibleControl(
17+
{Key? key,
18+
this.parent,
19+
required this.control,
20+
required this.children,
21+
required this.parentDisabled})
22+
: super(key: key);
23+
24+
@override
25+
Widget build(BuildContext context) {
26+
var server = FletAppServices.of(context).server;
27+
debugPrint("Dismissible build: ${control.id}");
28+
29+
bool disabled = control.isDisabled || parentDisabled;
30+
var contentCtrls = children.where((c) => c.name == "content");
31+
32+
if (contentCtrls.isEmpty) {
33+
return const ErrorControl("Dismissible does not have a content.");
34+
}
35+
36+
var backgroundCtrls = children.where((c) => c.name == "background");
37+
38+
var secondaryBackgroundCtrls =
39+
children.where((c) => c.name == "secondaryBackground");
40+
41+
SnackBarBehavior? behavior = SnackBarBehavior.values.firstWhereOrNull((a) =>
42+
a.name.toLowerCase() ==
43+
control.attrString("behavior", "")!.toLowerCase());
44+
45+
var dismissThresholds =
46+
parseDismissThresholds(control, "dismissThresholds");
47+
48+
DismissDirection? direction = DismissDirection.values.firstWhere(
49+
(a) =>
50+
a.name.toLowerCase() ==
51+
control.attrString("dismissDirection", "")!.toLowerCase(),
52+
orElse: () => DismissDirection.horizontal);
53+
54+
return constrainedControl(
55+
context,
56+
Dismissible(
57+
key: ValueKey<String>(control.id),
58+
direction: direction,
59+
background: backgroundCtrls.isNotEmpty
60+
? createControl(control, backgroundCtrls.first.id, disabled)
61+
: Container(color: Colors.transparent),
62+
secondaryBackground: secondaryBackgroundCtrls.isNotEmpty
63+
? createControl(
64+
control, secondaryBackgroundCtrls.first.id, disabled)
65+
: Container(color: Colors.transparent),
66+
onDismissed: (DismissDirection d) {
67+
server.sendPageEvent(
68+
eventTarget: control.id, eventName: "dismiss", eventData: "");
69+
},
70+
onResize: () {
71+
server.sendPageEvent(
72+
eventTarget: control.id, eventName: "resize", eventData: "");
73+
},
74+
onUpdate: (DismissUpdateDetails d) {
75+
server.sendPageEvent(
76+
eventTarget: control.id, eventName: "update", eventData: "");
77+
},
78+
// confirmDismiss: // TODO: implement
79+
movementDuration:
80+
Duration(milliseconds: control.attrInt("duration", 200)!),
81+
resizeDuration:
82+
Duration(milliseconds: control.attrInt("resizeDuration", 300)!),
83+
crossAxisEndOffset: control.attrDouble("crossAxisEndOffset", 0.0)!,
84+
dismissThresholds: dismissThresholds ?? {},
85+
child: createControl(control, contentCtrls.first.id, disabled)),
86+
parent,
87+
control);
88+
}
89+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import 'dart:convert';
2+
3+
import 'package:flet/src/utils/numbers.dart';
4+
import 'package:flutter/material.dart';
5+
6+
import '../models/control.dart';
7+
8+
Map<DismissDirection, double>? parseDismissThresholds(
9+
Control control, String propName) {
10+
var v = control.attrString(propName, null);
11+
if (v == null) {
12+
return null;
13+
}
14+
15+
final j1 = json.decode(v);
16+
return getDismissThresholds(j1, (jv) => parseDouble(jv));
17+
}
18+
19+
Map<DismissDirection, double>? getDismissThresholds<T>(
20+
dynamic jsonDictValue, T Function(dynamic) converterFromJson) {
21+
if (jsonDictValue == null) {
22+
return null;
23+
}
24+
var j = jsonDictValue;
25+
if (j is! Map<String, dynamic>) {
26+
j = {"": j};
27+
}
28+
29+
return getDismissThresholdsFromJSON(j, converterFromJson);
30+
}
31+
32+
Map<DismissDirection, double> getDismissThresholdsFromJSON(
33+
Map<String, dynamic>? jsonDictValue, Function(dynamic) converterFromJson) {
34+
Map<DismissDirection, double> dismissDirectionMap = {};
35+
36+
Set<DismissDirection> directions = {
37+
DismissDirection.vertical,
38+
DismissDirection.horizontal,
39+
DismissDirection.endToStart,
40+
DismissDirection.startToEnd,
41+
DismissDirection.up,
42+
DismissDirection.down
43+
};
44+
45+
if (jsonDictValue != null) {
46+
jsonDictValue.forEach((directionStr, jv) {
47+
directionStr
48+
.split(",")
49+
.map((s) => s.trim().toLowerCase())
50+
.forEach((state) {
51+
DismissDirection d = directions.firstWhere(
52+
(e) => e.name.toLowerCase() == state,
53+
orElse: () => DismissDirection.none);
54+
if (d != DismissDirection.none) {
55+
dismissDirectionMap[d] = converterFromJson(jv);
56+
}
57+
});
58+
});
59+
}
60+
61+
return dismissDirectionMap;
62+
}

sdk/python/packages/flet-core/src/flet_core/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
DataTable,
6969
)
7070
from flet_core.date_picker import DatePicker, DatePickerMode, DatePickerEntryMode
71+
from flet_core.dismissible import Dismissible
7172
from flet_core.divider import Divider
7273
from flet_core.drag_target import DragTarget, DragTargetAcceptEvent
7374
from flet_core.draggable import Draggable

0 commit comments

Comments
 (0)