Skip to content

Commit c17497f

Browse files
committed
wip: Add inset shadow.
Simplify code. Add tests. Signed-off-by: Zixuan James Li <zixuan@zulip.com>
1 parent fe6d8a7 commit c17497f

File tree

1 file changed

+79
-20
lines changed

1 file changed

+79
-20
lines changed

lib/widgets/compose_box.dart

Lines changed: 79 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -299,29 +299,88 @@ class _ContentInput extends StatelessWidget {
299299
narrow: narrow,
300300
controller: controller,
301301
focusNode: focusNode,
302-
fieldViewBuilder: (context) => SingleChildScrollView(
303-
// While the [TextField] is scrollable, we need to wrap it with
304-
// [SingleChildScrollView] to insert a fixed-height padding that can
305-
// be scrolled along with the text.
306-
child: Padding(
307-
padding: const EdgeInsets.only(top: topPadding, left: 16, right: 16),
308-
child: TextField(
309-
controller: controller,
310-
focusNode: focusNode,
311-
decoration: InputDecoration.collapsed(
312-
border: InputBorder.none,
313-
hintText: hintText,
314-
hintStyle: TextStyle(color: designVariables.textInput.withOpacity(0.5))),
315-
minLines: 2,
316-
maxLines: null,
317-
textCapitalization: TextCapitalization.sentences,
318-
style: TextStyle(
319-
fontSize: 17,
320-
height: (contentLineHeight / 17),
321-
color: designVariables.textInput))))));
302+
fieldViewBuilder: (context) => _ShadowBox(
303+
color: designVariables.bgComposeBox,
304+
child: SingleChildScrollView(
305+
// While the [TextField] is scrollable, we need to wrap it with
306+
// [SingleChildScrollView] to insert a fixed-height padding that can
307+
// be scrolled along with the text.
308+
child: Padding(
309+
padding: const EdgeInsets.only(top: topPadding, left: 16, right: 16),
310+
child: TextField(
311+
controller: controller,
312+
focusNode: focusNode,
313+
decoration: InputDecoration.collapsed(
314+
border: InputBorder.none,
315+
hintText: hintText,
316+
hintStyle: TextStyle(color: designVariables.textInput.withOpacity(0.5))),
317+
minLines: 2,
318+
maxLines: null,
319+
textCapitalization: TextCapitalization.sentences,
320+
style: TextStyle(
321+
fontSize: 17,
322+
height: (contentLineHeight / 17),
323+
color: designVariables.textInput)))))));
322324
}
323325
}
324326

327+
/// Overlay inset shadows on the child from all scrollable directions.
328+
class _ShadowBox extends StatefulWidget {
329+
const _ShadowBox({required this.color, required this.child});
330+
331+
final Color color;
332+
final Widget child;
333+
334+
@override
335+
State<_ShadowBox> createState() => _ShadowBoxState();
336+
}
337+
338+
class _ShadowBoxState extends State<_ShadowBox> {
339+
bool showTopShadow = false; bool showBottomShadow = false;
340+
bool showLeftShadow = false; bool showRightShadow = false;
341+
342+
bool handleScroll(ScrollNotification notification) {
343+
final metrics = notification.metrics;
344+
setState(() {
345+
switch (metrics.axisDirection) {
346+
case AxisDirection.up:
347+
case AxisDirection.down:
348+
showTopShadow = metrics.extentBefore != 0;
349+
showBottomShadow = metrics.extentAfter != 0;
350+
case AxisDirection.right:
351+
case AxisDirection.left:
352+
showLeftShadow = metrics.extentBefore != 0;
353+
showRightShadow = metrics.extentAfter != 0;
354+
}
355+
});
356+
return false;
357+
}
358+
359+
@override
360+
Widget build(BuildContext context) {
361+
BoxDecoration shadowFrom(AlignmentGeometry begin) =>
362+
BoxDecoration(gradient: LinearGradient(begin: begin, end: -begin,
363+
colors: [widget.color, widget.color.withOpacity(0)]));
364+
365+
return NotificationListener<ScrollNotification>(
366+
onNotification: handleScroll,
367+
child: Stack(
368+
children: [
369+
widget.child,
370+
if (showTopShadow) Positioned(top: 0, left: 0, right: 0,
371+
child: Container(height: 8, decoration: shadowFrom(Alignment.topCenter))),
372+
if (showBottomShadow) Positioned(bottom: 0, left: 0, right: 0,
373+
child: Container(height: 8, decoration: shadowFrom(Alignment.bottomCenter))),
374+
if (showLeftShadow) Positioned(left: 0, top: 0, bottom: 0,
375+
child: Container(width: 8, decoration: shadowFrom(Alignment.centerLeft))),
376+
if (showRightShadow) Positioned(right: 0, top: 0, bottom: 0,
377+
child: Container(width: 8, decoration: shadowFrom(Alignment.centerRight))),
378+
],
379+
));
380+
}
381+
}
382+
383+
325384
/// The content input for _StreamComposeBox.
326385
class _StreamContentInput extends StatefulWidget {
327386
const _StreamContentInput({

0 commit comments

Comments
 (0)