Merge pull request #821 from GetStream/chore/message-input-controller-review

chore(ui, core): docs and linting improvements
This commit is contained in:
Salvatore Giordano
2021-12-13 11:44:47 +01:00
committed by GitHub
6 changed files with 129 additions and 142 deletions
@@ -4,7 +4,6 @@ import 'dart:math';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:collection/collection.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
@@ -14,16 +13,12 @@ import 'package:stream_chat_flutter/src/commands_overlay.dart';
import 'package:stream_chat_flutter/src/emoji/emoji.dart';
import 'package:stream_chat_flutter/src/emoji_overlay.dart';
import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/src/message_list_view.dart';
import 'package:stream_chat_flutter/src/multi_overlay.dart';
import 'package:stream_chat_flutter/src/quoted_message_widget.dart';
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
import 'package:stream_chat_flutter/src/user_mentions_overlay.dart';
import 'package:stream_chat_flutter/src/video_service.dart';
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import 'package:video_compress/video_compress.dart';
export 'package:video_compress/video_compress.dart' show VideoQuality;
@@ -42,13 +37,14 @@ typedef ErrorListener = void Function(
///
/// This callback should not throw.
///
/// It exists merely for showing custom error, and should not be used otherwise.
/// It exists merely for showing a custom error, and should not be used
/// otherwise.
typedef AttachmentLimitExceedListener = void Function(
int limit,
String error,
);
/// Builder for attachment thumbnails
/// Builder for attachment thumbnails.
typedef AttachmentThumbnailBuilder = Widget Function(
BuildContext,
Attachment,
@@ -77,8 +73,8 @@ typedef ActionButtonBuilder = Widget Function(
IconButton defaultActionButton,
);
/// Widget builder for widgets that require may required data from the
/// [MessageInputController]
/// Widget builder for widgets that may require data from the
/// [MessageInputController].
typedef MessageRelatedBuilder = Widget Function(
BuildContext context,
MessageInputController messageInputController,
@@ -91,7 +87,7 @@ typedef AttachmentsPickerBuilder = Widget Function(
StreamAttachmentPicker defaultPicker,
);
/// Location for actions on the [MessageInput]
/// Location for actions on the [MessageInput].
enum ActionsLocation {
/// Align to left
left,
@@ -106,7 +102,7 @@ enum ActionsLocation {
rightInside,
}
/// Default attachments for widget
/// Default attachments for widget.
enum DefaultAttachmentTypes {
/// Image Attachment
image,
@@ -118,7 +114,7 @@ enum DefaultAttachmentTypes {
file,
}
/// Available locations for the sendMessage button relative to the textField
/// Available locations for the `sendMessage` button relative to the textField.
enum SendButtonLocation {
/// inside the textField
inside,
@@ -131,17 +127,17 @@ const _kMinMediaPickerSize = 360.0;
const _kDefaultMaxAttachmentSize = 20971520; // 20MB in Bytes
/// Inactive state
/// Inactive state:
///
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/message_input.png)
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/message_input_paint.png)
///
/// Focused state
/// Focused state:
///
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/message_input2.png)
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/message_input2_paint.png)
///
/// Widget used to enter the message and add attachments
/// Widget used to enter a message and add attachments:
///
/// ```dart
/// class ChannelPage extends StatelessWidget {
@@ -176,8 +172,7 @@ const _kDefaultMaxAttachmentSize = 20971520; // 20MB in Bytes
/// as the bottom widget.
///
/// The widget renders the ui based on the first ancestor of
/// type [StreamChatTheme].
/// Modify it to change the widget appearance.
/// type [StreamChatTheme]. Modify it to change the widget appearance.
class MessageInput extends StatefulWidget {
/// Instantiate a new MessageInput
const MessageInput({
@@ -218,61 +213,60 @@ class MessageInput extends StatefulWidget {
this.shouldKeepFocusAfterMessage,
}) : super(key: key);
/// List of options for showing overlays
/// List of options for showing overlays.
final List<OverlayOptions> customOverlays;
/// Video quality to use when compressing the videos
/// Video quality to use when compressing the videos.
final VideoQuality compressedVideoQuality;
/// Frame rate to use when compressing the videos
/// Frame rate to use when compressing the videos.
final int compressedVideoFrameRate;
/// Max attachment size in bytes
/// Defaults to 20 MB
/// do not set it if you're using our default CDN
/// Max attachment size in bytes:
/// - Defaults to 20 MB
/// - Do not set it if you're using our default CDN
final int maxAttachmentSize;
/// Function called after sending the message
/// Function called after sending the message.
final void Function(Message)? onMessageSent;
/// Function called right before sending the message
/// Use this to transform the message
/// Function called right before sending the message.
///
/// Use this to transform the message.
final FutureOr<Message> Function(Message)? preMessageSending;
/// Maximum Height for the TextField to grow before it starts scrolling
/// Maximum Height for the TextField to grow before it starts scrolling.
final double maxHeight;
/// The keyboard type assigned to the TextField
/// The keyboard type assigned to the TextField.
final TextInputType keyboardType;
/// If true the attachments button will not be displayed
/// If true the attachments button will not be displayed.
final bool disableAttachments;
/// Use this property to hide/show the commands button
/// Use this property to hide/show the commands button.
final bool showCommandsButton;
/// Hide send as dm checkbox
/// Hide send as dm checkbox.
final bool hideSendAsDm;
/// The text controller of the TextField
/// The text controller of the TextField.
final MessageInputController? messageInputController;
/// List of action widgets
/// List of action widgets.
final List<Widget> actions;
/// The location of the custom actions
/// The location of the custom actions.
final ActionsLocation actionsLocation;
/// Map that defines a thumbnail builder for an attachment type
/// Map that defines a thumbnail builder for an attachment type.
final Map<String, AttachmentThumbnailBuilder>? attachmentThumbnailBuilders;
/// The focus node associated to the TextField
/// The focus node associated to the TextField.
final FocusNode? focusNode;
///
final Message? quotedMessage;
///
final VoidCallback? onQuotedMessageCleared;
/// The location of the send button
@@ -21,7 +21,6 @@ typedef CustomAttachmentIconBuilder = Widget Function(
bool active,
);
///
class StreamAttachmentPicker extends StatefulWidget {
final bool isOpen;
final double pickerSize;
@@ -32,15 +31,15 @@ class StreamAttachmentPicker extends StatefulWidget {
final ValueChanged<String>? onError;
final FilePickerCallback onFilePicked;
/// Video quality to use when compressing the videos
/// Video quality to use when compressing the videos.
final VideoQuality compressedVideoQuality;
/// Frame rate to use when compressing the videos
/// Frame rate to use when compressing the videos.
final int compressedVideoFrameRate;
/// Max attachment size in bytes
/// Defaults to 20 MB
/// do not set it if you're using our default CDN
/// Max attachment size in bytes:
/// - Defaults to 20 MB
/// - Do not set it if you're using our default CDN
final int maxAttachmentSize;
final List<DefaultAttachmentTypes> allowedAttachmentTypes;
@@ -21,8 +21,8 @@ export 'package:flutter/services.dart'
class StreamMessageTextField extends StatefulWidget {
/// Creates a Material Design text field.
///
/// If [decoration] is non-null (which is the default), the text field requires
/// one of its ancestors to be a [Material] widget.
/// If [decoration] is non-null (which is the default), the text field
/// requires one of its ancestors to be a [Material] widget.
///
/// To remove the decoration entirely (including the extra padding introduced
/// by the decoration to save space for the labels), set the [decoration] to
@@ -115,7 +115,7 @@ class StreamMessageTextField extends StatefulWidget {
this.selectionHeightStyle = ui.BoxHeightStyle.tight,
this.selectionWidthStyle = ui.BoxWidthStyle.tight,
this.keyboardAppearance,
this.scrollPadding = const EdgeInsets.all(20.0),
this.scrollPadding = const EdgeInsets.all(20),
this.dragStartBehavior = DragStartBehavior.start,
this.enableInteractiveSelection = true,
this.selectionControls,
@@ -127,34 +127,24 @@ class StreamMessageTextField extends StatefulWidget {
this.autofillHints,
this.restorationId,
this.enableIMEPersonalizedLearning = true,
}) : assert(textAlign != null),
assert(readOnly != null),
assert(autofocus != null),
assert(obscuringCharacter != null && obscuringCharacter.length == 1),
assert(obscureText != null),
assert(autocorrect != null),
}) : assert(obscuringCharacter.length == 1,
'`obscuringCharacter.length` must be 1'),
smartDashesType = smartDashesType ??
(obscureText ? SmartDashesType.disabled : SmartDashesType.enabled),
smartQuotesType = smartQuotesType ??
(obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled),
assert(enableSuggestions != null),
assert(enableInteractiveSelection != null),
assert(maxLengthEnforced != null),
assert(
maxLengthEnforced || maxLengthEnforcement == null,
'maxLengthEnforced is deprecated, use only maxLengthEnforcement',
),
assert(scrollPadding != null),
assert(dragStartBehavior != null),
assert(selectionHeightStyle != null),
assert(selectionWidthStyle != null),
assert(maxLines == null || maxLines > 0),
assert(minLines == null || minLines > 0),
assert(maxLines == null || maxLines > 0,
'`maxLines` needs to be left as null or bigger than 0'),
assert(minLines == null || minLines > 0,
'`minLines` needs to be left as null or bigger than 0'),
assert(
(maxLines == null) || (minLines == null) || (maxLines >= minLines),
"minLines can't be greater than maxLines",
),
assert(expands != null),
assert(
!expands || (maxLines == null && minLines == null),
'minLines and maxLines must be null when expands is true.',
@@ -164,14 +154,15 @@ class StreamMessageTextField extends StatefulWidget {
assert(maxLength == null ||
maxLength == TextField.noMaxLength ||
maxLength > 0),
// Assert the following instead of setting it directly to avoid surprising the user by silently changing the value they set.
// Assert the following instead of setting it directly to avoid
// surprising the user by silently changing the value they set.
assert(
!identical(textInputAction, TextInputAction.newline) ||
maxLines == 1 ||
!identical(keyboardType, TextInputType.text),
'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.',
'''Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.''',
),
assert(enableIMEPersonalizedLearning != null),
keyboardType = keyboardType ??
(maxLines == 1 ? TextInputType.text : TextInputType.multiline),
toolbarOptions = toolbarOptions ??
@@ -230,7 +221,8 @@ class StreamMessageTextField extends StatefulWidget {
/// cause the focus to change, and will not make the keyboard visible.
///
/// This widget builds an [EditableText] and will ensure that the keyboard is
/// showing when it is tapped by calling [EditableTextState.requestKeyboard()].
/// showing when it is tapped by calling
/// [EditableTextState.requestKeyboard()].
final FocusNode? focusNode;
/// The decoration to show around the text field.
@@ -330,16 +322,20 @@ class StreamMessageTextField extends StatefulWidget {
/// If set, a character counter will be displayed below the
/// field showing how many characters have been entered. If set to a number
/// greater than 0, it will also display the maximum number allowed. If set
/// to [TextField.noMaxLength] then only the current character count is displayed.
/// to [TextField.noMaxLength] then only the current character count is
/// displayed.
///
/// After [maxLength] characters have been input, additional input
/// is ignored, unless [maxLengthEnforcement] is set to
/// [MaxLengthEnforcement.none].
///
/// The text field enforces the length with a [LengthLimitingTextInputFormatter],
/// which is evaluated after the supplied [inputFormatters], if any.
/// The text field enforces the length with a
/// [LengthLimitingTextInputFormatter], which is evaluated after the supplied
/// [inputFormatters], if any.
///
/// This value must be either null, [TextField.noMaxLength], or greater than
/// 0.
///
/// This value must be either null, [TextField.noMaxLength], or greater than 0.
/// If null (the default) then there is no limit to the number of characters
/// that can be entered. If set to [TextField.noMaxLength], then no limit will
/// be enforced, but the number of characters entered will still be displayed.
@@ -446,7 +442,8 @@ class StreamMessageTextField extends StatefulWidget {
///
/// This setting is only honored on iOS devices.
///
/// If unset, defaults to the brightness of [ThemeData.primaryColorBrightness].
/// If unset, defaults to the brightness of
/// [ThemeData.primaryColorBrightness].
final Brightness? keyboardAppearance;
/// {@macro flutter.widgets.editableText.scrollPadding}
@@ -490,14 +487,16 @@ class StreamMessageTextField extends StatefulWidget {
/// widget.
///
/// If [mouseCursor] is a [MaterialStateProperty<MouseCursor>],
/// [MaterialStateProperty.resolve] is used for the following [MaterialState]s:
/// [MaterialStateProperty.resolve] is used for the following
/// [MaterialState]s:
///
/// * [MaterialState.error].
/// * [MaterialState.hovered].
/// * [MaterialState.focused].
/// * [MaterialState.disabled].
///
/// If this property is null, [MaterialStateMouseCursor.textable] will be used.
/// If this property is null, [MaterialStateMouseCursor.textable] will be
/// used.
///
/// The [mouseCursor] is the only property of [TextField] that controls the
/// appearance of the mouse pointer. All other properties related to "cursor"