@@ -1724,34 +1724,45 @@ class EditMessageComposeBoxController extends ComposeBoxController {
1724
1724
/// A banner to display over or instead of interactive compose-box content.
1725
1725
///
1726
1726
/// 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
+ });
1731
1734
1732
- String getLabel (ZulipLocalizations zulipLocalizations);
1735
+ final _BannerIntent intent;
1736
+ final String label;
1733
1737
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
1735
1741
/// for spacing/positioning.
1736
1742
///
1737
1743
/// An interactive element's touchable area should have height at least 44px,
1738
1744
/// with some of that as "slop" vertical outer padding above and below
1739
1745
/// what gets painted:
1740
1746
/// https://github.com/zulip/zulip-flutter/pull/1432#discussion_r2023907300
1741
1747
///
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;
1744
1754
1745
1755
/// Whether to apply `end: 8` in [SafeArea.minimum] .
1746
1756
///
1747
- /// Subclasses can use `false` when the [buildTrailing ] element
1757
+ /// Pass `false` when the [trailing ] element
1748
1758
/// is meant to abut the edge of the screen
1749
1759
/// 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;
1751
1763
1752
1764
@override
1753
1765
Widget build (BuildContext context) {
1754
- final zulipLocalizations = ZulipLocalizations .of (context);
1755
1766
final designVariables = DesignVariables .of (context);
1756
1767
1757
1768
final (labelColor, backgroundColor) = switch (intent) {
@@ -1767,7 +1778,6 @@ abstract class _Banner extends StatelessWidget {
1767
1778
color: labelColor,
1768
1779
).merge (weightVariableTextStyle (context, wght: 600 ));
1769
1780
1770
- final trailing = buildTrailing (PageRoot .contextOf (context));
1771
1781
return DecoratedBox (
1772
1782
decoration: BoxDecoration (color: backgroundColor),
1773
1783
child: SafeArea (
@@ -1784,10 +1794,10 @@ abstract class _Banner extends StatelessWidget {
1784
1794
child: Text (
1785
1795
style: labelTextStyle,
1786
1796
textScaler: MediaQuery .textScalerOf (context).clamp (maxScaleFactor: 1.5 ),
1787
- getLabel (zulipLocalizations) ))),
1797
+ label ))),
1788
1798
if (trailing != null ) ...[
1789
1799
const SizedBox (width: 8 ),
1790
- trailing,
1800
+ trailing! ,
1791
1801
],
1792
1802
]))));
1793
1803
}
@@ -1798,41 +1808,11 @@ enum _BannerIntent {
1798
1808
danger,
1799
1809
}
1800
1810
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});
1826
1813
1827
1814
final ComposeBoxState composeBoxState;
1828
1815
1829
- @override
1830
- String getLabel (ZulipLocalizations zulipLocalizations) =>
1831
- zulipLocalizations.composeBoxBannerLabelEditMessage;
1832
-
1833
- @override
1834
- _BannerIntent get intent => _BannerIntent .info;
1835
-
1836
1816
void _handleTapSave (BuildContext context) async {
1837
1817
// (A BuildContext that's expected to remain mounted until the whole page
1838
1818
// disappears, which may be long after the banner disappears.)
@@ -1884,7 +1864,7 @@ class _EditMessageBanner extends _Banner {
1884
1864
}
1885
1865
1886
1866
@override
1887
- Widget buildTrailing ( context) {
1867
+ Widget build ( BuildContext context) {
1888
1868
final zulipLocalizations = ZulipLocalizations .of (context);
1889
1869
return Row (mainAxisSize: MainAxisSize .min, spacing: 8 , children: [
1890
1870
ZulipWebUiKitButton (label: zulipLocalizations.composeBoxBannerButtonCancel,
@@ -2148,25 +2128,28 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
2148
2128
super .dispose ();
2149
2129
}
2150
2130
2151
- /// An [_ErrorBanner ] that replaces the compose box's text inputs.
2131
+ /// A [_Banner ] that replaces the compose box's text inputs.
2152
2132
Widget ? _errorBannerComposingNotAllowed (BuildContext context) {
2153
2133
final store = PerAccountStoreWidget .of (context);
2134
+ final zulipLocalizations = ZulipLocalizations .of (context);
2154
2135
switch (widget.narrow) {
2155
2136
case ChannelNarrow (: final streamId):
2156
2137
case TopicNarrow (: final streamId):
2157
2138
final channel = store.streams[streamId];
2158
2139
if (channel == null || ! store.selfCanSendMessage (inChannel: channel,
2159
2140
byDate: DateTime .now ())) {
2160
- return _ErrorBanner (getLabel: (zulipLocalizations) =>
2161
- zulipLocalizations.errorBannerCannotPostInChannelLabel);
2141
+ return _Banner (
2142
+ intent: _BannerIntent .danger,
2143
+ label: zulipLocalizations.errorBannerCannotPostInChannelLabel);
2162
2144
}
2163
2145
2164
2146
case DmNarrow (: final otherRecipientIds):
2165
2147
final hasDeactivatedUser = otherRecipientIds.any ((id) =>
2166
2148
! (store.getUser (id)? .isActive ?? true ));
2167
2149
if (hasDeactivatedUser) {
2168
- return _ErrorBanner (getLabel: (zulipLocalizations) =>
2169
- zulipLocalizations.errorBannerDeactivatedDmLabel);
2150
+ return _Banner (
2151
+ intent: _BannerIntent .danger,
2152
+ label: zulipLocalizations.errorBannerDeactivatedDmLabel);
2170
2153
}
2171
2154
2172
2155
case CombinedFeedNarrow ():
@@ -2180,6 +2163,8 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
2180
2163
2181
2164
@override
2182
2165
Widget build (BuildContext context) {
2166
+ final zulipLocalizations = ZulipLocalizations .of (context);
2167
+
2183
2168
final errorBanner = _errorBannerComposingNotAllowed (context);
2184
2169
if (errorBanner != null ) {
2185
2170
return ComposeBoxInheritedWidget .fromComposeBoxState (this ,
@@ -2202,7 +2187,10 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
2202
2187
}
2203
2188
case EditMessageComposeBoxController (): {
2204
2189
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 ));
2206
2194
}
2207
2195
}
2208
2196
0 commit comments