Skip to content

Commit c8f40f4

Browse files
committed
compose_box: Cast inset shadow for scrollable contents.
This also supports horizontal scrolling, to later add shadow when we have more compose box icons. Fixex: zulip#915 Signed-off-by: Zixuan James Li <[email protected]>
1 parent 0e99b76 commit c8f40f4

File tree

1 file changed

+53
-24
lines changed

1 file changed

+53
-24
lines changed

lib/widgets/compose_box.dart

+53-24
Original file line numberDiff line numberDiff line change
@@ -302,32 +302,61 @@ class _ContentInput extends StatelessWidget {
302302
// The bottom padding is not added because it is not supposed to extend
303303
// the compose box.
304304
maxHeight: verticalPadding + contentLineHeight * 7 + contentLineHeight * 0.727),
305-
child: ClipRect(
306-
child: ComposeAutocomplete(
307-
narrow: narrow,
308-
controller: controller,
309-
focusNode: focusNode,
310-
fieldViewBuilder: (context) => TextField(
305+
child: ClipRect(
306+
child: ComposeAutocomplete(
307+
narrow: narrow,
311308
controller: controller,
312309
focusNode: focusNode,
313-
// `contentPadding` causes the text to be clipped while leaving
314-
// a gap to the top border, because it shrinks the size of the
315-
// body of `TextField`. Overriding this gives us full control
316-
// over the clipping behavior with the `ConstrainedBox`.
317-
clipBehavior: Clip.none,
318-
maxLines: null,
319-
textCapitalization: TextCapitalization.sentences,
320-
style: TextStyle(
321-
fontSize: 17,
322-
height: (contentLineHeight / 17),
323-
color: designVariables.textInput),
324-
decoration: InputDecoration(
325-
isDense: true,
326-
border: InputBorder.none,
327-
contentPadding: const EdgeInsets.symmetric(vertical: verticalPadding),
328-
hintText: hintText,
329-
hintStyle: TextStyle(
330-
color: designVariables.textInput.withValues(alpha: 0.5)))))));
310+
fieldViewBuilder: (context) => _ShadowBox(
311+
color: designVariables.bgComposeBox,
312+
child: TextField(
313+
controller: controller,
314+
focusNode: focusNode,
315+
// `contentPadding` causes the text to be clipped while leaving
316+
// a gap to the top border, because it shrinks the size of the
317+
// body of `TextField`. Overriding this gives us full control
318+
// over the clipping behavior with the `ConstrainedBox`.
319+
clipBehavior: Clip.none,
320+
maxLines: null,
321+
textCapitalization: TextCapitalization.sentences,
322+
style: TextStyle(
323+
fontSize: 17,
324+
height: (contentLineHeight / 17),
325+
color: designVariables.textInput),
326+
decoration: InputDecoration(
327+
isDense: true,
328+
border: InputBorder.none,
329+
contentPadding: const EdgeInsets.symmetric(vertical: verticalPadding),
330+
hintText: hintText,
331+
hintStyle: TextStyle(
332+
color: designVariables.textInput.withValues(alpha: 0.5))))))));
333+
}
334+
}
335+
336+
/// A widget that overlays inset shadows on a child.
337+
class _ShadowBox extends StatelessWidget {
338+
const _ShadowBox({required this.color, required this.child});
339+
340+
/// The shadow color to fade into transparency from the top and bottom borders.
341+
final Color color;
342+
final Widget child;
343+
344+
BoxDecoration _shadowFrom(AlignmentGeometry begin) {
345+
return BoxDecoration(gradient: LinearGradient(
346+
begin: begin, end: -begin,
347+
colors: [color, color.withValues(alpha: 0)]));
348+
}
349+
350+
@override
351+
Widget build(BuildContext context) {
352+
return Stack(
353+
children: [
354+
child,
355+
Positioned(top: 0, left: 0, right: 0,
356+
child: Container(height: 8, decoration: _shadowFrom(Alignment.topCenter))),
357+
Positioned(bottom: 0, left: 0, right: 0,
358+
child: Container(height: 8, decoration: _shadowFrom(Alignment.bottomCenter))),
359+
]);
331360
}
332361
}
333362

0 commit comments

Comments
 (0)