Skip to content

Commit c739fb2

Browse files
v1 fix: Update properties or actions of opened AlertDialog (#5547)
* Refactor dialog management in BasePage Removed deprecated 'open' and 'close' methods in favor of 'show_dialog' and 'pop_dialog'. Enhanced 'show_dialog' to better manage dialog lifecycle and dismissal, including improved event handling and error checking. Updated docstrings for clarity and maintainability. Fix #5439 * Refactor alert dialogs to use ControlInheritedNotifier Replaces direct widget construction with ControlInheritedNotifier in both AlertDialogControl and CupertinoAlertDialogControl for improved state management. Error handling is now managed via a string error message instead of an ErrorControl widget instance. * Refactor Banner dart widget * Added alert_dialog test * Added CupertinoAlertDialog for body update * Fix BasePage comments * Split alert dialog tests
1 parent 363881e commit c739fb2

File tree

12 files changed

+244
-142
lines changed

12 files changed

+244
-142
lines changed

packages/flet/lib/src/controls/alert_dialog.dart

Lines changed: 54 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import '../utils/edge_insets.dart';
99
import '../utils/misc.dart';
1010
import '../utils/numbers.dart';
1111
import '../utils/text.dart';
12+
import '../widgets/control_inherited_notifier.dart';
1213
import '../widgets/error.dart';
1314
import 'control_widget.dart';
1415

@@ -23,9 +24,9 @@ class AlertDialogControl extends StatefulWidget {
2324
}
2425

2526
class _AlertDialogControlState extends State<AlertDialogControl> {
26-
Widget? _dialog;
2727
bool _open = false;
2828
NavigatorState? _navigatorState;
29+
String? _error;
2930

3031
@override
3132
void didChangeDependencies() {
@@ -48,50 +49,50 @@ class _AlertDialogControlState extends State<AlertDialogControl> {
4849
}
4950

5051
Widget _createAlertDialog() {
51-
var title = widget.control.get("title");
52-
var content = widget.control.buildWidget("content");
53-
var actions = widget.control.buildWidgets("actions");
54-
if (title == null && content == null && actions.isEmpty) {
55-
return const ErrorControl(
56-
"AlertDialog has nothing to display. Provide at minimum one of the following: title, content, actions");
57-
}
58-
59-
return AlertDialog(
60-
title: title is Control
61-
? ControlWidget(control: title)
62-
: title is String
63-
? Text(title)
64-
: null,
65-
titlePadding: widget.control.getPadding("title_padding"),
66-
content: content,
67-
contentPadding: widget.control.getPadding("content_padding",
68-
const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 24.0))!,
69-
actions: actions,
70-
actionsPadding: widget.control.getPadding("actions_padding"),
71-
actionsAlignment:
72-
widget.control.getMainAxisAlignment("actions_alignment"),
73-
shape: widget.control.getShape("shape", Theme.of(context)),
74-
semanticLabel: widget.control.getString("semantics_label"),
75-
insetPadding: widget.control.getPadding("inset_padding",
76-
const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0))!,
77-
iconPadding: widget.control.getPadding("icon_padding"),
78-
backgroundColor: widget.control.getColor("bgcolor", context),
79-
buttonPadding: widget.control.getPadding("action_button_padding"),
80-
surfaceTintColor: widget.control.getColor("surface_tint_color", context),
81-
shadowColor: widget.control.getColor("shadow_color", context),
82-
elevation: widget.control.getDouble("elevation"),
83-
clipBehavior:
84-
parseClip(widget.control.getString("clip_behavior"), Clip.none)!,
85-
icon: widget.control.buildIconOrWidget("icon"),
86-
iconColor: widget.control.getColor("icon_color", context),
87-
scrollable: widget.control.getBool("scrollable", false)!,
88-
actionsOverflowButtonSpacing:
89-
widget.control.getDouble("actions_overflow_button_spacing"),
90-
alignment: widget.control.getAlignment("alignment"),
91-
contentTextStyle:
92-
widget.control.getTextStyle("content_text_style", Theme.of(context)),
93-
titleTextStyle:
94-
widget.control.getTextStyle("title_text_style", Theme.of(context)),
52+
return ControlInheritedNotifier(
53+
notifier: widget.control,
54+
child: Builder(builder: (context) {
55+
ControlInheritedNotifier.of(context);
56+
var title = widget.control.get("title");
57+
return AlertDialog(
58+
title: title is Control
59+
? ControlWidget(control: title)
60+
: title is String
61+
? Text(title)
62+
: null,
63+
titlePadding: widget.control.getPadding("title_padding"),
64+
content: widget.control.buildWidget("content"),
65+
contentPadding: widget.control.getPadding("content_padding",
66+
const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 24.0))!,
67+
actions: widget.control.buildWidgets("actions"),
68+
actionsPadding: widget.control.getPadding("actions_padding"),
69+
actionsAlignment:
70+
widget.control.getMainAxisAlignment("actions_alignment"),
71+
shape: widget.control.getShape("shape", Theme.of(context)),
72+
semanticLabel: widget.control.getString("semantics_label"),
73+
insetPadding: widget.control.getPadding("inset_padding",
74+
const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0))!,
75+
iconPadding: widget.control.getPadding("icon_padding"),
76+
backgroundColor: widget.control.getColor("bgcolor", context),
77+
buttonPadding: widget.control.getPadding("action_button_padding"),
78+
surfaceTintColor:
79+
widget.control.getColor("surface_tint_color", context),
80+
shadowColor: widget.control.getColor("shadow_color", context),
81+
elevation: widget.control.getDouble("elevation"),
82+
clipBehavior:
83+
parseClip(widget.control.getString("clip_behavior"), Clip.none)!,
84+
icon: widget.control.buildIconOrWidget("icon"),
85+
iconColor: widget.control.getColor("icon_color", context),
86+
scrollable: widget.control.getBool("scrollable", false)!,
87+
actionsOverflowButtonSpacing:
88+
widget.control.getDouble("actions_overflow_button_spacing"),
89+
alignment: widget.control.getAlignment("alignment"),
90+
contentTextStyle: widget.control
91+
.getTextStyle("content_text_style", Theme.of(context)),
92+
titleTextStyle: widget.control
93+
.getTextStyle("title_text_style", Theme.of(context)),
94+
);
95+
}),
9596
);
9697
}
9798

@@ -102,11 +103,11 @@ class _AlertDialogControlState extends State<AlertDialogControl> {
102103
var modal = widget.control.getBool("modal", false)!;
103104

104105
if (open && (open != _open)) {
105-
_dialog = _createAlertDialog();
106-
107-
if (_dialog is ErrorControl) {
108-
debugPrint(
109-
"AlertDialog: ErrorControl, not showing dialog: ${(_dialog as ErrorControl).message}");
106+
if (widget.control.get("title") == null &&
107+
widget.control.get("content") == null &&
108+
widget.control.children("actions").isEmpty) {
109+
_error =
110+
"AlertDialog has nothing to display. Provide at minimum one of the following: title, content, actions.";
110111
return;
111112
}
112113

@@ -118,7 +119,7 @@ class _AlertDialogControlState extends State<AlertDialogControl> {
118119
barrierColor: widget.control.getColor("barrier_color", context),
119120
useRootNavigator: false,
120121
context: context,
121-
builder: (context) => _dialog!).then((value) {
122+
builder: (context) => _createAlertDialog()).then((value) {
122123
debugPrint("Dismissing AlertDialog(${widget.control.id})");
123124
_open = false;
124125
widget.control.updateProperties({"open": false});
@@ -132,7 +133,7 @@ class _AlertDialogControlState extends State<AlertDialogControl> {
132133

133134
@override
134135
Widget build(BuildContext context) {
135-
return _dialog is ErrorControl ? _dialog! : const SizedBox.shrink();
136+
return _error != null ? ErrorControl(_error!) : const SizedBox.shrink();
136137
}
137138

138139
void _closeDialog() {
@@ -142,7 +143,7 @@ class _AlertDialogControlState extends State<AlertDialogControl> {
142143
"AlertDialog(${widget.control.id}): Closing dialog managed by this widget.");
143144
_navigatorState?.pop();
144145
_open = false;
145-
_dialog = null;
146+
_error = null;
146147
} else {
147148
debugPrint(
148149
"AlertDialog(${widget.control.id}): Dialog was not opened by this widget, skipping pop.");

packages/flet/lib/src/controls/banner.dart

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class BannerControl extends StatefulWidget {
1919
}
2020

2121
class _BannerControlState extends State<BannerControl> {
22-
Widget? _dialog;
22+
String? _error;
2323

2424
@override
2525
void initState() {
@@ -41,24 +41,13 @@ class _BannerControlState extends State<BannerControl> {
4141
_toggleBanner();
4242
}
4343

44-
Widget _createBanner() {
45-
var leading = widget.control.buildIconOrWidget("leading");
46-
var content = widget.control.buildTextOrWidget("content");
47-
var actions = widget.control.buildWidgets("actions");
48-
49-
if (content == null) {
50-
return const ErrorControl("Banner.content must be provided and visible");
51-
} else if (actions.isEmpty) {
52-
return const ErrorControl(
53-
"Banner.actions must be provided and at least one action should be visible");
54-
}
55-
44+
MaterialBanner _createBanner() {
5645
return MaterialBanner(
57-
leading: leading,
46+
leading: widget.control.buildIconOrWidget("leading"),
5847
leadingPadding: widget.control.getPadding("leading_padding"),
59-
content: content,
48+
content: widget.control.buildTextOrWidget("content")!,
6049
padding: widget.control.getPadding("content_padding"),
61-
actions: actions,
50+
actions: widget.control.buildWidgets("actions"),
6251
forceActionsBelow: widget.control.getBool("force_actions_below", false)!,
6352
backgroundColor: widget.control.getColor("bgcolor", context),
6453
contentTextStyle:
@@ -87,11 +76,12 @@ class _BannerControlState extends State<BannerControl> {
8776
var open = widget.control.getBool("open", false)!;
8877

8978
if (open && (open != lastOpen)) {
90-
_dialog = _createBanner();
91-
92-
if (_dialog is ErrorControl) {
93-
debugPrint(
94-
"Banner: ErrorControl, not showing dialog: ${(_dialog as ErrorControl).message}");
79+
if (widget.control.get("content") == null) {
80+
_error = "Banner.content must be provided and visible";
81+
return;
82+
} else if (widget.control.children("actions").isEmpty) {
83+
_error =
84+
"Banner.actions must be provided and at least one action should be visible";
9585
return;
9686
}
9787

@@ -100,7 +90,7 @@ class _BannerControlState extends State<BannerControl> {
10090
WidgetsBinding.instance.addPostFrameCallback((_) {
10191
ScaffoldMessenger.of(context).removeCurrentMaterialBanner();
10292
ScaffoldMessenger.of(context)
103-
.showMaterialBanner(_dialog as MaterialBanner)
93+
.showMaterialBanner(_createBanner())
10494
.closed
10595
.then((reason) {
10696
debugPrint(
@@ -127,6 +117,6 @@ class _BannerControlState extends State<BannerControl> {
127117

128118
@override
129119
Widget build(BuildContext context) {
130-
return _dialog is ErrorControl ? _dialog! : const SizedBox.shrink();
120+
return _error != null ? ErrorControl(_error!) : const SizedBox.shrink();
131121
}
132122
}

packages/flet/lib/src/controls/cupertino_alert_dialog.dart

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import '../models/control.dart';
66
import '../utils/animations.dart';
77
import '../utils/colors.dart';
88
import '../utils/numbers.dart';
9+
import '../widgets/control_inherited_notifier.dart';
910
import '../widgets/error.dart';
1011

1112
class CupertinoAlertDialogControl extends StatefulWidget {
@@ -21,9 +22,9 @@ class CupertinoAlertDialogControl extends StatefulWidget {
2122

2223
class _CupertinoAlertDialogControlState
2324
extends State<CupertinoAlertDialogControl> {
24-
Widget? _dialog;
2525
bool _open = false;
2626
NavigatorState? _navigatorState;
27+
String? _error;
2728

2829
@override
2930
void didChangeDependencies() {
@@ -49,25 +50,24 @@ class _CupertinoAlertDialogControlState
4950
}
5051

5152
Widget _createCupertinoAlertDialog() {
52-
var title = widget.control.buildTextOrWidget("title");
53-
var content = widget.control.buildWidget("content");
54-
var actions = widget.control.buildWidgets("actions");
55-
if (title == null && content == null && actions.isEmpty) {
56-
return const ErrorControl(
57-
"CupertinoAlertDialog has nothing to display. Provide at minimum one of the following: title, content, actions");
58-
}
59-
var insetAnimation = parseAnimation(
60-
widget.control.get("inset_animation"),
61-
ImplicitAnimationDetails(
62-
duration: const Duration(milliseconds: 100),
63-
curve: Curves.decelerate))!;
64-
65-
return CupertinoAlertDialog(
66-
insetAnimationCurve: insetAnimation.curve,
67-
insetAnimationDuration: insetAnimation.duration,
68-
title: title,
69-
content: content,
70-
actions: actions,
53+
return ControlInheritedNotifier(
54+
notifier: widget.control,
55+
child: Builder(builder: (context) {
56+
ControlInheritedNotifier.of(context);
57+
var insetAnimation = parseAnimation(
58+
widget.control.get("inset_animation"),
59+
ImplicitAnimationDetails(
60+
duration: const Duration(milliseconds: 100),
61+
curve: Curves.decelerate))!;
62+
63+
return CupertinoAlertDialog(
64+
insetAnimationCurve: insetAnimation.curve,
65+
insetAnimationDuration: insetAnimation.duration,
66+
title: widget.control.buildTextOrWidget("title"),
67+
content: widget.control.buildWidget("content"),
68+
actions: widget.control.buildWidgets("actions"),
69+
);
70+
}),
7171
);
7272
}
7373

@@ -78,11 +78,11 @@ class _CupertinoAlertDialogControlState
7878
var modal = widget.control.getBool("modal", false)!;
7979

8080
if (open && (open != _open)) {
81-
_dialog = _createCupertinoAlertDialog();
82-
83-
if (_dialog is ErrorControl) {
84-
debugPrint(
85-
"CupertinoAlertDialog: ErrorControl, not showing dialog: ${(_dialog as ErrorControl).message}");
81+
if (widget.control.get("title") == null &&
82+
widget.control.get("content") == null &&
83+
widget.control.children("actions").isEmpty) {
84+
_error =
85+
"CupertinoAlertDialog has nothing to display. Provide at minimum one of the following: title, content, actions.";
8686
return;
8787
}
8888

@@ -94,7 +94,7 @@ class _CupertinoAlertDialogControlState
9494
barrierColor: widget.control.getColor("barrier_color", context),
9595
useRootNavigator: false,
9696
context: context,
97-
builder: (context) => _dialog!).then((value) {
97+
builder: (context) => _createCupertinoAlertDialog()).then((value) {
9898
debugPrint("Dismissing CupertinoAlertDialog(${widget.control.id})");
9999
_open = false;
100100
widget.control.updateProperties({"open": false});
@@ -113,7 +113,7 @@ class _CupertinoAlertDialogControlState
113113
"CupertinoAlertDialog(${widget.control.id}): Closing dialog managed by this widget.");
114114
_navigatorState?.pop();
115115
_open = false;
116-
_dialog = null;
116+
_error = null;
117117
} else {
118118
debugPrint(
119119
"CupertinoAlertDialog(${widget.control.id}): Dialog was not opened by this widget, skipping pop.");
@@ -123,6 +123,6 @@ class _CupertinoAlertDialogControlState
123123

124124
@override
125125
Widget build(BuildContext context) {
126-
return _dialog is ErrorControl ? _dialog! : const SizedBox.shrink();
126+
return _error != null ? ErrorControl(_error!) : const SizedBox.shrink();
127127
}
128128
}
14.6 KB
Loading
12.7 KB
Loading
13 KB
Loading
11.6 KB
Loading

sdk/python/packages/flet/integration_tests/controls/test_alert_dialog.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import pytest
2+
13
import flet as ft
24
import flet.testing as ftt
3-
import pytest
45

56

67
@pytest.mark.asyncio(loop_scope="module")

0 commit comments

Comments
 (0)