refactor(ui): remove context from Commands and Mentions overlays

This commit is contained in:
Salvatore Giordano
2021-09-10 10:52:59 +02:00
parent 19472027cc
commit 377789c421
5 changed files with 61 additions and 49 deletions
@@ -110,12 +110,10 @@ class _OverlayBuilderState extends State<OverlayBuilder> {
} }
void addToOverlay(OverlayEntry entry) async { void addToOverlay(OverlayEntry entry) async {
print('addToOverlay');
Overlay.of(context)?.insert(entry); Overlay.of(context)?.insert(entry);
} }
void hideOverlay() { void hideOverlay() {
print('hideOverlay');
overlayEntry?.remove(); overlayEntry?.remove();
overlayEntry = null; overlayEntry = null;
} }
@@ -1,33 +1,34 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// Overlay for displaying commands that can be used /// Overlay for displaying commands that can be used
class CommandsOverlay extends StatelessWidget { class CommandsOverlay extends StatelessWidget {
/// Constructor for creating a [CommandsOverlay] /// Constructor for creating a [CommandsOverlay]
const CommandsOverlay( const CommandsOverlay({
this.context, {
required this.text, required this.text,
required this.onCommandResult, required this.onCommandResult,
required this.size,
required this.channel,
Key? key, Key? key,
}) : super(key: key); }) : super(key: key);
/// Context of the upper tree /// The size of the overlay
final BuildContext context; final Size size;
/// Query for searching commands /// Query for searching commands
final String text; final String text;
/// The channel to search for users
final Channel channel;
/// Callback called when a command is selected /// Callback called when a command is selected
final ValueChanged<Command> onCommandResult; final ValueChanged<Command> onCommandResult;
@override @override
Widget build(BuildContext otherContext) { Widget build(BuildContext context) {
final _streamChatTheme = StreamChatTheme.of(context); final _streamChatTheme = StreamChatTheme.of(context);
final commands = StreamChannel.of(context) final commands = channel.config?.commands
.channel
.config
?.commands
.where((c) => c.name.contains(text.replaceFirst('/', ''))) .where((c) => c.name.contains(text.replaceFirst('/', '')))
.toList() ?? .toList() ??
[]; [];
@@ -36,8 +37,6 @@ class CommandsOverlay extends StatelessWidget {
return const SizedBox(); return const SizedBox();
} }
final size = MediaQuery.of(context).size;
return Padding( return Padding(
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(4),
child: Card( child: Card(
@@ -48,7 +47,7 @@ class CommandsOverlay extends StatelessWidget {
color: _streamChatTheme.colorTheme.barsBg, color: _streamChatTheme.colorTheme.barsBg,
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
child: Container( child: Container(
constraints: BoxConstraints.loose(Size(size.width - 16, 400)), constraints: BoxConstraints.loose(size),
decoration: BoxDecoration( decoration: BoxDecoration(
color: _streamChatTheme.colorTheme.barsBg, color: _streamChatTheme.colorTheme.barsBg,
borderRadius: BorderRadius.circular(8)), borderRadius: BorderRadius.circular(8)),
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_flutter/src/emoji/emoji.dart'; import 'package:stream_chat_flutter/src/emoji/emoji.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:substring_highlight/substring_highlight.dart'; import 'package:substring_highlight/substring_highlight.dart';
/// Overlay for displaying emoji that can be used /// Overlay for displaying emoji that can be used
@@ -4,20 +4,24 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// Overlay for displaying users that can be mentioned /// Overlay for displaying users that can be mentioned
class MentionsOverlay extends StatelessWidget { class MentionsOverlay extends StatelessWidget {
/// Constructor for creating a [MentionsOverlay] /// Constructor for creating a [MentionsOverlay]
const MentionsOverlay( const MentionsOverlay({
this.context, {
required this.query, required this.query,
required this.onMentionResult, required this.onMentionResult,
required this.size,
required this.channel,
this.mentionsTileBuilder, this.mentionsTileBuilder,
Key? key, Key? key,
}) : super(key: key); }) : super(key: key);
/// Context of the upper tree /// The size of the overlay
final BuildContext context; final Size size;
/// Query for searching users /// Query for searching users
final String query; final String query;
/// The channel to search for users
final Channel channel;
/// Callback called when a user is selected /// Callback called when a user is selected
final ValueChanged<User?> onMentionResult; final ValueChanged<User?> onMentionResult;
@@ -25,19 +29,18 @@ class MentionsOverlay extends StatelessWidget {
final MentionTileBuilder? mentionsTileBuilder; final MentionTileBuilder? mentionsTileBuilder;
@override @override
Widget build(BuildContext otherContext) { Widget build(BuildContext context) {
final _streamChatTheme = StreamChatTheme.of(context); final _streamChatTheme = StreamChatTheme.of(context);
Future<List<Member>>? queryMembers; Future<List<Member>>? queryMembers;
final channelState = StreamChannel.of(context);
if (query.isNotEmpty) { if (query.isNotEmpty) {
queryMembers = channelState.channel queryMembers = channel
.queryMembers(filter: Filter.autoComplete('name', query)) .queryMembers(filter: Filter.autoComplete('name', query))
.then((res) => res.members); .then((res) => res.members);
} }
final members = channelState.channel.state?.members final members = channel.state?.members
.where((m) => m.user?.name.toLowerCase().contains(query) == true) .where((m) => m.user?.name.toLowerCase().contains(query) == true)
.toList() ?? .toList() ??
[]; [];
@@ -46,9 +49,6 @@ class MentionsOverlay extends StatelessWidget {
return const SizedBox(); return const SizedBox();
} }
// ignore: cast_nullable_to_non_nullable
final renderBox = context.findRenderObject() as RenderBox;
final size = renderBox.size;
final child = Card( final child = Card(
margin: const EdgeInsets.all(8), margin: const EdgeInsets.all(8),
elevation: 2, elevation: 2,
@@ -58,7 +58,7 @@ class MentionsOverlay extends StatelessWidget {
), ),
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
child: Container( child: Container(
constraints: BoxConstraints.loose(Size(size.width - 16, 200)), constraints: BoxConstraints.loose(size),
decoration: BoxDecoration( decoration: BoxDecoration(
color: _streamChatTheme.colorTheme.barsBg, color: _streamChatTheme.colorTheme.barsBg,
), ),
@@ -14,7 +14,7 @@ import 'package:shimmer/shimmer.dart';
import 'package:stream_chat_flutter/src/commands_overlay.dart'; import 'package:stream_chat_flutter/src/commands_overlay.dart';
import 'package:stream_chat_flutter/src/emoji_overlay.dart'; import 'package:stream_chat_flutter/src/emoji_overlay.dart';
import 'package:stream_chat_flutter/src/mentions_overlay.dart'; import 'package:stream_chat_flutter/src/mentions_overlay.dart';
import 'package:stream_chat_flutter/src/overlays.dart'; import 'package:stream_chat_flutter/src/anchored_overlay.dart';
import 'package:stream_chat_flutter/src/emoji/emoji.dart'; import 'package:stream_chat_flutter/src/emoji/emoji.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/src/media_list_view.dart'; import 'package:stream_chat_flutter/src/media_list_view.dart';
@@ -923,7 +923,14 @@ class MessageInputState extends State<MessageInput> {
Widget _buildCommandsOverlayEntry() { Widget _buildCommandsOverlayEntry() {
final text = textEditingController.text.trimLeft(); final text = textEditingController.text.trimLeft();
return CommandsOverlay(context, text: text, onCommandResult: _setCommand); // ignore: cast_nullable_to_non_nullable
final renderObject = context.findRenderObject() as RenderBox;
return CommandsOverlay(
channel: StreamChannel.of(context).channel,
size: Size(renderObject.size.width - 16, 400),
text: text,
onCommandResult: _setCommand,
);
} }
Widget _buildFilePickerSection() { Widget _buildFilePickerSection() {
@@ -1141,27 +1148,35 @@ class MessageInputState extends State<MessageInput> {
.split('@'); .split('@');
final query = splits.last.toLowerCase(); final query = splits.last.toLowerCase();
return MentionsOverlay(context, query: query, onMentionResult: (user) { // ignore: cast_nullable_to_non_nullable
if (user != null) { final renderObject = context.findRenderObject() as RenderBox;
_mentionedUsers.add(user);
}
splits[splits.length - 1] = user!.name; return MentionsOverlay(
final rejoin = splits.join('@'); channel: StreamChannel.of(context).channel,
size: Size(renderObject.size.width - 16, 400),
query: query,
onMentionResult: (user) {
if (user != null) {
_mentionedUsers.add(user);
}
textEditingController.value = TextEditingValue( splits[splits.length - 1] = user!.name;
text: rejoin + final rejoin = splits.join('@');
textEditingController.text
.substring(textEditingController.selection.start), textEditingController.value = TextEditingValue(
selection: TextSelection.collapsed( text: rejoin +
offset: rejoin.length, textEditingController.text
), .substring(textEditingController.selection.start),
); selection: TextSelection.collapsed(
_debounce!.cancel(); offset: rejoin.length,
setState(() { ),
_mentionsOverlay = null; );
}); _debounce!.cancel();
}); setState(() {
_mentionsOverlay = null;
});
},
);
} }
Widget _buildEmojiOverlay() { Widget _buildEmojiOverlay() {