@@ -1484,6 +1484,42 @@ class _ErrorBanner extends _Banner {
14841484 }
14851485}
14861486
1487+ class _WarningBanner extends _Banner {
1488+ const _WarningBanner ({
1489+ required this .label,
1490+ required this .onDismiss,
1491+ });
1492+
1493+ final String label;
1494+ final VoidCallback ? onDismiss;
1495+
1496+ @override
1497+ String getLabel (ZulipLocalizations zulipLocalizations) => label;
1498+
1499+ @override
1500+ Color getLabelColor (DesignVariables designVariables) =>
1501+ designVariables.btnLabelAttMediumIntWarning;
1502+
1503+ @override
1504+ Color getBackgroundColor (DesignVariables designVariables) =>
1505+ designVariables.bannerBgIntWarning;
1506+
1507+ @override
1508+ bool get padEnd => false ;
1509+
1510+ @override
1511+ Widget ? buildTrailing (BuildContext context) {
1512+ final designVariables = DesignVariables .of (context);
1513+ return InkWell (
1514+ splashFactory: NoSplash .splashFactory,
1515+ onTap: onDismiss,
1516+ child: Padding (
1517+ padding: const EdgeInsets .all (8.0 ),
1518+ child: Icon (ZulipIcons .remove,
1519+ size: 24 , color: designVariables.btnLabelAttLowIntWarning)));
1520+ }
1521+ }
1522+
14871523/// The compose box.
14881524///
14891525/// Takes the full screen width, covering the horizontal insets with its surface.
@@ -1521,6 +1557,8 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
15211557 @override ComposeBoxController get controller => _controller! ;
15221558 ComposeBoxController ? _controller;
15231559
1560+ bool _isWarningBannerDismissed = false ;
1561+
15241562 @override
15251563 void onNewStore () {
15261564 switch (widget.narrow) {
@@ -1547,6 +1585,12 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
15471585 super .dispose ();
15481586 }
15491587
1588+ void _dismissWarningBanner () {
1589+ setState (() {
1590+ _isWarningBannerDismissed = true ;
1591+ });
1592+ }
1593+
15501594 /// An [_ErrorBanner] that replaces the compose box's text inputs.
15511595 Widget ? _errorBannerComposingNotAllowed (BuildContext context) {
15521596 final store = PerAccountStoreWidget .of (context);
@@ -1576,11 +1620,62 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
15761620 return null ;
15771621 }
15781622
1623+ /// A [_WarningBanner] that goes at the top of the compose box.
1624+ Widget ? _warningBanner (BuildContext context) {
1625+ if (_isWarningBannerDismissed) return null ;
1626+
1627+ final store = PerAccountStoreWidget .of (context);
1628+ final zulipLocalizations = ZulipLocalizations .of (context);
1629+
1630+ if (store.connection.zulipFeatureLevel! < 348 ||
1631+ ! store.realmEnableGuestUserDmWarning) {
1632+ return null ;
1633+ }
1634+
1635+ switch (widget.narrow) {
1636+ case DmNarrow (: final otherRecipientIds):
1637+ final guestUsers = otherRecipientIds
1638+ .map ((id) => store.getUser (id))
1639+ .where ((user) => user? .role == UserRole .guest)
1640+ .toList ();
1641+
1642+ if (guestUsers.isEmpty) return null ;
1643+
1644+ final guestNames = guestUsers
1645+ .map ((user) => user != null
1646+ ? store.userDisplayName (user.userId)
1647+ : zulipLocalizations.unknownUserName)
1648+ .toList ();
1649+
1650+ final String formattedNames;
1651+ if (guestUsers.length == 1 ) {
1652+ formattedNames = guestNames[0 ];
1653+ } else {
1654+ final allButLast =
1655+ guestNames.sublist (0 , guestNames.length - 1 ).join (', ' );
1656+ formattedNames =
1657+ "$allButLast ${guestUsers .length > 2 ? ',' : '' } and ${guestNames .last }" ;
1658+ }
1659+
1660+ final bannerText = guestUsers.length == 1
1661+ ? zulipLocalizations.guestUserDmWarningOne (guestNames.first)
1662+ : zulipLocalizations.guestUserDmWarningMany (formattedNames);
1663+
1664+ return _WarningBanner (label: bannerText,
1665+ onDismiss: _dismissWarningBanner);
1666+
1667+ default :
1668+ return null ;
1669+ }
1670+ }
1671+
15791672 @override
15801673 Widget build (BuildContext context) {
15811674 final Widget ? body;
15821675
15831676 final errorBanner = _errorBannerComposingNotAllowed (context);
1677+ final warningBanner = _warningBanner (context);
1678+
15841679 if (errorBanner != null ) {
15851680 return _ComposeBoxContainer (body: null , banner: errorBanner);
15861681 }
@@ -1603,6 +1698,6 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
16031698 // errorBanner = _ErrorBanner(label:
16041699 // ZulipLocalizations.of(context).errorSendMessageTimeout);
16051700 // }
1606- return _ComposeBoxContainer (body: body, banner: null );
1701+ return _ComposeBoxContainer (body: body, banner: warningBanner );
16071702 }
16081703}
0 commit comments