diff --git a/packages/stream_chat/lib/src/client/retry_queue.dart b/packages/stream_chat/lib/src/client/retry_queue.dart index 7c3157b2..ad140ad6 100644 --- a/packages/stream_chat/lib/src/client/retry_queue.dart +++ b/packages/stream_chat/lib/src/client/retry_queue.dart @@ -1,18 +1,13 @@ import 'dart:async'; import 'package:collection/collection.dart'; -import 'package:logging/logging.dart'; import 'package:rxdart/rxdart.dart'; -import 'package:stream_chat/src/client/channel.dart'; import 'package:stream_chat/src/client/retry_policy.dart'; -import 'package:stream_chat/src/core/error/error.dart'; -import 'package:stream_chat/src/core/models/message.dart'; -import 'package:stream_chat/src/event_type.dart'; import 'package:stream_chat/stream_chat.dart'; -/// The retry queue associated to a channel +/// The retry queue associated to a channel. class RetryQueue { - /// Instantiate a new RetryQueue object + /// Instantiate a new RetryQueue object. RetryQueue({ required this.channel, this.logger, @@ -22,13 +17,13 @@ class RetryQueue { _listenFailedEvents(); } - /// The channel of this queue + /// The channel of this queue. final Channel channel; - /// The client associated with this [channel] + /// The client associated with this [channel]. final StreamChatClient client; - /// The logger associated to this queue + /// The logger associated to this queue. final Logger? logger; late final RetryPolicy _retryPolicy; @@ -68,7 +63,7 @@ class RetryQueue { }).addTo(_compositeSubscription); } - /// Add a list of messages + /// Add a list of messages. void add(List messages) { if (messages.isEmpty) return; if (!_messageQueue.containsAllMessage(messages)) { @@ -180,10 +175,10 @@ class RetryQueue { } } - /// Whether our [_messageQueue] has messages or not + /// Whether our [_messageQueue] has messages or not. bool get hasMessages => _messageQueue.isNotEmpty; - /// Call this method to dispose this object + /// Call this method to dispose this object. void dispose() { _messageQueue.clear(); _compositeSubscription.dispose(); diff --git a/packages/stream_chat/lib/src/core/models/message.dart b/packages/stream_chat/lib/src/core/models/message.dart index 85bf8a96..f1408d45 100644 --- a/packages/stream_chat/lib/src/core/models/message.dart +++ b/packages/stream_chat/lib/src/core/models/message.dart @@ -14,7 +14,7 @@ class _PinExpires { const _pinExpires = _PinExpires(); -/// Enum defining the status of a sending message +/// Enum defining the status of a sending message. enum MessageSendingStatus { /// Message is being sent sending, @@ -40,10 +40,10 @@ enum MessageSendingStatus { sent, } -/// The class that contains the information about a message +/// The class that contains the information about a message. @JsonSerializable() class Message extends Equatable { - /// Constructor used for json serialization + /// Constructor used for json serialization. Message({ String? id, this.text, @@ -65,13 +65,13 @@ class Message extends Equatable { this.command, DateTime? createdAt, DateTime? updatedAt, + this.deletedAt, this.user, this.pinned = false, this.pinnedAt, DateTime? pinExpires, this.pinnedBy, this.extraData = const {}, - this.deletedAt, this.status = MessageSendingStatus.sending, this.i18n, }) : id = id ?? const Uuid().v4(), @@ -80,7 +80,7 @@ class Message extends Equatable { _updatedAt = updatedAt, _quotedMessageId = quotedMessageId; - /// Create a new instance from a json + /// Create a new instance from JSON. factory Message.fromJson(Map json) => _$MessageFromJson( Serializer.moveToExtraDataFromRoot(json, topLevelFields), ).copyWith( @@ -91,14 +91,14 @@ class Message extends Equatable { /// the message is added. final String id; - /// The text of this message + /// The text of this message. final String? text; - /// The status of a sending message + /// The status of a sending message. @JsonKey(ignore: true) final MessageSendingStatus status; - /// The message type + /// The message type. @JsonKey( includeIfNull: false, toJson: Serializer.readOnly, @@ -110,15 +110,15 @@ class Message extends Equatable { @JsonKey(includeIfNull: false) final List attachments; - /// The list of user mentioned in the message + /// The list of user mentioned in the message. @JsonKey(toJson: User.toIds) final List mentionedUsers; - /// A map describing the count of number of every reaction + /// A map describing the count of number of every reaction. @JsonKey(includeIfNull: false, toJson: Serializer.readOnly) final Map? reactionCounts; - /// A map describing the count of score of every reaction + /// A map describing the count of score of every reaction. @JsonKey(includeIfNull: false, toJson: Serializer.readOnly) final Map? reactionScores; @@ -133,7 +133,7 @@ class Message extends Equatable { /// The ID of the parent message, if the message is a thread reply. final String? parentId; - /// A quoted reply message + /// A quoted reply message. @JsonKey(toJson: Serializer.readOnly) final Message? quotedMessage; @@ -153,10 +153,10 @@ class Message extends Equatable { /// Check if this message needs to show in the channel. final bool? showInChannel; - /// If true the message is silent + /// If true the message is silent. final bool silent; - /// If true the message is shadowed + /// If true the message is shadowed. @JsonKey( includeIfNull: false, toJson: Serializer.readOnly, @@ -169,6 +169,10 @@ class Message extends Equatable { final DateTime? _createdAt; + /// Reserved field indicating when the message was deleted. + @JsonKey(includeIfNull: false, toJson: Serializer.readOnly) + final DateTime? deletedAt; + /// Reserved field indicating when the message was created. @JsonKey(includeIfNull: false, toJson: Serializer.readOnly) DateTime get createdAt => _createdAt ?? DateTime.now(); @@ -179,48 +183,45 @@ class Message extends Equatable { @JsonKey(includeIfNull: false, toJson: Serializer.readOnly) DateTime get updatedAt => _updatedAt ?? DateTime.now(); - /// User who sent the message + /// User who sent the message. @JsonKey(includeIfNull: false, toJson: Serializer.readOnly) final User? user; - /// If true the message is pinned + /// If true the message is pinned. final bool pinned; - /// Reserved field indicating when the message was pinned + /// Reserved field indicating when the message was pinned. @JsonKey(toJson: Serializer.readOnly) final DateTime? pinnedAt; - /// Reserved field indicating when the message will expire + /// Reserved field indicating when the message will expire. /// - /// if `null` message has no expiry + /// If `null` message has no expiry. final DateTime? pinExpires; - /// Reserved field indicating who pinned the message + /// Reserved field indicating who pinned the message. @JsonKey(toJson: Serializer.readOnly) final User? pinnedBy; - /// Message custom extraData + /// Message custom extraData. @JsonKey(includeIfNull: false) final Map extraData; - /// True if the message is a system info + /// True if the message is a system info. bool get isSystem => type == 'system'; - /// True if the message has been deleted + /// True if the message has been deleted. bool get isDeleted => type == 'deleted'; - /// True if the message is ephemeral + /// True if the message is ephemeral. bool get isEphemeral => type == 'ephemeral'; - /// Reserved field indicating when the message was deleted. - @JsonKey(includeIfNull: false, toJson: Serializer.readOnly) - final DateTime? deletedAt; - /// A Map of translations. @JsonKey(includeIfNull: false) final Map? i18n; /// Known top level fields. + /// /// Useful for [Serializer] methods. static const topLevelFields = [ 'id', @@ -253,7 +254,7 @@ class Message extends Equatable { 'i18n', ]; - /// Serialize to json + /// Serialize to json. Map toJson() => Serializer.moveFromExtraDataToRoot( _$MessageToJson(this), ); @@ -265,6 +266,8 @@ class Message extends Equatable { String? type, List? attachments, List? mentionedUsers, + bool? silent, + bool? shadowed, Map? reactionCounts, Map? reactionScores, List? latestReactions, @@ -275,8 +278,6 @@ class Message extends Equatable { int? replyCount, List? threadParticipants, bool? showInChannel, - bool? shadowed, - bool? silent, String? command, DateTime? createdAt, DateTime? updatedAt, @@ -304,6 +305,8 @@ class Message extends Equatable { type: type ?? this.type, attachments: attachments ?? this.attachments, mentionedUsers: mentionedUsers ?? this.mentionedUsers, + silent: silent ?? this.silent, + shadowed: shadowed ?? this.shadowed, reactionCounts: reactionCounts ?? this.reactionCounts, reactionScores: reactionScores ?? this.reactionScores, latestReactions: latestReactions ?? this.latestReactions, @@ -316,18 +319,16 @@ class Message extends Equatable { showInChannel: showInChannel ?? this.showInChannel, command: command ?? this.command, createdAt: createdAt ?? _createdAt, - silent: silent ?? this.silent, - extraData: extraData ?? this.extraData, - user: user ?? this.user, - shadowed: shadowed ?? this.shadowed, updatedAt: updatedAt ?? _updatedAt, deletedAt: deletedAt ?? this.deletedAt, - status: status ?? this.status, + user: user ?? this.user, pinned: pinned ?? this.pinned, pinnedAt: pinnedAt ?? this.pinnedAt, - pinnedBy: pinnedBy ?? this.pinnedBy, pinExpires: pinExpires == _pinExpires ? this.pinExpires : pinExpires as DateTime?, + pinnedBy: pinnedBy ?? this.pinnedBy, + extraData: extraData ?? this.extraData, + status: status ?? this.status, i18n: i18n ?? this.i18n, ); } @@ -340,6 +341,8 @@ class Message extends Equatable { type: other.type, attachments: other.attachments, mentionedUsers: other.mentionedUsers, + silent: other.silent, + shadowed: other.shadowed, reactionCounts: other.reactionCounts, reactionScores: other.reactionScores, latestReactions: other.latestReactions, @@ -352,17 +355,15 @@ class Message extends Equatable { showInChannel: other.showInChannel, command: other.command, createdAt: other.createdAt, - silent: other.silent, - extraData: other.extraData, - user: other.user, - shadowed: other.shadowed, updatedAt: other.updatedAt, deletedAt: other.deletedAt, - status: other.status, + user: other.user, pinned: other.pinned, pinnedAt: other.pinnedAt, pinExpires: other.pinExpires, pinnedBy: other.pinnedBy, + extraData: other.extraData, + status: other.status, i18n: other.i18n, ); diff --git a/packages/stream_chat_flutter/lib/src/message_input/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input/message_input.dart index 99acb33a..b7eb4cf2 100644 --- a/packages/stream_chat_flutter/lib/src/message_input/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input/message_input.dart @@ -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 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 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 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? 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 diff --git a/packages/stream_chat_flutter/lib/src/message_input/stream_attachment_picker.dart b/packages/stream_chat_flutter/lib/src/message_input/stream_attachment_picker.dart index 066ed780..88fbab74 100644 --- a/packages/stream_chat_flutter/lib/src/message_input/stream_attachment_picker.dart +++ b/packages/stream_chat_flutter/lib/src/message_input/stream_attachment_picker.dart @@ -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? 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 allowedAttachmentTypes; diff --git a/packages/stream_chat_flutter/lib/src/message_input/stream_message_text_field.dart b/packages/stream_chat_flutter/lib/src/message_input/stream_message_text_field.dart index 37b4f683..e5ffde94 100644 --- a/packages/stream_chat_flutter/lib/src/message_input/stream_message_text_field.dart +++ b/packages/stream_chat_flutter/lib/src/message_input/stream_message_text_field.dart @@ -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], - /// [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" diff --git a/packages/stream_chat_flutter_core/lib/src/message_input_controller.dart b/packages/stream_chat_flutter_core/lib/src/message_input_controller.dart index 3944d59b..7aad03e6 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_input_controller.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_input_controller.dart @@ -4,7 +4,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:stream_chat/stream_chat.dart'; -/// A value listenable builder related to a [Message] +/// A value listenable builder related to a [Message]. +/// +/// Pass in a [MessageInputController] as the `valueListenable`. typedef MessageValueListenableBuilder = ValueListenableBuilder; /// A function that returns true if the message is valid and can be sent. @@ -35,7 +37,7 @@ class MessageInputController extends ValueNotifier { validator: validator ?? _defaultValidator, ); - /// Creates a controller for an editable text field from an initial + /// Creates a controller for an editable text field from initial /// [attachments]. factory MessageInputController.fromAttachments( List attachments, { @@ -127,7 +129,7 @@ class MessageInputController extends ValueNotifier { /// Returns the start of the selection of the text field. int get selectionStart => textEditingController.selection.start; - /// Sets the showInChannel flag of the message. + /// Sets the [showInChannel] flag of the message. set showInChannel(bool newValue) { value = value.copyWith(showInChannel: newValue); } @@ -202,14 +204,14 @@ class MessageInputController extends ValueNotifier { mentionedUsers = []; } - /// Set the [value] to empty. + /// Sets the [message], or [value], to empty. /// /// After calling this function, [text], [attachments] and [mentionedUsers] - /// all will be empty. + /// will all be empty. /// /// Calling this will notify all the listeners of this /// [MessageInputController] that they need to update - /// (it calls [notifyListeners]). For this reason, + /// (calls [notifyListeners]). For this reason, /// this method should only be called between frames, e.g. in response to user /// actions, not during the build, layout, or paint phases. void clear() { @@ -217,7 +219,7 @@ class MessageInputController extends ValueNotifier { _textEditingController.clear(); } - /// Set the [value] to the initial [Message] value. + /// Sets the [value] to the initial [Message] value. void reset({bool resetId = true}) { if (resetId) { _initialMessage = _initialMessage.copyWith( @@ -246,16 +248,13 @@ class RestorableMessageInputController extends RestorableChangeNotifier { /// Creates a [RestorableMessageInputController]. /// - /// This constructor treats a null `text` argument as if it were the empty - /// string. + /// This constructor creates a default [Message] when no `message` argument + /// is supplied. RestorableMessageInputController({Message? message}) : _initialValue = message ?? Message(); /// Creates a [RestorableMessageInputController] from an initial - /// [TextEditingValue]. - /// - /// This constructor treats a null `value` argument as if it were - /// [TextEditingValue.empty]. + /// [text] value. factory RestorableMessageInputController.fromText(String? text) => RestorableMessageInputController(message: Message(text: text));