@@ -1724,38 +1724,45 @@ class EditMessageComposeBoxController extends ComposeBoxController {
17241724/// A banner to display over or instead of interactive compose-box content.
17251725///
17261726/// Must have a [PageRoot] ancestor.
1727- abstract class _Banner extends StatelessWidget {
1728- const _Banner ();
1729-
1730- _BannerIntent get intent;
1727+ class _Banner extends StatelessWidget {
1728+ const _Banner ({
1729+ required this .intent,
1730+ required this .label,
1731+ this .trailing,
1732+ this .padEnd = true , // ignore: unused_element_parameter
1733+ });
17311734
1732- String getLabel (ZulipLocalizations zulipLocalizations);
1735+ final _BannerIntent intent;
1736+ final String label;
17331737
1734- /// A trailing element, with vertical but not horizontal outer padding
1738+ /// An optional trailing element.
1739+ ///
1740+ /// It should include vertical but not horizontal outer padding
17351741 /// for spacing/positioning.
17361742 ///
17371743 /// An interactive element's touchable area should have height at least 44px,
17381744 /// with some of that as "slop" vertical outer padding above and below
17391745 /// what gets painted:
17401746 /// https://github.com/zulip/zulip-flutter/pull/1432#discussion_r2023907300
17411747 ///
1742- /// To control the element's distance from the end edge, override [padEnd] .
1743- ///
1744- /// The passed [BuildContext] will be the result of [PageRoot.contextOf] ,
1745- /// so it's expected to remain mounted until the whole page disappears,
1746- /// which may be long after the banner disappears.
1747- Widget ? buildTrailing ( BuildContext pageContext) ;
1748+ /// To control the element's distance from the end edge, use [padEnd] .
1749+ // An "x" button could go here.
1750+ // 24px square with 8px touchable padding in all directions?
1751+ // and `padEnd: false`; see Figma:
1752+ // https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=4031-17029&m=dev
1753+ final Widget ? trailing ;
17481754
17491755 /// Whether to apply `end: 8` in [SafeArea.minimum] .
17501756 ///
1751- /// Subclasses can use `false` when the [buildTrailing ] element
1757+ /// Pass `false` when the [trailing ] element
17521758 /// is meant to abut the edge of the screen
17531759 /// in the common case that there are no horizontal device insets.
1754- bool get padEnd => true ;
1760+ ///
1761+ /// Defaults to `true` .
1762+ final bool padEnd;
17551763
17561764 @override
17571765 Widget build (BuildContext context) {
1758- final zulipLocalizations = ZulipLocalizations .of (context);
17591766 final designVariables = DesignVariables .of (context);
17601767
17611768 final (labelColor, backgroundColor) = switch (intent) {
@@ -1771,7 +1778,6 @@ abstract class _Banner extends StatelessWidget {
17711778 color: labelColor,
17721779 ).merge (weightVariableTextStyle (context, wght: 600 ));
17731780
1774- final trailing = buildTrailing (PageRoot .contextOf (context));
17751781 return DecoratedBox (
17761782 decoration: BoxDecoration (color: backgroundColor),
17771783 child: SafeArea (
@@ -1788,10 +1794,10 @@ abstract class _Banner extends StatelessWidget {
17881794 child: Text (
17891795 style: labelTextStyle,
17901796 textScaler: MediaQuery .textScalerOf (context).clamp (maxScaleFactor: 1.5 ),
1791- getLabel (zulipLocalizations) ))),
1797+ label ))),
17921798 if (trailing != null ) ...[
17931799 const SizedBox (width: 8 ),
1794- trailing,
1800+ trailing! ,
17951801 ],
17961802 ]))));
17971803 }
@@ -1802,41 +1808,11 @@ enum _BannerIntent {
18021808 danger,
18031809}
18041810
1805- class _ErrorBanner extends _Banner {
1806- const _ErrorBanner ({
1807- required String Function (ZulipLocalizations ) getLabel,
1808- }) : _getLabel = getLabel;
1809-
1810- @override
1811- String getLabel (ZulipLocalizations zulipLocalizations) =>
1812- _getLabel (zulipLocalizations);
1813- final String Function (ZulipLocalizations ) _getLabel;
1814-
1815- @override
1816- _BannerIntent get intent => _BannerIntent .danger;
1817-
1818- @override
1819- Widget ? buildTrailing (pageContext) {
1820- // An "x" button can go here.
1821- // 24px square with 8px touchable padding in all directions?
1822- // and `bool get padEnd => false`; see Figma:
1823- // https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=4031-17029&m=dev
1824- return null ;
1825- }
1826- }
1827-
1828- class _EditMessageBanner extends _Banner {
1829- const _EditMessageBanner ({required this .composeBoxState});
1811+ class _EditMessageBannerTrailing extends StatelessWidget {
1812+ const _EditMessageBannerTrailing ({required this .composeBoxState});
18301813
18311814 final ComposeBoxState composeBoxState;
18321815
1833- @override
1834- String getLabel (ZulipLocalizations zulipLocalizations) =>
1835- zulipLocalizations.composeBoxBannerLabelEditMessage;
1836-
1837- @override
1838- _BannerIntent get intent => _BannerIntent .info;
1839-
18401816 void _handleTapSave (BuildContext pageContext) async {
18411817 final store = PerAccountStoreWidget .of (pageContext);
18421818 final controller = composeBoxState.controller;
@@ -1884,7 +1860,11 @@ class _EditMessageBanner extends _Banner {
18841860 }
18851861
18861862 @override
1887- Widget buildTrailing (pageContext) {
1863+ Widget build (BuildContext context) {
1864+ // (A BuildContext that's expected to remain mounted until the whole page
1865+ // disappears, which may be long after the banner disappears.)
1866+ final pageContext = PageRoot .contextOf (context);
1867+
18881868 final zulipLocalizations = ZulipLocalizations .of (pageContext);
18891869 return Row (mainAxisSize: MainAxisSize .min, spacing: 8 , children: [
18901870 ZulipWebUiKitButton (label: zulipLocalizations.composeBoxBannerButtonCancel,
@@ -2148,25 +2128,28 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
21482128 super .dispose ();
21492129 }
21502130
2151- /// An [_ErrorBanner ] that replaces the compose box's text inputs.
2131+ /// A [_Banner ] that replaces the compose box's text inputs.
21522132 Widget ? _errorBannerComposingNotAllowed (BuildContext context) {
21532133 final store = PerAccountStoreWidget .of (context);
2134+ final zulipLocalizations = ZulipLocalizations .of (context);
21542135 switch (widget.narrow) {
21552136 case ChannelNarrow (: final streamId):
21562137 case TopicNarrow (: final streamId):
21572138 final channel = store.streams[streamId];
21582139 if (channel == null || ! store.selfCanSendMessage (inChannel: channel,
21592140 byDate: DateTime .now ())) {
2160- return _ErrorBanner (getLabel: (zulipLocalizations) =>
2161- zulipLocalizations.errorBannerCannotPostInChannelLabel);
2141+ return _Banner (
2142+ intent: _BannerIntent .danger,
2143+ label: zulipLocalizations.errorBannerCannotPostInChannelLabel);
21622144 }
21632145
21642146 case DmNarrow (: final otherRecipientIds):
21652147 final hasDeactivatedUser = otherRecipientIds.any ((id) =>
21662148 ! (store.getUser (id)? .isActive ?? true ));
21672149 if (hasDeactivatedUser) {
2168- return _ErrorBanner (getLabel: (zulipLocalizations) =>
2169- zulipLocalizations.errorBannerDeactivatedDmLabel);
2150+ return _Banner (
2151+ intent: _BannerIntent .danger,
2152+ label: zulipLocalizations.errorBannerDeactivatedDmLabel);
21702153 }
21712154
21722155 case CombinedFeedNarrow ():
@@ -2180,6 +2163,8 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
21802163
21812164 @override
21822165 Widget build (BuildContext context) {
2166+ final zulipLocalizations = ZulipLocalizations .of (context);
2167+
21832168 final errorBanner = _errorBannerComposingNotAllowed (context);
21842169 if (errorBanner != null ) {
21852170 return ComposeBoxInheritedWidget .fromComposeBoxState (this ,
@@ -2202,7 +2187,10 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
22022187 }
22032188 case EditMessageComposeBoxController (): {
22042189 body = _EditMessageComposeBoxBody (controller: controller, narrow: narrow);
2205- banner = _EditMessageBanner (composeBoxState: this );
2190+ banner = _Banner (
2191+ intent: _BannerIntent .info,
2192+ label: zulipLocalizations.composeBoxBannerLabelEditMessage,
2193+ trailing: _EditMessageBannerTrailing (composeBoxState: this ));
22062194 }
22072195 }
22082196
0 commit comments