From 0af7b1a0e61be679bb63875858ce1dd27990c097 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 7 Sep 2021 14:31:48 +0530 Subject: [PATCH] added new overlays and docs --- .../lib/src/message_input.dart | 23 +++- .../stream_chat_flutter/lib/src/overlays.dart | 103 +++++++++++------- 2 files changed, 80 insertions(+), 46 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index cf118b7f..60fe49a1 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -475,7 +475,7 @@ class MessageInputState extends State { _emojiOverlay != null || _mentionsOverlay != null, overlayBuilder: (context, offset) { - late Widget child; + late Widget? child; if (_commandsOverlay != null) { child = _buildCommandsOverlayEntry(); @@ -487,7 +487,7 @@ class MessageInputState extends State { return CenterAbout( position: Offset(offset.dx, offset.dy), - child: child, + child: child ?? const SizedBox(), ); }, child: child, @@ -922,7 +922,7 @@ class MessageInputState extends State { } } - Widget _buildCommandsOverlayEntry() { + Widget? _buildCommandsOverlayEntry() { final text = textEditingController.text.trimLeft(); final commands = StreamChannel.of(context) .channel @@ -931,6 +931,11 @@ class MessageInputState extends State { .where((c) => c.name.contains(text.replaceFirst('/', ''))) .toList() ?? []; + + if (commands.isEmpty) { + return null; + } + final size = MediaQuery.of(context).size; return Padding( @@ -1312,7 +1317,7 @@ class MessageInputState extends State { } } - Widget _buildMentionsOverlayEntry() { + Widget? _buildMentionsOverlayEntry() { final splits = textEditingController.text .substring(0, textEditingController.value.selection.start) .split('@'); @@ -1332,6 +1337,10 @@ class MessageInputState extends State { .toList() ?? []; + if (members.isEmpty) { + return null; + } + // ignore: cast_nullable_to_non_nullable final renderBox = context.findRenderObject() as RenderBox; final size = renderBox.size; @@ -1410,7 +1419,7 @@ class MessageInputState extends State { ); } - Widget _buildEmojiOverlay() { + Widget? _buildEmojiOverlay() { final splits = textEditingController.text .substring(0, textEditingController.value.selection.start) .split(':'); @@ -1421,6 +1430,10 @@ class MessageInputState extends State { .map(Emoji.byName) .where((e) => e != null); + if (emojis.isEmpty) { + return null; + } + // ignore: cast_nullable_to_non_nullable final renderBox = context.findRenderObject() as RenderBox; final size = renderBox.size; diff --git a/packages/stream_chat_flutter/lib/src/overlays.dart b/packages/stream_chat_flutter/lib/src/overlays.dart index 65956cb9..ce6a9a4e 100644 --- a/packages/stream_chat_flutter/lib/src/overlays.dart +++ b/packages/stream_chat_flutter/lib/src/overlays.dart @@ -1,49 +1,66 @@ import 'package:flutter/material.dart'; +/// Class to create an overlay anchored to a child widget class AnchoredOverlay extends StatelessWidget { - final bool showOverlay; - final Widget Function(BuildContext, Offset anchor) overlayBuilder; - final Widget child; - - AnchoredOverlay({ + /// Constructor for creating an [AnchoredOverlay] + const AnchoredOverlay({ + Key? key, this.showOverlay = false, required this.overlayBuilder, required this.child, - }); + }) : super(key: key); + + /// Show or hide overlay + final bool showOverlay; + + /// Builder for creating overlay widget + final Widget Function(BuildContext, Offset anchor) overlayBuilder; + + /// Child to which overlay is anchored + final Widget child; @override - Widget build(BuildContext context) { - return new Container( - child: new LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return new OverlayBuilder( - showOverlay: showOverlay, - overlayBuilder: (BuildContext overlayContext) { - RenderBox box = context.findRenderObject() as RenderBox; - final center = - box.size.center(box.localToGlobal(const Offset(0.0, 0.0))); - return overlayBuilder(overlayContext, center); - }, - child: child, - ); - }), - ); - } + Widget build(BuildContext context) => SizedBox( + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) => + OverlayBuilder( + showOverlay: showOverlay, + overlayBuilder: (BuildContext overlayContext) { + final box = context.findRenderObject() as RenderBox?; + if (box != null) { + final center = box.size + .center(box.localToGlobal(const Offset(0, 0))); + return overlayBuilder(overlayContext, center); + } else { + return const SizedBox(); + } + }, + child: child, + )), + ); } +/// Class for creating a declarative-ish overlay class OverlayBuilder extends StatefulWidget { - final bool showOverlay; - final Widget Function(BuildContext) overlayBuilder; - final Widget child; - - OverlayBuilder({ + /// Constructor for creating an [OverlayBuilder] + const OverlayBuilder({ + Key? key, this.showOverlay = false, required this.overlayBuilder, required this.child, - }); + }) : super(key: key); + + /// Show or hide overlay + final bool showOverlay; + + /// Builder for creating overlay widget + final Widget Function(BuildContext) overlayBuilder; + + /// Child to which overlay is anchored + final Widget child; @override - _OverlayBuilderState createState() => new _OverlayBuilderState(); + _OverlayBuilderState createState() => _OverlayBuilderState(); } class _OverlayBuilderState extends State { @@ -112,31 +129,35 @@ class _OverlayBuilderState extends State { } @override - Widget build(BuildContext context) { - return widget.child; - } + Widget build(BuildContext context) => widget.child; } +/// Class to position Overlay class CenterAbout extends StatelessWidget { - final Offset position; - final Widget child; - - CenterAbout({ + /// Constructor for creating an [CenterAbout] + const CenterAbout({ + Key? key, required this.position, required this.child, - }); + }) : super(key: key); + + /// Position of child + final Offset position; + + /// Child widget to which overlay is attached + final Widget child; @override Widget build(BuildContext context) { - var size = MediaQuery.of(context).size; + final size = MediaQuery.of(context).size; return Positioned( bottom: size.height - position.dy, left: position.dx, child: FractionalTranslation( - translation: const Offset(-0.5, 0.0), + translation: const Offset(-0.5, 0), child: Padding( - padding: const EdgeInsets.only(bottom: 32.0), + padding: const EdgeInsets.only(bottom: 32), child: child, ), ),