@@ -1724,34 +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- Widget ? buildTrailing (BuildContext context);
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;
17441754
17451755 /// Whether to apply `end: 8` in [SafeArea.minimum] .
17461756 ///
1747- /// Subclasses can use `false` when the [buildTrailing ] element
1757+ /// Pass `false` when the [trailing ] element
17481758 /// is meant to abut the edge of the screen
17491759 /// in the common case that there are no horizontal device insets.
1750- bool get padEnd => true ;
1760+ ///
1761+ /// Defaults to `true` .
1762+ final bool padEnd;
17511763
17521764 @override
17531765 Widget build (BuildContext context) {
1754- final zulipLocalizations = ZulipLocalizations .of (context);
17551766 final designVariables = DesignVariables .of (context);
17561767
17571768 final (labelColor, backgroundColor) = switch (intent) {
@@ -1767,7 +1778,6 @@ abstract class _Banner extends StatelessWidget {
17671778 color: labelColor,
17681779 ).merge (weightVariableTextStyle (context, wght: 600 ));
17691780
1770- final trailing = buildTrailing (PageRoot .contextOf (context));
17711781 return DecoratedBox (
17721782 decoration: BoxDecoration (color: backgroundColor),
17731783 child: SafeArea (
@@ -1784,10 +1794,10 @@ abstract class _Banner extends StatelessWidget {
17841794 child: Text (
17851795 style: labelTextStyle,
17861796 textScaler: MediaQuery .textScalerOf (context).clamp (maxScaleFactor: 1.5 ),
1787- getLabel (zulipLocalizations) ))),
1797+ label ))),
17881798 if (trailing != null ) ...[
17891799 const SizedBox (width: 8 ),
1790- trailing,
1800+ trailing! ,
17911801 ],
17921802 ]))));
17931803 }
@@ -1798,41 +1808,11 @@ enum _BannerIntent {
17981808 danger,
17991809}
18001810
1801- class _ErrorBanner extends _Banner {
1802- const _ErrorBanner ({
1803- required String Function (ZulipLocalizations ) getLabel,
1804- }) : _getLabel = getLabel;
1805-
1806- @override
1807- String getLabel (ZulipLocalizations zulipLocalizations) =>
1808- _getLabel (zulipLocalizations);
1809- final String Function (ZulipLocalizations ) _getLabel;
1810-
1811- @override
1812- _BannerIntent get intent => _BannerIntent .danger;
1813-
1814- @override
1815- Widget ? buildTrailing (context) {
1816- // An "x" button can go here.
1817- // 24px square with 8px touchable padding in all directions?
1818- // and `bool get padEnd => false`; see Figma:
1819- // https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=4031-17029&m=dev
1820- return null ;
1821- }
1822- }
1823-
1824- class _EditMessageBanner extends _Banner {
1825- const _EditMessageBanner ({required this .composeBoxState});
1811+ class _EditMessageBannerTrailing extends StatelessWidget {
1812+ const _EditMessageBannerTrailing ({required this .composeBoxState});
18261813
18271814 final ComposeBoxState composeBoxState;
18281815
1829- @override
1830- String getLabel (ZulipLocalizations zulipLocalizations) =>
1831- zulipLocalizations.composeBoxBannerLabelEditMessage;
1832-
1833- @override
1834- _BannerIntent get intent => _BannerIntent .info;
1835-
18361816 void _handleTapSave (BuildContext context) async {
18371817 // (A BuildContext that's expected to remain mounted until the whole page
18381818 // disappears, which may be long after the banner disappears.)
@@ -1884,7 +1864,7 @@ class _EditMessageBanner extends _Banner {
18841864 }
18851865
18861866 @override
1887- Widget buildTrailing ( context) {
1867+ Widget build ( BuildContext context) {
18881868 final zulipLocalizations = ZulipLocalizations .of (context);
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