@@ -1269,13 +1269,15 @@ class StreamComposeBoxController extends ComposeBoxController {
12691269class FixedDestinationComposeBoxController extends ComposeBoxController {}
12701270
12711271class _ErrorBanner extends StatelessWidget {
1272- const _ErrorBanner ({required this .label});
1272+ const _ErrorBanner ({required this .label, this .onDismiss });
12731273
12741274 final String label;
1275+ final void Function ()? onDismiss;
12751276
12761277 @override
12771278 Widget build (BuildContext context) {
12781279 final designVariables = DesignVariables .of (context);
1280+ final iconButtonTheme = IconButtonTheme .of (context);
12791281 final labelTextStyle = TextStyle (
12801282 fontSize: 17 ,
12811283 height: 22 / 17 ,
@@ -1297,8 +1299,14 @@ class _ErrorBanner extends StatelessWidget {
12971299 child: Text (style: labelTextStyle,
12981300 label))),
12991301 const SizedBox (width: 8 ),
1300- // TODO(#720) "x" button goes here.
1301- // 24px square with 8px touchable padding in all directions?
1302+ if (onDismiss != null )
1303+ IconButton (
1304+ icon: Icon (
1305+ ZulipIcons .remove, color: designVariables.btnLabelAttLowIntDanger),
1306+ style: iconButtonTheme.style! .copyWith (
1307+ shape: const WidgetStatePropertyAll (ContinuousRectangleBorder (
1308+ borderRadius: BorderRadius .all (Radius .circular (4 ))))),
1309+ onPressed: onDismiss),
13021310 ])));
13031311 }
13041312}
@@ -1358,7 +1366,7 @@ class _ComposeBoxState extends State<ComposeBox> implements ComposeBoxState {
13581366 super .dispose ();
13591367 }
13601368
1361- Widget ? _errorBanner (BuildContext context) {
1369+ Widget ? _canPostInNarrowErrorBanner (BuildContext context) {
13621370 final store = PerAccountStoreWidget .of (context);
13631371 final selfUser = store.users[store.selfUserId]! ;
13641372 switch (widget.narrow) {
@@ -1385,13 +1393,28 @@ class _ComposeBoxState extends State<ComposeBox> implements ComposeBoxState {
13851393 return null ;
13861394 }
13871395
1396+ Widget _sendMessageErrorErrorBanner (BuildContext context) {
1397+ final designVariables = DesignVariables .of (context);
1398+ return ValueListenableBuilder (
1399+ valueListenable: controller._sendMessageError,
1400+ builder: (context, sendMessageError, child) {
1401+ if (sendMessageError == null ) return const SizedBox .shrink ();
1402+ return _ErrorBanner (
1403+ label: sendMessageError,
1404+ onDismiss: () => controller._sendMessageError.value = null );
1405+ },
1406+ child: IconButton (icon: Icon (ZulipIcons .remove,
1407+ color: designVariables.btnLabelAttLowIntDanger),
1408+ onPressed: () => controller._sendMessageError.value = null ));
1409+ }
1410+
13881411 @override
13891412 Widget build (BuildContext context) {
13901413 final Widget ? body;
13911414
1392- final errorBanner = _errorBanner (context);
1393- if (errorBanner != null ) {
1394- return _ComposeBoxContainer (body: null , errorBanner: errorBanner );
1415+ final canPostInNarrowErrorBanner = _canPostInNarrowErrorBanner (context);
1416+ if (canPostInNarrowErrorBanner != null ) {
1417+ return _ComposeBoxContainer (body: null , errorBanner: canPostInNarrowErrorBanner );
13951418 }
13961419
13971420 final narrow = widget.narrow;
@@ -1406,11 +1429,7 @@ class _ComposeBoxState extends State<ComposeBox> implements ComposeBoxState {
14061429 }
14071430 }
14081431
1409- // TODO(#720) dismissable message-send error, maybe something like:
1410- // if (controller.sendMessageError.value != null) {
1411- // errorBanner = _ErrorBanner(label:
1412- // ZulipLocalizations.of(context).errorSendMessageTimeout);
1413- // }
1414- return _ComposeBoxContainer (body: body, errorBanner: null );
1432+ return _ComposeBoxContainer (
1433+ body: body, errorBanner: _sendMessageErrorErrorBanner (context));
14151434 }
14161435}
0 commit comments