Merge branch 'develop' into ISSUE-1456/SendingMessageIndicatorFix
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
- Now it is possible to customize the max lines of the title of a url attachment. Before it was always 1 line.
|
- Now it is possible to customize the max lines of the title of a url attachment. Before it was always 1 line.
|
||||||
- Added `attachmentActionsModalBuilder` parameter to `StreamMessageWidget` that allows to customize `AttachmentActionsModal`.
|
- Added `attachmentActionsModalBuilder` parameter to `StreamMessageWidget` that allows to customize `AttachmentActionsModal`.
|
||||||
|
- Added `StreamMessageInput.sendMessageKeyPredicate` and `StreamMessageInput.clearQuotedMessageKeyPredicate` to customize the keys used to send and clear the quoted message.
|
||||||
|
|
||||||
🔄 Changed
|
🔄 Changed
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
import 'package:flutter/material.dart' show Theme;
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
/// A generic widget builder function.
|
/// A generic widget builder function.
|
||||||
@@ -30,7 +30,7 @@ abstract class PlatformWidgetBase<M extends Widget, D extends Widget,
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final platform = Theme.of(context).platform;
|
final platform = defaultTargetPlatform;
|
||||||
if (platform == TargetPlatform.android || platform == TargetPlatform.iOS) {
|
if (platform == TargetPlatform.android || platform == TargetPlatform.iOS) {
|
||||||
return createMobileWidget(context);
|
return createMobileWidget(context);
|
||||||
} else if (platform == TargetPlatform.macOS ||
|
} else if (platform == TargetPlatform.macOS ||
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:cached_network_image/cached_network_image.dart'
|
|||||||
hide ErrorListener;
|
hide ErrorListener;
|
||||||
import 'package:desktop_drop/desktop_drop.dart';
|
import 'package:desktop_drop/desktop_drop.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:photo_manager/photo_manager.dart';
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
import 'package:shimmer/shimmer.dart';
|
import 'package:shimmer/shimmer.dart';
|
||||||
@@ -110,8 +111,17 @@ class StreamMessageInput extends StatefulWidget {
|
|||||||
this.enableMentionsOverlay = true,
|
this.enableMentionsOverlay = true,
|
||||||
this.onQuotedMessageCleared,
|
this.onQuotedMessageCleared,
|
||||||
this.enableActionAnimation = true,
|
this.enableActionAnimation = true,
|
||||||
|
this.sendMessageKeyPredicate = _defaultSendMessageKeyPredicate,
|
||||||
|
this.clearQuotedMessageKeyPredicate =
|
||||||
|
_defaultClearQuotedMessageKeyPredicate,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// The predicate used to send a message on desktop/web
|
||||||
|
final KeyEventPredicate sendMessageKeyPredicate;
|
||||||
|
|
||||||
|
/// The predicate used to clear the quoted message on desktop/web
|
||||||
|
final KeyEventPredicate clearQuotedMessageKeyPredicate;
|
||||||
|
|
||||||
/// If true the message input will animate the actions while you type
|
/// If true the message input will animate the actions while you type
|
||||||
final bool enableActionAnimation;
|
final bool enableActionAnimation;
|
||||||
|
|
||||||
@@ -252,6 +262,22 @@ class StreamMessageInput extends StatefulWidget {
|
|||||||
static bool _defaultValidator(Message message) =>
|
static bool _defaultValidator(Message message) =>
|
||||||
message.text?.isNotEmpty == true || message.attachments.isNotEmpty;
|
message.text?.isNotEmpty == true || message.attachments.isNotEmpty;
|
||||||
|
|
||||||
|
static bool _defaultSendMessageKeyPredicate(
|
||||||
|
FocusNode node,
|
||||||
|
KeyEvent event,
|
||||||
|
) {
|
||||||
|
// On desktop/web, send the message when the user presses the enter key.
|
||||||
|
return event is KeyUpEvent && event.logicalKey == LogicalKeyboardKey.enter;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _defaultClearQuotedMessageKeyPredicate(
|
||||||
|
FocusNode node,
|
||||||
|
KeyEvent event,
|
||||||
|
) {
|
||||||
|
// On desktop/web, clear the quoted message when the user presses the escape key.
|
||||||
|
return event is KeyUpEvent && event.logicalKey == LogicalKeyboardKey.escape;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
StreamMessageInputState createState() => StreamMessageInputState();
|
StreamMessageInputState createState() => StreamMessageInputState();
|
||||||
}
|
}
|
||||||
@@ -509,9 +535,6 @@ class StreamMessageInputState extends State<StreamMessageInput>
|
|||||||
: CrossFadeState.showSecond,
|
: CrossFadeState.showSecond,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// PlatformWidgetBuilder(
|
|
||||||
// mobile: (context, child) => _buildFilePickerSection(),
|
|
||||||
// ),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -753,24 +776,12 @@ class StreamMessageInputState extends State<StreamMessageInput>
|
|||||||
LimitedBox(
|
LimitedBox(
|
||||||
maxHeight: widget.maxHeight,
|
maxHeight: widget.maxHeight,
|
||||||
child: PlatformWidgetBuilder(
|
child: PlatformWidgetBuilder(
|
||||||
web: (context, child) => KeyboardShortcutRunner(
|
web: (context, child) => Focus(
|
||||||
onEnterKeypress: sendMessage,
|
onKeyEvent: _handleKeyPressed,
|
||||||
onEscapeKeypress: () {
|
|
||||||
if (_hasQuotedMessage &&
|
|
||||||
_effectiveController.text.isEmpty) {
|
|
||||||
widget.onQuotedMessageCleared?.call();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: child!,
|
child: child!,
|
||||||
),
|
),
|
||||||
desktop: (context, child) => KeyboardShortcutRunner(
|
desktop: (context, child) => Focus(
|
||||||
onEnterKeypress: sendMessage,
|
onKeyEvent: _handleKeyPressed,
|
||||||
onEscapeKeypress: () {
|
|
||||||
if (_hasQuotedMessage &&
|
|
||||||
_effectiveController.text.isEmpty) {
|
|
||||||
widget.onQuotedMessageCleared?.call();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: child!,
|
child: child!,
|
||||||
),
|
),
|
||||||
mobile: (context, child) => child,
|
mobile: (context, child) => child,
|
||||||
@@ -801,6 +812,25 @@ class StreamMessageInputState extends State<StreamMessageInput>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyEventResult _handleKeyPressed(FocusNode node, KeyEvent event) {
|
||||||
|
// Check for send message key.
|
||||||
|
if (widget.sendMessageKeyPredicate(node, event)) {
|
||||||
|
sendMessage();
|
||||||
|
return KeyEventResult.handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for clear quoted message key.
|
||||||
|
if (widget.clearQuotedMessageKeyPredicate(node, event)) {
|
||||||
|
if (_hasQuotedMessage && _effectiveController.text.isEmpty) {
|
||||||
|
widget.onQuotedMessageCleared?.call();
|
||||||
|
}
|
||||||
|
return KeyEventResult.handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return ignored to allow other key events to be handled.
|
||||||
|
return KeyEventResult.ignored;
|
||||||
|
}
|
||||||
|
|
||||||
InputDecoration _getInputDecoration(BuildContext context) {
|
InputDecoration _getInputDecoration(BuildContext context) {
|
||||||
final passedDecoration = _messageInputTheme.inputDecoration;
|
final passedDecoration = _messageInputTheme.inputDecoration;
|
||||||
return InputDecoration(
|
return InputDecoration(
|
||||||
|
|||||||
@@ -340,6 +340,11 @@ typedef DownloadedPathCallback = void Function(String? path);
|
|||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
typedef UserTapCallback = void Function(User, Widget?);
|
typedef UserTapCallback = void Function(User, Widget?);
|
||||||
|
|
||||||
|
/// {@template rawKeyEventPredicate}
|
||||||
|
/// Callback called to react to a key event
|
||||||
|
/// {@endtemplate}
|
||||||
|
typedef KeyEventPredicate = bool Function(FocusNode, KeyEvent);
|
||||||
|
|
||||||
/// {@template userItemBuilder}
|
/// {@template userItemBuilder}
|
||||||
/// Builder used to create a custom [ListUserItem] from a [User]
|
/// Builder used to create a custom [ListUserItem] from a [User]
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
|
|||||||
Reference in New Issue
Block a user