@@ -17,6 +17,7 @@ import 'autocomplete.dart';
17
17
import 'color.dart' ;
18
18
import 'dialog.dart' ;
19
19
import 'icons.dart' ;
20
+ import 'inset_shadow.dart' ;
20
21
import 'store.dart' ;
21
22
import 'text.dart' ;
22
23
import 'theme.dart' ;
@@ -287,30 +288,62 @@ class _ContentInput extends StatelessWidget {
287
288
288
289
@override
289
290
Widget build (BuildContext context) {
290
- ColorScheme colorScheme = Theme .of (context).colorScheme;
291
-
292
- return InputDecorator (
293
- decoration: const InputDecoration (),
294
- child: ConstrainedBox (
295
- constraints: const BoxConstraints (
296
- // TODO constrain this adaptively (i.e. not hard-coded 200)
297
- maxHeight: 200 ,
298
- ),
299
- child: ComposeAutocomplete (
300
- narrow: narrow,
301
- controller: controller,
302
- focusNode: focusNode,
303
- fieldViewBuilder: (context) {
304
- return TextField (
291
+ const verticalPadding = 8.0 ;
292
+ const contentLineHeight = 22.0 ;
293
+ final textScaler = MediaQuery .textScalerOf (context).clamp (maxScaleFactor: 1.5 );
294
+
295
+ final designVariables = DesignVariables .of (context);
296
+
297
+ return ComposeAutocomplete (
298
+ narrow: narrow,
299
+ controller: controller,
300
+ focusNode: focusNode,
301
+ fieldViewBuilder: (context) => ConstrainedBox (
302
+ constraints: BoxConstraints (
303
+ // Reserve space to fully show the first 7th lines and just partially
304
+ // clip the 8th line, where the height matches the spec at
305
+ // https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=3960-5147&node-type=text&m=dev
306
+ // > Maximum size of the compose box is suggested to be 178px. Which
307
+ // > has 7 fully visible lines of text
308
+ //
309
+ // The partial line hints that the content input is scrollable.
310
+ maxHeight: verticalPadding + textScaler.scale (
311
+ contentLineHeight * 7 + contentLineHeight * 0.727 )),
312
+ child: ClipRect (
313
+ child: InsetShadowBox (
314
+ top: verticalPadding, bottom: verticalPadding,
315
+ color: designVariables.composeBoxBg,
316
+ child: TextField (
305
317
controller: controller,
306
318
focusNode: focusNode,
307
- style: TextStyle (color: colorScheme.onSurface),
308
- decoration: InputDecoration .collapsed (hintText: hintText),
319
+ // Let the content show through the `contentPadding` so that
320
+ // our [InsetShadowBox] can fade it smoothly there.
321
+ clipBehavior: Clip .none,
322
+ style: TextStyle (
323
+ fontSize: 17 ,
324
+ height: (contentLineHeight / 17 ),
325
+ color: designVariables.textInput),
326
+ // From the spec at
327
+ // https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=3960-5147&node-type=text&m=dev
328
+ // > Compose box has the height to fit 2 lines. This is [done] to
329
+ // > have a bigger hit area for the user to start the input. […]
330
+ minLines: 2 ,
309
331
maxLines: null ,
310
332
textCapitalization: TextCapitalization .sentences,
311
- );
312
- }),
313
- ));
333
+ decoration: InputDecoration (
334
+ // This padding ensures that the user can always scroll long
335
+ // content entirely out of the top or bottom shadow if desired.
336
+ // With this and the `minLines: 2` above, an empty content input
337
+ // gets 60px vertical distance between the top of the top shadow
338
+ // and the bottom of the bottom shadow (with no text-size
339
+ // scaling). That's a bit more than the 54px given in the Figma,
340
+ // and we can revisit if needed, but it's tricky to get that
341
+ // 54px distance while also making the scrolling work like this
342
+ // and offering two lines of touchable area.
343
+ contentPadding: const EdgeInsets .symmetric (vertical: verticalPadding),
344
+ hintText: hintText,
345
+ hintStyle: TextStyle (
346
+ color: designVariables.textInput.withValues (alpha: 0.5 ))))))));
314
347
}
315
348
}
316
349
0 commit comments