Merge pull request #1611 from GetStream/feat/quoted-message-builder
This commit is contained in:
@@ -35,6 +35,22 @@
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- Added support for `StreamMessageWidget.quotedMessageBuilder` and `StreamMessageInput.quotedMessageBuilder` to override
|
||||||
|
the default quoted message widget. [#1547](https://github.com/GetStream/stream-chat-flutter/issues/1547)
|
||||||
|
|
||||||
|
```dart
|
||||||
|
StreamMessageWidget(
|
||||||
|
...,
|
||||||
|
quotedMessageBuilder: (context, message) {
|
||||||
|
return Container(
|
||||||
|
color: Colors.red,
|
||||||
|
child: Text('Quoted Message'),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## 6.3.0
|
## 6.3.0
|
||||||
|
|
||||||
🐞 Fixed
|
🐞 Fixed
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ class StreamQuotedMessageWidget extends StatelessWidget {
|
|||||||
this.textLimit = 170,
|
this.textLimit = 170,
|
||||||
this.attachmentThumbnailBuilders,
|
this.attachmentThumbnailBuilders,
|
||||||
this.padding = const EdgeInsets.all(8),
|
this.padding = const EdgeInsets.all(8),
|
||||||
this.onTap,
|
|
||||||
this.onQuotedMessageClear,
|
this.onQuotedMessageClear,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -46,9 +45,6 @@ class StreamQuotedMessageWidget extends StatelessWidget {
|
|||||||
/// Padding around the widget
|
/// Padding around the widget
|
||||||
final EdgeInsetsGeometry padding;
|
final EdgeInsetsGeometry padding;
|
||||||
|
|
||||||
/// Callback for tap on widget
|
|
||||||
final GestureTapCallback? onTap;
|
|
||||||
|
|
||||||
/// Callback for clearing quoted messages.
|
/// Callback for clearing quoted messages.
|
||||||
final VoidCallback? onQuotedMessageClear;
|
final VoidCallback? onQuotedMessageClear;
|
||||||
|
|
||||||
@@ -77,19 +73,12 @@ class StreamQuotedMessageWidget extends StatelessWidget {
|
|||||||
showOnlineStatus: false,
|
showOnlineStatus: false,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
return MouseRegion(
|
return Padding(
|
||||||
cursor: SystemMouseCursors.click,
|
padding: padding,
|
||||||
child: GestureDetector(
|
child: Row(
|
||||||
behavior: HitTestBehavior.opaque,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
onTap: onTap,
|
mainAxisSize: MainAxisSize.min,
|
||||||
child: Padding(
|
children: reverse ? children.reversed.toList() : children,
|
||||||
padding: padding,
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: reverse ? children.reversed.toList() : children,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -258,23 +247,26 @@ class _ParseAttachments extends StatelessWidget {
|
|||||||
child = attachmentBuilder(context, attachment);
|
child = attachmentBuilder(context, attachment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
child = AbsorbPointer(child: child);
|
|
||||||
|
final isImageFile = attachment.title?.mimeType?.type == 'image';
|
||||||
|
final isVideoFile = attachment.title?.mimeType?.type == 'video';
|
||||||
|
|
||||||
return Material(
|
return Material(
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
type: MaterialType.transparency,
|
type: MaterialType.transparency,
|
||||||
shape: attachment.type == 'file'
|
shape: attachment.type == 'file' && (!isImageFile && !isVideoFile)
|
||||||
? null
|
? null
|
||||||
: RoundedRectangleBorder(
|
: RoundedRectangleBorder(
|
||||||
side: const BorderSide(width: 0, color: Colors.transparent),
|
side: const BorderSide(width: 0, color: Colors.transparent),
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: child,
|
child: AbsorbPointer(child: child),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, QuotedMessageAttachmentThumbnailBuilder>
|
Map<String, QuotedMessageAttachmentThumbnailBuilder>
|
||||||
get _defaultAttachmentBuilder {
|
get _defaultAttachmentBuilder {
|
||||||
return {
|
final builders = <String, QuotedMessageAttachmentThumbnailBuilder>{
|
||||||
'image': (_, attachment) {
|
'image': (_, attachment) {
|
||||||
return StreamImageAttachment(
|
return StreamImageAttachment(
|
||||||
attachment: attachment,
|
attachment: attachment,
|
||||||
@@ -315,16 +307,33 @@ class _ParseAttachments extends StatelessWidget {
|
|||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'file': (_, attachment) {
|
|
||||||
return SizedBox(
|
|
||||||
height: 32,
|
|
||||||
width: 32,
|
|
||||||
child: getFileTypeImage(
|
|
||||||
attachment.extraData['mime_type'] as String?,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
builders['file'] = (_, attachment) {
|
||||||
|
return SizedBox(
|
||||||
|
height: 32,
|
||||||
|
width: 32,
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final isImageFile = attachment.title?.mimeType?.type == 'image';
|
||||||
|
if (isImageFile) {
|
||||||
|
return builders['image']!(context, attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
final isVideoFile = attachment.title?.mimeType?.type == 'video';
|
||||||
|
if (isVideoFile) {
|
||||||
|
return builders['video']!(context, attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
return getFileTypeImage(
|
||||||
|
attachment.extraData['mime_type'] as String?,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return builders;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ class StreamMessageInput extends StatefulWidget {
|
|||||||
this.customAutocompleteTriggers = const [],
|
this.customAutocompleteTriggers = const [],
|
||||||
this.mentionAllAppUsers = false,
|
this.mentionAllAppUsers = false,
|
||||||
this.sendButtonBuilder,
|
this.sendButtonBuilder,
|
||||||
|
this.quotedMessageBuilder,
|
||||||
this.shouldKeepFocusAfterMessage,
|
this.shouldKeepFocusAfterMessage,
|
||||||
this.validator = _defaultValidator,
|
this.validator = _defaultValidator,
|
||||||
this.restorationId,
|
this.restorationId,
|
||||||
@@ -265,6 +266,9 @@ class StreamMessageInput extends StatefulWidget {
|
|||||||
/// Builder for creating send button
|
/// Builder for creating send button
|
||||||
final MessageRelatedBuilder? sendButtonBuilder;
|
final MessageRelatedBuilder? sendButtonBuilder;
|
||||||
|
|
||||||
|
/// Builder for building quoted message
|
||||||
|
final Widget Function(BuildContext, Message)? quotedMessageBuilder;
|
||||||
|
|
||||||
/// Defines if the [StreamMessageInput] loses focuses after a message is sent.
|
/// Defines if the [StreamMessageInput] loses focuses after a message is sent.
|
||||||
/// The default behaviour keeps focus until a command is enabled.
|
/// The default behaviour keeps focus until a command is enabled.
|
||||||
final bool? shouldKeepFocusAfterMessage;
|
final bool? shouldKeepFocusAfterMessage;
|
||||||
@@ -1126,14 +1130,20 @@ class StreamMessageInputState extends State<StreamMessageInput>
|
|||||||
if (!_hasQuotedMessage) return const Offstage();
|
if (!_hasQuotedMessage) return const Offstage();
|
||||||
final containsUrl = _effectiveController.message.quotedMessage!.attachments
|
final containsUrl = _effectiveController.message.quotedMessage!.attachments
|
||||||
.any((element) => element.titleLink != null);
|
.any((element) => element.titleLink != null);
|
||||||
return StreamQuotedMessageWidget(
|
|
||||||
reverse: true,
|
return widget.quotedMessageBuilder?.call(
|
||||||
showBorder: !containsUrl,
|
context,
|
||||||
message: _effectiveController.message.quotedMessage!,
|
_effectiveController.message.quotedMessage!,
|
||||||
messageTheme: _streamChatTheme.otherMessageTheme,
|
) ??
|
||||||
padding: const EdgeInsets.fromLTRB(8, 8, 8, 0),
|
StreamQuotedMessageWidget(
|
||||||
onQuotedMessageClear: widget.onQuotedMessageCleared,
|
reverse: true,
|
||||||
);
|
showBorder: !containsUrl,
|
||||||
|
message: _effectiveController.message.quotedMessage!,
|
||||||
|
messageTheme: _streamChatTheme.otherMessageTheme,
|
||||||
|
padding: const EdgeInsets.fromLTRB(8, 8, 8, 0),
|
||||||
|
onQuotedMessageClear: widget.onQuotedMessageCleared,
|
||||||
|
attachmentThumbnailBuilders: widget.attachmentThumbnailBuilders,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildAttachments() {
|
Widget _buildAttachments() {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ class MessageCard extends StatefulWidget {
|
|||||||
this.borderSide,
|
this.borderSide,
|
||||||
this.borderRadiusGeometry,
|
this.borderRadiusGeometry,
|
||||||
this.textBuilder,
|
this.textBuilder,
|
||||||
|
this.quotedMessageBuilder,
|
||||||
this.onLinkTap,
|
this.onLinkTap,
|
||||||
this.onMentionTap,
|
this.onMentionTap,
|
||||||
this.onQuotedMessageTap,
|
this.onQuotedMessageTap,
|
||||||
@@ -82,6 +83,9 @@ class MessageCard extends StatefulWidget {
|
|||||||
/// {@macro textBuilder}
|
/// {@macro textBuilder}
|
||||||
final Widget Function(BuildContext, Message)? textBuilder;
|
final Widget Function(BuildContext, Message)? textBuilder;
|
||||||
|
|
||||||
|
/// {@macro quotedMessageBuilder}
|
||||||
|
final Widget Function(BuildContext, Message)? quotedMessageBuilder;
|
||||||
|
|
||||||
/// {@macro onLinkTap}
|
/// {@macro onLinkTap}
|
||||||
final void Function(String)? onLinkTap;
|
final void Function(String)? onLinkTap;
|
||||||
|
|
||||||
@@ -129,8 +133,12 @@ class _MessageCardState extends State<MessageCard> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final onQuotedMessageTap = widget.onQuotedMessageTap;
|
||||||
|
final quotedMessageBuilder = widget.quotedMessageBuilder;
|
||||||
|
|
||||||
return Card(
|
return Card(
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
margin: EdgeInsets.symmetric(
|
margin: EdgeInsets.symmetric(
|
||||||
horizontal: (widget.isFailedState ? 15.0 : 0.0) +
|
horizontal: (widget.isFailedState ? 15.0 : 0.0) +
|
||||||
(widget.showUserAvatar == DisplayWidget.gone ? 0 : 4.0),
|
(widget.showUserAvatar == DisplayWidget.gone ? 0 : 4.0),
|
||||||
@@ -150,15 +158,27 @@ class _MessageCardState extends State<MessageCard> {
|
|||||||
maxWidth: widthLimit ?? double.infinity,
|
maxWidth: widthLimit ?? double.infinity,
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (widget.hasQuotedMessage)
|
if (widget.hasQuotedMessage)
|
||||||
QuotedMessage(
|
MouseRegion(
|
||||||
reverse: widget.reverse,
|
cursor: SystemMouseCursors.click,
|
||||||
message: widget.message,
|
child: InkWell(
|
||||||
hasNonUrlAttachments: widget.hasNonUrlAttachments,
|
onTap: !widget.message.quotedMessage!.isDeleted &&
|
||||||
onQuotedMessageTap: widget.onQuotedMessageTap,
|
onQuotedMessageTap != null
|
||||||
|
? () => onQuotedMessageTap(widget.message.quotedMessageId)
|
||||||
|
: null,
|
||||||
|
child: quotedMessageBuilder?.call(
|
||||||
|
context,
|
||||||
|
widget.message.quotedMessage!,
|
||||||
|
) ??
|
||||||
|
QuotedMessage(
|
||||||
|
reverse: widget.reverse,
|
||||||
|
message: widget.message,
|
||||||
|
hasNonUrlAttachments: widget.hasNonUrlAttachments,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
if (widget.hasNonUrlAttachments)
|
if (widget.hasNonUrlAttachments)
|
||||||
ParseAttachments(
|
ParseAttachments(
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
this.onMessageActions,
|
this.onMessageActions,
|
||||||
this.onShowMessage,
|
this.onShowMessage,
|
||||||
this.userAvatarBuilder,
|
this.userAvatarBuilder,
|
||||||
|
this.quotedMessageBuilder,
|
||||||
this.editMessageInputBuilder,
|
this.editMessageInputBuilder,
|
||||||
this.textBuilder,
|
this.textBuilder,
|
||||||
@Deprecated('''
|
@Deprecated('''
|
||||||
@@ -354,6 +355,11 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
final Widget Function(BuildContext, User)? userAvatarBuilder;
|
final Widget Function(BuildContext, User)? userAvatarBuilder;
|
||||||
|
|
||||||
|
/// {@template quotedMessageBuilder}
|
||||||
|
/// Widget builder for building quoted message
|
||||||
|
/// {@endtemplate}
|
||||||
|
final Widget Function(BuildContext, Message)? quotedMessageBuilder;
|
||||||
|
|
||||||
/// {@template message}
|
/// {@template message}
|
||||||
/// The message to display.
|
/// The message to display.
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
@@ -577,6 +583,7 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
Future<void> Function(Message)? onConfirmDeleteTap,
|
Future<void> Function(Message)? onConfirmDeleteTap,
|
||||||
Widget Function(BuildContext, Message)? editMessageInputBuilder,
|
Widget Function(BuildContext, Message)? editMessageInputBuilder,
|
||||||
Widget Function(BuildContext, Message)? textBuilder,
|
Widget Function(BuildContext, Message)? textBuilder,
|
||||||
|
Widget Function(BuildContext, Message)? quotedMessageBuilder,
|
||||||
@Deprecated('''
|
@Deprecated('''
|
||||||
Use [bottomRowBuilderWithDefaultWidget] instead.
|
Use [bottomRowBuilderWithDefaultWidget] instead.
|
||||||
Will be removed in the next major version.
|
Will be removed in the next major version.
|
||||||
@@ -670,6 +677,7 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
editMessageInputBuilder:
|
editMessageInputBuilder:
|
||||||
editMessageInputBuilder ?? this.editMessageInputBuilder,
|
editMessageInputBuilder ?? this.editMessageInputBuilder,
|
||||||
textBuilder: textBuilder ?? this.textBuilder,
|
textBuilder: textBuilder ?? this.textBuilder,
|
||||||
|
quotedMessageBuilder: quotedMessageBuilder ?? this.quotedMessageBuilder,
|
||||||
bottomRowBuilderWithDefaultWidget: _bottomRowBuilderWithDefaultWidget,
|
bottomRowBuilderWithDefaultWidget: _bottomRowBuilderWithDefaultWidget,
|
||||||
onMessageActions: onMessageActions ?? this.onMessageActions,
|
onMessageActions: onMessageActions ?? this.onMessageActions,
|
||||||
message: message ?? this.message,
|
message: message ?? this.message,
|
||||||
@@ -965,6 +973,7 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
|||||||
borderSide: widget.borderSide,
|
borderSide: widget.borderSide,
|
||||||
borderRadiusGeometry: widget.borderRadiusGeometry,
|
borderRadiusGeometry: widget.borderRadiusGeometry,
|
||||||
textBuilder: widget.textBuilder,
|
textBuilder: widget.textBuilder,
|
||||||
|
quotedMessageBuilder: widget.quotedMessageBuilder,
|
||||||
onLinkTap: widget.onLinkTap,
|
onLinkTap: widget.onLinkTap,
|
||||||
onMentionTap: widget.onMentionTap,
|
onMentionTap: widget.onMentionTap,
|
||||||
onQuotedMessageTap: widget.onQuotedMessageTap,
|
onQuotedMessageTap: widget.onQuotedMessageTap,
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ class MessageWidgetContent extends StatelessWidget {
|
|||||||
this.onMentionTap,
|
this.onMentionTap,
|
||||||
this.onLinkTap,
|
this.onLinkTap,
|
||||||
this.textBuilder,
|
this.textBuilder,
|
||||||
|
this.quotedMessageBuilder,
|
||||||
@Deprecated('''
|
@Deprecated('''
|
||||||
Use [bottomRowBuilderWithDefaultWidget] instead.
|
Use [bottomRowBuilderWithDefaultWidget] instead.
|
||||||
Will be removed in the next major version.
|
Will be removed in the next major version.
|
||||||
@@ -170,6 +171,9 @@ class MessageWidgetContent extends StatelessWidget {
|
|||||||
/// {@macro textBuilder}
|
/// {@macro textBuilder}
|
||||||
final Widget Function(BuildContext, Message)? textBuilder;
|
final Widget Function(BuildContext, Message)? textBuilder;
|
||||||
|
|
||||||
|
/// {@macro quotedMessageBuilder}
|
||||||
|
final Widget Function(BuildContext, Message)? quotedMessageBuilder;
|
||||||
|
|
||||||
/// {@macro showReactionPickerIndicator}
|
/// {@macro showReactionPickerIndicator}
|
||||||
final bool showReactionPickerIndicator;
|
final bool showReactionPickerIndicator;
|
||||||
|
|
||||||
@@ -351,6 +355,8 @@ class MessageWidgetContent extends StatelessWidget {
|
|||||||
onMentionTap: onMentionTap,
|
onMentionTap: onMentionTap,
|
||||||
onLinkTap: onLinkTap,
|
onLinkTap: onLinkTap,
|
||||||
textBuilder: textBuilder,
|
textBuilder: textBuilder,
|
||||||
|
quotedMessageBuilder:
|
||||||
|
quotedMessageBuilder,
|
||||||
borderRadiusGeometry:
|
borderRadiusGeometry:
|
||||||
borderRadiusGeometry,
|
borderRadiusGeometry,
|
||||||
borderSide: borderSide,
|
borderSide: borderSide,
|
||||||
|
|||||||
@@ -7,63 +7,41 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
///
|
///
|
||||||
/// Used in [QuotedMessageCard]. Should not be used elsewhere.
|
/// Used in [QuotedMessageCard]. Should not be used elsewhere.
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
class QuotedMessage extends StatefulWidget {
|
class QuotedMessage extends StatelessWidget {
|
||||||
/// {@macro quotedMessage}
|
/// {@macro quotedMessage}
|
||||||
const QuotedMessage({
|
const QuotedMessage({
|
||||||
super.key,
|
super.key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.reverse,
|
required this.reverse,
|
||||||
required this.hasNonUrlAttachments,
|
required this.hasNonUrlAttachments,
|
||||||
this.onQuotedMessageTap,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/// {@macro message}
|
/// {@macro message}
|
||||||
final Message message;
|
final Message message;
|
||||||
|
|
||||||
/// {@macro onQuotedMessageTap}
|
|
||||||
final OnQuotedMessageTap? onQuotedMessageTap;
|
|
||||||
|
|
||||||
/// {@macro reverse}
|
/// {@macro reverse}
|
||||||
final bool reverse;
|
final bool reverse;
|
||||||
|
|
||||||
/// {@macro hasNonUrlAttachments}
|
/// {@macro hasNonUrlAttachments}
|
||||||
final bool hasNonUrlAttachments;
|
final bool hasNonUrlAttachments;
|
||||||
|
|
||||||
@override
|
|
||||||
State<QuotedMessage> createState() => _QuotedMessageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _QuotedMessageState extends State<QuotedMessage> {
|
|
||||||
late StreamChatState _streamChat;
|
|
||||||
late StreamChatThemeData _streamChatTheme;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void didChangeDependencies() {
|
|
||||||
super.didChangeDependencies();
|
|
||||||
_streamChatTheme = StreamChatTheme.of(context);
|
|
||||||
_streamChat = StreamChat.of(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final isMyMessage = widget.message.user?.id == _streamChat.currentUser?.id;
|
final streamChat = StreamChat.of(context);
|
||||||
final onTap = widget.message.quotedMessage?.isDeleted != true &&
|
final chatThemeData = StreamChatTheme.of(context);
|
||||||
widget.onQuotedMessageTap != null
|
|
||||||
? () => widget.onQuotedMessageTap!(widget.message.quotedMessageId)
|
final isMyMessage = message.user?.id == streamChat.currentUser?.id;
|
||||||
: null;
|
|
||||||
final chatThemeData = _streamChatTheme;
|
|
||||||
return StreamQuotedMessageWidget(
|
return StreamQuotedMessageWidget(
|
||||||
onTap: onTap,
|
message: message.quotedMessage!,
|
||||||
message: widget.message.quotedMessage!,
|
|
||||||
messageTheme: isMyMessage
|
messageTheme: isMyMessage
|
||||||
? chatThemeData.otherMessageTheme
|
? chatThemeData.otherMessageTheme
|
||||||
: chatThemeData.ownMessageTheme,
|
: chatThemeData.ownMessageTheme,
|
||||||
reverse: widget.reverse,
|
reverse: reverse,
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
right: 8,
|
right: 8,
|
||||||
left: 8,
|
left: 8,
|
||||||
top: 8,
|
top: 8,
|
||||||
bottom: widget.hasNonUrlAttachments ? 8 : 0,
|
bottom: hasNonUrlAttachments ? 8 : 0,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user